ROS探索总结(三十四)——rviz plugin

43000
100
2017年6月13日 21时04分

rvizROS官方的一款3D可视化工具,几乎我们需要用到的所有机器人相关数据都可以在rviz中展现,当然由于机器人系统的需求不同,很多时候rviz中已有的一些功能仍然无法满足我们的需求,这个时候rvizplugin机制就派上用场了。上一篇我们探索了插件的概念和基本实现,这一篇通过rviz中的插件实现,来进行巩固加深。

rviz作为一种可扩展化的视图工具,可以使用这种插件机制来扩展丰富的功能,进行二次开发,我们在rviz中常常使用的激光数据可视化显示、图像数据可视化显示,其实都是官方提供的插件。所以,我们完全可以在rviz的基础上,打造属于我们自己的机器人人机界面。

 

一、目标

在《Mastering ROS for Robotics Programming》这本书的第六章,讲解了一个发布速度控制的rviz plugin,这里我们就根据这个plugin的实现来学习。

plugin的整体效果如下:

image

从上边的图片我们有一个大致的感性认识:

首先,这是一个可视化的界面,在ros的编程中,好像没有可视化的编程语句,那么如何实现可视化编程呢?如果你使用过ROSrqt工具箱,应该就会想到Qt,没错,Qt是一个实现GUI的优秀框架,ROS中的可视化工具绝大部分都是基于Qt进行开发的,rvizplugin也不例外。所以我们需要了解Qt的一些相关知识。

其次,这个界面里包含三个输入框,分别对应topic名称、线速度值、角速度值,这就需要我们读取用户的输入,然后转换成ROStopic,这里也会涉及到Qt中的重要概念——信号、槽,类似于回调函数,可以自行百度学习一下。

好的,接下来,我们就分步骤看一下如何实现这个plugin,也可以跟着一起做。

完整的功能包代码可以在github上下载。

 

二、创建功能包

首先,我们来创建一个功能包,用来放置plugin的所有相关代码:

$ catkin_create_pkg rviz_telop_commander roscpp rviz std_msgs

这个功能包的依赖于rviz,因为rviz是基于Qt开发的,所以省去了对Qt的依赖。

 

三、实现主代码

接下来,我们在功能包的src文件夹下开始做代码的实现,这个plugin相对简单,只需要一个cpp文件就可以完成,当然对应的还要有它的头文件。

 

3.1 头文件

#ifndef TELEOP_PAD_H
#define TELEOP_PAD_H

//所需要包含的头文件
#include <ros/ros.h>
#include <ros/console.h>
#include <rviz/panel.h>   //plugin基类的头文件

class QLineEdit;

namespace rviz_telop_commander
{
// 所有的plugin都必须是rviz::Panel的子类
class TeleopPanel: public rviz::Panel
{
// 后边需要用到Qt的信号和槽,都是QObject的子类,所以需要声明Q_OBJECT宏
Q_OBJECT
public:
  // 构造函数,在类中会用到QWidget的实例来实现GUI界面,这里先初始化为0即可
  TeleopPanel( QWidget* parent = 0 );

  // 重载rviz::Panel积累中的函数,用于保存、加载配置文件中的数据,在我们这个plugin
  // 中,数据就是topic的名称
  virtual void load( const rviz::Config& config );
  virtual void save( rviz::Config config ) const;

  // 公共槽.
public Q_SLOTS:
  // 当用户输入topic的命名并按下回车后,回调用此槽来创建一个相应名称的topic publisher
  void setTopic( const QString& topic );

  // 内部槽.
protected Q_SLOTS:
  void sendVel();                 // 发布当前的速度值
  void update_Linear_Velocity();  // 根据用户的输入更新线速度值
  void update_Angular_Velocity(); // 根据用户的输入更新角速度值
  void updateTopic();             // 根据用户的输入更新topic name

  // 内部变量.
protected:
  // topic name输入框
  QLineEdit* output_topic_editor_;
  QString output_topic_;

  // 线速度值输入框
  QLineEdit* output_topic_editor_1;
  QString output_topic_1;

  // 角速度值输入框
  QLineEdit* output_topic_editor_2;
  QString output_topic_2;

  // ROS的publisher,用来发布速度topic
  ros::Publisher velocity_publisher_;

  // The ROS node handle.
  ros::NodeHandle nh_;

  // 当前保存的线速度和角速度值
  float linear_velocity_;
  float angular_velocity_;
};

} // end namespace rviz_plugin_tutorials

#endif // TELEOP_PANEL_H

 

3.2 cpp文件

接下来是cpp代码文件 teleop_pad.cpp

#include <stdio.h>

#include <QPainter>
#include <QLineEdit>
#include <QVBoxLayout>
#include <QHBoxLayout>
#include <QLabel>
#include <QTimer>

#include <geometry_msgs/Twist.h>
#include <QDebug>

#include "teleop_pad.h"

namespace rviz_telop_commander
{

// 构造函数,初始化变量
TeleopPanel::TeleopPanel( QWidget* parent )
  : rviz::Panel( parent )
  , linear_velocity_( 0 )
  , angular_velocity_( 0 )
{

  // 创建一个输入topic命名的窗口
  QVBoxLayout* topic_layout = new QVBoxLayout;
  topic_layout->addWidget( new QLabel( "Teleop Topic:" ));
  output_topic_editor_ = new QLineEdit;
  topic_layout->addWidget( output_topic_editor_ );

  // 创建一个输入线速度的窗口
  topic_layout->addWidget( new QLabel( "Linear Velocity:" ));
  output_topic_editor_1 = new QLineEdit;
  topic_layout->addWidget( output_topic_editor_1 );

  // 创建一个输入角速度的窗口
  topic_layout->addWidget( new QLabel( "Angular Velocity:" ));
  output_topic_editor_2 = new QLineEdit;
  topic_layout->addWidget( output_topic_editor_2 );

  QHBoxLayout* layout = new QHBoxLayout;
  layout->addLayout( topic_layout );
  setLayout( layout );

  // 创建一个定时器,用来定时发布消息
  QTimer* output_timer = new QTimer( this );

  // 设置信号与槽的连接
  connect( output_topic_editor_, SIGNAL( editingFinished() ), this, SLOT( updateTopic() ));             // 输入topic命名,回车后,调用updateTopic()
  connect( output_topic_editor_1, SIGNAL( editingFinished() ), this, SLOT( update_Linear_Velocity() )); // 输入线速度值,回车后,调用update_Linear_Velocity()
  connect( output_topic_editor_2, SIGNAL( editingFinished() ), this, SLOT( update_Angular_Velocity() ));// 输入角速度值,回车后,调用update_Angular_Velocity()

  // 设置定时器的回调函数,按周期调用sendVel()
  connect( output_timer, SIGNAL( timeout() ), this, SLOT( sendVel() ));

  // 设置定时器的周期,100ms
  output_timer->start( 100 );
}

// 更新线速度值
void TeleopPanel::update_Linear_Velocity()
{
    // 获取输入框内的数据
    QString temp_string = output_topic_editor_1->text();

    // 将字符串转换成浮点数
    float lin = temp_string.toFloat();

    // 保存当前的输入值
    linear_velocity_ = lin;
}

// 更新角速度值
void TeleopPanel::update_Angular_Velocity()
{
    QString temp_string = output_topic_editor_2->text();
    float ang = temp_string.toFloat() ;
    angular_velocity_ = ang;
}

// 更新topic命名
void TeleopPanel::updateTopic()
{
  setTopic( output_topic_editor_->text() );
}

// 设置topic命名
void TeleopPanel::setTopic( const QString& new_topic )
{
  // 检查topic是否发生改变.
  if( new_topic != output_topic_ )
  {
    output_topic_ = new_topic;

    // 如果命名为空,不发布任何信息
    if( output_topic_ == "" )
    {
      velocity_publisher_.shutdown();
    }
    // 否则,初始化publisher
    else
    {
      velocity_publisher_ = nh_.advertise<geometry_msgs::Twist>( output_topic_.toStdString(), 1 );
    }

    Q_EMIT configChanged();
  }
}

// 发布消息
void TeleopPanel::sendVel()
{
  if( ros::ok() && velocity_publisher_ )
  {
    geometry_msgs::Twist msg;
    msg.linear.x = linear_velocity_;
    msg.linear.y = 0;
    msg.linear.z = 0;
    msg.angular.x = 0;
    msg.angular.y = 0;
    msg.angular.z = angular_velocity_;
    velocity_publisher_.publish( msg );
  }
}

// 重载父类的功能
void TeleopPanel::save( rviz::Config config ) const
{
  rviz::Panel::save( config );
  config.mapSetValue( "Topic", output_topic_ );
}

// 重载父类的功能,加载配置数据
void TeleopPanel::load( const rviz::Config& config )
{
  rviz::Panel::load( config );
  QString topic;
  if( config.mapGetString( "Topic", &topic ))
  {
    output_topic_editor_->setText( topic );
    updateTopic();
  }
}

} // end namespace rviz_plugin_tutorials

// 声明此类是一个rviz的插件
#include <pluginlib/class_list_macros.h>
PLUGINLIB_EXPORT_CLASS(rviz_telop_commander::TeleopPanel,rviz::Panel )
// END_TUTORIAL

代码文件就是这样,并没有很多代码,还是比较好理解的。

 

四、完成编译文件

为了编译成功,还需要完成一些编译文件的设置。

4.1 plugin的描述文件

在功能包的根目录下需要创建一个plugin的描述文件 plugin_description.xml

<library path="lib/librviz_telop_commander">
  <class name="rviz_telop_commander/Teleop"
         type="rviz_telop_commander::TeleopPanel"
         base_class_type="rviz::Panel">
    <description>
      A panel widget allowing simple diff-drive style robot base control.
    </description>
  </class>
</library>

 

4.2  package.xml

然后在 package.xml文件里添加plugin_description.xml

  <export>
      <rviz plugin="${prefix}/plugin_description.xml"/>
  </export>

 

4.3  CMakeLists.txt

当然, CMakeLists.txt文件也必须要加入相应的编译规则:

## This plugin includes Qt widgets, so we must include Qt like so:
find_package(Qt4 COMPONENTS QtCore QtGui REQUIRED)
include(${QT_USE_FILE})

## I prefer the Qt signals and slots to avoid defining "emit", "slots",
## etc because they can conflict with boost signals, so define QT_NO_KEYWORDS here.
add_definitions(-DQT_NO_KEYWORDS)

## Here we specify which header files need to be run through "moc",
## Qt's meta-object compiler.
qt4_wrap_cpp(MOC_FILES
  src/teleop_pad.h
)

## Here we specify the list of source files, including the output of
## the previous command which is stored in ``${MOC_FILES}``.
set(SOURCE_FILES
  src/teleop_pad.cpp 
  ${MOC_FILES}
)

## An rviz plugin is just a shared library, so here we declare the
## library to be called ``${PROJECT_NAME}`` (which is
## "rviz_plugin_tutorials", or whatever your version of this project
## is called) and specify the list of source files we collected above
## in ``${SOURCE_FILES}``.
add_library(${PROJECT_NAME} ${SOURCE_FILES})

## Link the library with whatever Qt libraries have been defined by
## the ``find_package(Qt4 ...)`` line above, and with whatever libraries
## catkin has included.
##
## Although this puts "rviz_plugin_tutorials" (or whatever you have
## called the project) as the name of the library, cmake knows it is a
## library and names the actual file something like
## "librviz_plugin_tutorials.so", or whatever is appropriate for your
## particular OS.
target_link_libraries(${PROJECT_NAME} ${QT_LIBRARIES} ${catkin_LIBRARIES})

现在就可以开始编译了!

 

五、实现效果

编译成功后,我们来运行rviz,需要注意的是:一定要source devel文件夹下的setup脚本,来生效路径,否则会找不到插件

rosrun rviz rviz

启动之后应该并没有什么不同,点击菜单栏中的“Panels”选项,选择“Add New Panel”,在打开的窗口中的最下方,就可以看到我们创建的plugin了,点中之后,可以在下方的“Description”中看到我们在plugin_description.xml文件中对plugin的描述。

image

点击“OK”,就会弹出“TeleopPanel”插件啦:

image

 

我们分别填写三行所对应的内容:

image

然后打开一个终端查看消息:

 

image

image

OK,实现一个rvizplugin是不是很简单,重点是理解ROSQt的结合使用。使用类似的方法和Qt的编程技巧,就可以基于rviz打造属于自己的人机交互界面了!

发表评论

后才能评论

评论列表(100条)

  • ll 2019年9月13日 下午7:49

    老师你好,我使用一个插件,用一个按钮来驱动机器人连续运动,但我发现用execute()去执行的时候,是会卡的(看了评论发现是阻塞的),但是卡完以后发现直接是到终点的,不会有机器人运动过程,请问这种情况怎么办

  • kai mi 2019年9月5日 上午11:36

    古月老师,您好!
    咨询您一个问题!
    我在编写ros plugin中增加TCP\IP socket 与一个ARM(linux系统)开发板通信(自己编写协议,底层ARM没有安装ROS),发现连接通信没问题,但是只要循环发送和接受的过程中增加延时,通信就会断开,发送失败,直接编写QT程序,通信不会出问题,一直保持连接,想知道ros在这里有影响?

    • kai mi 回复 kai mi 2019年9月5日 下午4:59

      以解决,谢谢

  • ll 2019年5月21日 下午8:33

    老师您好,我在编译过程发现:
    /home/sunxiaoqin/catkin_ws/src/rviz_telop_commander/src/teleop_pad.cpp: In constructor ‘rviz_telop_commander::TeleopPanel::TeleopPanel(QWidget*)’:
    /home/sunxiaoqin/catkin_ws/src/rviz_telop_commander/src/teleop_pad.cpp:42:13: error: ‘class QHBoxLayout’ has no member named ‘addlayout’
    layout->addlayout(topic_layout);
    ^
    /home/sunxiaoqin/catkin_ws/src/rviz_telop_commander/src/teleop_pad.cpp:49:57: error: ‘editingFinished’ was not declared in this scope
    connect(output_topic_editor_,SINGAL(editingFinished()),this,SLOT(updateTopic()));
    ^
    /home/sunxiaoqin/catkin_ws/src/rviz_telop_commander/src/teleop_pad.cpp:49:58: error: ‘SINGAL’ was not declared in this scope
    connect(output_topic_editor_,SINGAL(editingFinished()),this,SLOT(updateTopic()));
    ^
    /home/sunxiaoqin/catkin_ws/src/rviz_telop_commander/src/teleop_pad.cpp:53:41: error: ‘timeout’ was not declared in this scope
    connect(output_timer,SINGAL(timeout()),this,SLOT(sendVel()));
    ^
    rviz_telop_commander/CMakeFiles/rviz_telop_commander.dir/build.make:66: recipe for target ‘rviz_telop_commander/CMakeFiles/rviz_telop_commander.dir/src/teleop_pad.cpp.o’ failed
    make[2]: *** [rviz_telop_commander/CMakeFiles/rviz_telop_commander.dir/src/teleop_pad.cpp.o] Error 1
    CMakeFiles/Makefile2:1951: recipe for target ‘rviz_telop_commander/CMakeFiles/rviz_telop_commander.dir/all’ failed
    make[1]: *** [rviz_telop_commander/CMakeFiles/rviz_telop_commander.dir/all] Error 2
    Makefile:138: recipe for target ‘all’ failed
    make: *** [all] Error 2
    请问怎么解决,谢谢

    • 古月 回复 ll 2019年5月23日 下午5:09

      编程问题吧,google下

    • ll 回复 古月 2019年5月23日 下午8:22

      谢谢老师,已解决

  • ll 2019年5月20日 下午2:28

    胡老师您好,我按照您的程序编写,并在Cmakelist文件添加了以上内容,但是编译显示:
    usr/include/boost/type_traits/detail/has_binary_operator.hp:50: Parse error at “BOOST_JOIN”
    usr/include/boost/type_traits/detail/has_binary_operator.hp:50: Parse error at “BOOST_JOIN”
    rviz_telop_commander/CMakeFiles/teleop_pad.dir/build.make:62: recipe for target ‘rviz_telop_commander/src/moc_teleop_pad.cxx’ failed
    rviz_telop_commander/CMakeFiles/rviz_telop_commander.dir/build.make:62: recipe for target ‘rviz_telop_commander/src/moc_teleop_pad.cxx’ failed
    make[2]: *** [rviz_telop_commander/src/moc_teleop_pad.cxx] Error 1
    make[2]: *** [rviz_telop_commander/src/moc_teleop_pad.cxx] Error 1
    CMakeFiles/Makefile2:2502: recipe for target ‘rviz_telop_commander/CMakeFiles/teleop_pad.dir/all’ failed
    make[1]: *** [rviz_telop_commander/CMakeFiles/teleop_pad.dir/all] Error 2
    make[1]: *** 正在等待未完成的任务….
    CMakeFiles/Makefile2:1953: recipe for target ‘rviz_telop_commander/CMakeFiles/rviz_telop_commander.dir/all’ failed
    make[1]: *** [rviz_telop_commander/CMakeFiles/rviz_telop_commander.dir/all] Error 2
    Makefile:138: recipe for target ‘all’ failed
    我用的是kinetic版本的,应该是在添加Cmakelist文件内容时出错,请问我如何解决这个问题,谢谢

  • crisps 2018年12月27日 下午9:20

    古月老师您好,1.请问moveit中机械臂的动作规划组中在rviz中显示的时候只有有末端执行器的动作规划组才会有末端的交互小球吗?为什么我下载的机械臂模型里有的规划组不存在交互拖拽小球呢?
    2.然后在没有末端规划小球的动作组做动作规划时,当然这就不能拖拽,只能随机有效位置,出现错误如下:
    [ WARN] [1545915929.504385536]: Controller right_arm failed with error code INVALID_JOINTS
    [ WARN] [1545915929.504691837]: Controller handle right_arm reports status FAILED

    • 古月 回复 crisps 2018年12月29日 下午9:50

      1. 需要setup assistant配置规划组之后才会出现
      2. 感觉配置有问题

    • crisps 回复 古月 2018年12月29日 下午11:02

      那请问老师,跟规划组有没有添加end_effector 没有关系吗

    • 古月 回复 crisps 2019年1月2日 上午9:39

      可以试一下

    • crisps 回复 古月 2019年1月2日 下午1:02

      好的,谢谢古月老师

  • sure 2018年12月7日 上午12:14

    古月老师你好, 我用server 产生一个三次方的trajectory , 然后用rosrun package node 运行,并且把起点 终点通过rosservice call 赋值,想要通过rqt_plot得到trajectory 的轨迹,可是就没办法显示出这条三次曲线。terminal 中也显示了 trajectory finish 了,trajectory 这条三次曲线应该是产生成功了,但就是不能用rqt_plot 显示出来。
    请问要如何把这个三次方trajectory 用rqt_plot 显示出来
    多谢老师

    • 古月 回复 sure 2018年12月7日 下午10:20

      rqt_plot是通过订阅话题把其中的数据绘制出来的

    • 金聪聪 回复 古月 2018年12月14日 下午11:27

      可以指教一下,如何在插件中实现订阅话题的功能?案例只有发布话题的,订阅话题要用到spinonce和回调函数,这个在类里面要如何实现,十分困扰。

    • 古月 回复 金聪聪 2018年12月16日 下午12:57

      和写ros的节点是一样的,创建一个订阅者的节点即可,qt中有定时器可以做处理,也可以用多线程处理

  • 马文龙 2018年8月7日 上午11:32

    胡老师您好我下载了您的包之后编译不能通过编译到百分之6的时候就不行了 显示这个Makefile:138: recipe for target ‘all’ failed
    make: *** [all] Error 2
    Invoking “make -j4 -l4” fai
    该怎么解决呢

    • 古月 回复 马文龙 2018年8月7日 下午11:44

      ROS 版本?这里用的是indigo,kinetic编译会有问题

  • zp 2018年7月23日 下午4:14

    古月老师,我的rqt打开后没有菜单栏,是个空白页面,请问是怎么了?万分感谢

    • 古月 回复 zp 2018年7月27日 上午10:13

      rqt打开之后默认就是空白的,在最上边应该有菜单可以选择添加的显示插件的

    • 段彦卉 回复 古月 2018年11月27日 下午6:02

      老师您好,我的打开在最上面没有菜单栏,全部是空白的界面

    • 袁杨 回复 段彦卉 2019年3月22日 下午4:56

      你好 我也遇到了这种情况 请问您怎么解决的?

  • 洋洋 2018年7月13日 上午9:42

    古月老师你好,我打算做一个采集机械臂各个关节运动轨迹数据这个该怎么写,和plugin类似吗?

    • 古月 回复 洋洋 2018年7月15日 下午7:24

      机器人的关节状态会通过joint_states发布出来,写个节点订阅这个话题就可以,然后需要怎么处理就在节点里处理

    • 洋洋 回复 古月 2018年7月24日 上午10:31

      如果想通过rqt_plot在rviz当中实时显示出来,我在rqt_plot当中输入joint_states,但是并没有显示出轨迹曲线(通过rostopic list 已查看到joint_states有运行),请问古月老师这是什么问题

    • 丑丑 回复 洋洋 2018年7月24日 上午11:13

      rqt_plot /joint_states position[0]:position[1]…….便可实现

    • 古月 回复 洋洋 2018年7月27日 上午10:15

      joint_states是一个结构体,要把里边的具体成员变量也输入的,类似:joint_states/position[0]

    • 洋洋 回复 古月 2018年7月24日 上午11:11

      古月老师请问如何实现在rviz拖动机械臂末端示教,并记录关键位置点,以便后期的轨迹再现

    • 古月 回复 洋洋 2018年7月27日 上午10:17

      在demo.launch里终端是有一个拖动的控制球的,至于记录关键点,要自己实现,没有现成的功能包,请参考moveit官方的API手册

    • 洋洋 回复 古月 2018年7月31日 下午9:34

      谢谢古月老师

  • 罗西 2018年5月3日 上午8:42

    月哥,我运行rosrun rviz rviz 时打开的界面只有一个黑色的框框了,没有左右两边的显示项了,想问一下应该怎么解决?

    • 古月 回复 罗西 2018年5月4日 上午9:10

      其他工具栏被关掉了吧,在菜单栏里找到打开就行了

  • apple 2018年1月15日 下午3:38

    古月老师你好,我在做到 点击“OK”,就会弹出“TeleopPanel”插件 这一步时没有弹出这个插件是什么原因呢?我之前也source过的,但就是找不到原因。

    • 古月 回复 apple 2018年1月15日 下午9:00

      可以看到TeleopPanel么?你用的是哪个版本的ROS,如果是Kinetic的话,会因为Qt版本的问题打不开,需要修改编译选项

    • apple 回复 古月 2018年1月21日 上午10:49

      看不到的,古月老师。我纠结了好几天了 😥 。我是Ubuntu14.04版本的。

    • 古月 回复 apple 2018年1月22日 上午11:25

      你先用《Mastering ROS for Robotics Programming》中的源码试一下,这个代码应该没问题,把source加入到bashrc中,有时候环境变量生效需要重启系统

  • 孙玉哲 2018年1月13日 下午9:24

    您好,我想在Qt界面中显示rviz的地图,请问怎么在Qt中实现地图显示呢?或者说rviz显示地图消息的原理是什么?它是怎么将消息转化为地图显示的?求指点

    • 古月 回复 孙玉哲 2018年1月13日 下午11:58

      不好意思,这个我也不是很清楚,可以找来rviz的源码看一下

    • 段彦卉 回复 孙玉哲 2019年3月21日 上午10:02

      有Librviz可以用

  • 得光 2017年12月6日 下午2:27

    古月老师您好,我想做一个初始化机械臂的一个插件,就是那种只含一个button的插件,按照这个思路写了,显示找不到相应的库,这个例子里plugin_description.xml的lib/librviz_telop_commander是自带的库是吗?那在我这个例子里,这个库应该写什么呢?

    • 古月 回复 得光 2017年12月6日 下午9:48

      librviz_telop_commander这个是此处生成的插件名,你插件编译的是什么名称这里就是什么

  • James 2017年11月22日 上午10:20

    老师你好,请问use_sim_time可不可以在一个launch文件里用两次?

    • 古月 回复 James 2017年11月23日 上午11:50

      最好不要这样做,可以分解为两个launch

  • 单腾飞 2017年11月19日 下午5:41

    胡老师,我试了一下您上面提供的github里的包,build通过了,但是在加载的时候出现[ERROR] [1511083575.461585030]: PluginlibFactory: The plugin for class ‘rviz_teleop_commander/TeleopPanel’ failed to load. Error: Could not find library corresponding to plugin rviz_teleop_commander/TeleopPanel. Make sure the plugin description XML file has the correct name of the library and that the library actually exists.我试了一下mastering ros for robotics里的包,也出现了同样的问题。代码我都是直接用的您的,没有改动过,我的环境是ubuntu14.04+indigo,Q&A里看了一下,有的说没有source,大部分说description有问题,试着改了改,但是没有效果。

    • 古月 回复 单腾飞 2017年11月19日 下午9:07

      package.xml文件修改了么?

    • 单腾飞 回复 古月 2017年11月25日 上午11:04

      重试了一遍好了,谢谢胡老师

    • 段彦卉 回复 单腾飞 2019年3月10日 下午11:33

      请问您是怎么改好的?我出现了类似的问题,我的版本是ubuntu16.04

    • 单腾飞 回复 古月 2017年11月27日 下午2:35

      胡老师,还有个问题,例程中的save函数和load函数都已经overide了,但是在cpp文件中定义了这两个函数后在哪里调用的呢,没有看见调用的地方。函数参数中的config配置文件也没有找到。所以这两个函数不是很清楚,请问是怎样被调用的呢?

    • 古月 回复 单腾飞 2017年11月29日 上午9:16

      这个是rviz插件机制需要调用的,没有体现在我们自己的程序中

    • 单腾飞 回复 古月 2017年11月29日 下午8:59

      那是意味着所有自己写的的插件都必须要重载这两个函数吗?是只需重载这两个函数还是其他的类成员函数也要重载呢?

    • 古月 回复 单腾飞 2017年11月30日 下午9:35

      只需要重载这两个函数就行

    • 单腾飞 回复 古月 2017年12月6日 下午6:59

      谢谢老师回复。胡老师,还有点小问题想请教:
      1.我是否可以这样理解:这两个函数是在rviz插件加载的时候调用load,然后将存于“Topic”的话题名称给到qstring topic然后更新output_topic_editor_的内容?save函数是rviz 插件关闭的时候,将output_topic_里的话题名称存到“Topic”里吗?但是我delte panel 后重新add这个插件并没有自动在要发布的话题名称框里显示上次的话题,这样理解不对吧?
      2.假如是这样的话重载的部分应该不是必须要有的吧?也就是说我网一个固定的话题/服务/action接口上发布数据,您例程里的load函数和save函数需要怎样重写还是不需要重写?

    • 古月 回复 单腾飞 2017年12月6日 下午9:54

      这两个重载的函数是用来更新界面的,但应该不是必须重载:virtual void load( const rviz::Config& config );
      virtual void save( rviz::Config config ) const;

  • 单腾飞 2017年11月18日 下午8:02

    古月老师您好,请问在您在ros-industrial中介绍的调试界面是如上述在rviz中不断的添加插件做出来的吗?

  • James 2017年11月13日 下午7:32

    古月老师您好,咨询您一个问题。我用ROS采集两间教室的地图,再用cartographer离线跑着两组数据,分开跑是可以的,请问可不可以将两组数据同时在一个RVIZ中跑出来??

    • 古月 回复 James 2017年11月15日 下午11:20

      可以创建两个地图显示项,地图话题不能同名,然后分别订阅,试试可不可以

    • James 回复 古月 2017年11月16日 上午9:20

      这里两个地图数据不是同时采集的对同时显示有没有影响,也就是时间戳这边会不会出现问题?

    • 古月 回复 James 2017年11月16日 下午6:53

      这个我也没做过,感觉没问题,你可以试试

    • James 回复 古月 2017年11月16日 下午8:17

      对的,时间戳这边没有问题,试过了,现在就是话题名的问题,不知改怎么修改?

    • 古月 回复 James 2017年11月18日 上午12:06

      话题名可以重映射

    • James 回复 古月 2017年11月18日 下午4:00

      重映射要不要修改发布与订阅的.cpp文件呢?

    • 古月 回复 James 2017年11月19日 下午9:01

      重映射不用,在launch里remap就可以

    • James 回复 古月 2017年11月20日 上午9:05

      问题有点多啊,崩溃!!是不是在采集数据的时候就可以改变话题名?这个还怎么修改呢?

    • 古月 回复 James 2017年11月20日 下午10:33

      看你需要修改哪些话题名了,一般是在launch或者命令行里重命名,也可以启动的时候加上命名空间试试

    • James 回复 古月 2017年11月21日 上午9:19

      用turtlebot搭载激光雷达采集激光雷达和里程计的数据,要把这两个数据的话题名改了?

    • 古月 回复 James 2017年11月21日 上午11:16

      如果有两个机器人发布同样话题的消息的话,就需要修改话题名了,否则数据会出问题

    • James 回复 古月 2017年11月16日 下午8:16

      采集好的地图数据话题信息怎么修改,是通过修改发布消息和订阅消息的文件吗?

  • 肖翼甫 2017年11月11日 下午6:33

    古月前辈,您好!
    我想请教大神一个问题,请问urdf文件,除了做仿真,还有什么其他的作用吗?

    • 古月 回复 肖翼甫 2017年11月13日 下午1:21

      你好,还可以可视化显示,有些功能包中的算法也会用到机器人的URDF模型

  • Constance 2017年10月25日 下午7:06

    大神,我想请问一下在QT-ros环境下开发rviz的插件,开发过程中,我先不让他编译成库,先让他生成可执行文件,可是怎么不能运行呢,一直报The program has unexpectedly finished.这样的错误,我检查了一下,如果不继承自rviz::Panel这个类,继承QT原生的QWidget就可以运行。还有我调试的时候直接进到像内存一样的界面,完全看不懂的那种。就像是正常调试程序出现段错误进去那种界面。请问是不是rviz::Panel不可以实例化?

    • Constance 回复 Constance 2017年10月26日 上午8:48

      现在在开发过程中我无法运行看效果,这样比较困惑,怎样设置才可以呢,古月大神。

    • 古月 回复 Constance 2017年10月26日 上午9:24

      如果不需要rviz,用qt creator做开发调试比较方便

    • 古月 回复 Constance 2017年10月26日 上午9:21

      如果继承QT原生的QWidget,应该就是一个原生的qt程序,可以编译成可执行文件,但不算是插件,如果不需要依托rviz,这样做是没问题的。关于rviz::Panel,可以看相关的文档:http://docs.ros.org/jade/api/rviz/html/c++/classrviz_1_1Panel.html

    • Constance 回复 古月 2017年10月26日 上午9:27

      可是我就是需要开发一个rviz的插件,所以我要继承rviz::Panel,但是这样就无法调试吗?

    • 古月 回复 Constance 2017年10月26日 下午1:24

      rviz插件的在线调试我也没试过,不确定是否可以

  • rospoor 2017年10月25日 上午11:23

    古月老师您好,我按照步骤都弄完了,但是我在rviz 中add时没有看到那个插件,我的编译没有问题,source也做了。我是个新手,目前比较困惑 🙂

    • 古月 回复 rospoor 2017年10月26日 上午8:38

      你好,不是点rviz左下角的add,是在菜单栏里选Panel –> Add New Panel

  • rospoor 2017年10月25日 上午11:23

    古月老师您好,我按照步骤都弄完了,但是我在rviz 中add时没有看到那个插件,我的编译没有问题,source也做了。我是个新手,目前比较困惑

    • real_dg 回复 rospoor 2017年11月22日 下午4:34

      是在rviz界面的左上角,有files panels help

  • lyyh 2017年10月13日 下午5:47

    大神你好,有个问题,机械臂在moveit中从a点到b点的轨迹需要保持rx,ry坐标不变,怎么在程序中设置约束?

    • 古月 回复 lyyh 2017年10月14日 下午3:26

      你好,也就是只在z向运动么?可以使用moveit中的cartesian_path走直线

    • lyyh 回复 古月 2017年10月16日 上午9:27

      不是z方向运动 是规划轨迹时约束末端执行器运动时orientation保持水平(即orientation x 和orientation y不变) 但是orientation z 是可变的(由moveit规划决定),这样的约束如何实现

    • 古月 回复 lyyh 2017年10月16日 下午6:29

      不好意思,这个我还不太清楚

  • Richard 2017年10月11日 下午2:35

    古月老师,您好!
    我按照按照本篇博客的内容搭了环境,跑下来碰到两个问题:
    1. 用catkin_make编译时,qt4有报错: “/usr/include/boot/type_traits/detail/has_binary_operator.hp: Parse error at “BOOST_JOIN” “,有workaround可以绕过:https://stackoverflow.com/questions/15455178/qt4-cgal-parse-error-at-boost-join,最终编译可以通过。
    2. 编译成功以后,打开rviz,在”Add New Panel”里面可以找到新添加的”TeleopPanel”插件,但只要一运行程序就崩溃: Segmentation fault (core dumped)。以前没调试过这种段错误,所以这个问题没找到怎么解决,特来请教。非常感谢。

    不确定是否是我环境的问题,我用的是generic Ubuntu 16.04 (desktop x64), 系统自带了QT (QMake version 2.01a, Qt version 4.8.7),ROS版本是Kinetic。现在官网QT版本最新已经是5.9了,不太清楚是不是因为Qt版本太旧了。

    • 古月 回复 Richard 2017年10月11日 下午6:40

      我用的是ubuntu14.04+ros indigo版本,在16.04和kinetic上可能会有依赖软件版本不同的问题,这个我还没试过

    • Richard 回复 古月 2017年10月12日 上午11:03

      谢谢古月老师回复,通过修改CMakelists.txt解决了这个问题,看起来的确是一些运行时的依赖库问题。

    • 古月 回复 Richard 2017年10月13日 上午8:20

      能否具体说下修改了什么?我也学习一下

    • 王芳 回复 Richard 2018年1月30日 下午2:27

      我也遇到同样的情况,运行就是段错误,请问下,您是如何修改的呢?

    • 古月 回复 王芳 2018年1月30日 下午5:37

      qt版本不一样,你试下把CMakelists.txt里边的qt4都改成qt5

    • candy 回复 古月 2018年1月31日 下午4:08

      古月大侠,不改前,包能编译通过,都改为qt5,出错如下:
      CMake Error at /usr/lib/x86_64-linux-gnu/cmake/Qt5/Qt5Config.cmake:26 (find_package):
      Could not find a package configuration file provided by “Qt5QtCore” with
      any of the following names:

      Qt5QtCoreConfig.cmake
      qt5qtcore-config.cmake

      Add the installation prefix of “Qt5QtCore” to CMAKE_PREFIX_PATH or set
      “Qt5QtCore_DIR” to a directory containing one of the above files. If
      “Qt5QtCore” provides a separate development package or SDK, be sure it has
      been installed.
      Call Stack (most recent call first):
      ros_blog_sources/rviz_teleop_commander/CMakeLists.txt:14 (find_package)

      — Configuring incomplete, errors occurred!
      See also “/root/catkin_ws/build/CMakeFiles/CMakeOutput.log”.
      See also “/root/catkin_ws/build/CMakeFiles/CMakeError.log”.
      Makefile:2908: recipe for target ‘cmake_check_build_system’ failed
      make: *** [cmake_check_build_system] Error 1
      Invoking “make cmake_check_build_system” failed

    • candy 回复 古月 2018年1月31日 下午5:05

      查了资料,经实践测试通过,更改为qt5需要在CMakelists.txt中更改的内容为如下:
      (1)添加
      set (Qt5QtCore_DIR /usr/lib/x86_64-linux-gnu/cmake)

      (2)Qt4 QtCore QtGui改为如下
      ## This plugin includes Qt widgets, so we must include Qt like so:
      #find_package(Qt4 COMPONENTS QtCore QtGui REQUIRED)
      find_package(Qt5 COMPONENTS Core Gui REQUIRED)

      ## Here we specify which header files need to be run through “moc”,
      ## Qt’s meta-object compiler.
      #qt4_wrap_cpp(MOC_FILES
      qt5_wrap_cpp(MOC_FILES
      src/teleop_pad.h
      )

      (3)编译依赖库更改如下,删除 ${QT_LIBRARIES}
      #target_link_libraries(${PROJECT_NAME} ${QT_LIBRARIES} ${catkin_LIBRARIES})
      target_link_libraries(${PROJECT_NAME} ${catkin_LIBRARIES})

      添加
      target_link_libraries(rviz_teleop_commander Qt5::Widgets)

      编译包catkin_make –pkg rviz_teleop_commander后,运行rviz可以使用rviz plugin了

    • candy 回复 古月 2018年1月31日 下午5:14

      更正,查了资料,经实践测试通过,更改为qt5需要在CMakelists.txt中更改的内容为如下:
      (1)添加find_package(Qt5Widgets) 以及设置Qt5QtCore_DIR,位置如下
      find_package(Qt5Widgets)
      catkin_package()
      include_directories(${catkin_INCLUDE_DIRS})
      link_directories(${catkin_LIBRARY_DIRS})
      set (Qt5QtCore_DIR /usr/lib/x86_64-linux-gnu/cmake)

      (2)Qt4 QtCore QtGui改为如下
      ## This plugin includes Qt widgets, so we must include Qt like so:
      #find_package(Qt4 COMPONENTS QtCore QtGui REQUIRED)
      find_package(Qt5 COMPONENTS Core Gui REQUIRED)

      ## Here we specify which header files need to be run through “moc”,
      ## Qt’s meta-object compiler.
      #qt4_wrap_cpp(MOC_FILES
      qt5_wrap_cpp(MOC_FILES
      src/teleop_pad.h
      )

      (3)编译依赖库更改如下,删除 ${QT_LIBRARIES}
      #target_link_libraries(${PROJECT_NAME} ${QT_LIBRARIES} ${catkin_LIBRARIES})
      target_link_libraries(${PROJECT_NAME} ${catkin_LIBRARIES})

      添加
      target_link_libraries(rviz_teleop_commander Qt5::Widgets)

      编译包catkin_make –pkg rviz_teleop_commander后,运行rviz可以使用rviz plugin了

    • 古月 回复 candy 2018年1月31日 下午7:11

      赞,学习了,非常感谢!

    • alan 回复 candy 2018年7月13日 上午11:33

      还有一个需要改动的:
      #include(${QT_USE_FILE})
      include_directories(${QT_USE_FILE})
      不然还是会报错。

  • JIAMIN 2017年7月26日 上午8:53

    古月老师,您好,想问下,您有做过ROS与android的通讯连接吗?我在示例中看有rosbridge这个包,但是不是特别懂

    • 古月 回复 JIAMIN 2017年7月27日 下午2:42

      ros有java的接口实现,可以在android上跑ros节点,可以google找一下,turtlebot好像也有android的控制客户端

    • JIAMIN 回复 古月 2017年7月27日 下午4:15

      好的,那我找找看,谢谢您了

  • Celine 2017年7月19日 上午9:39

    古月老师,您好!
    咨询您一个问题!
    我现在使用的是window操作系统,想远程控制Ubuntu,嘿嘿,就是Ubuntu上面安装了ROS。
    现在按照网络上的教材可以远程连接上了,问题是只有命令行界面,没有图形化界面。
    只要运行类似RVIZ,GAZEBO之类的就不行。
    请问,有什么办法能够让远程控制的Ubuntu能够运行这些图形界面么?
    非常感谢!
    Celine
    Best Regards
    Hope you happy every day!