机器人操作系统ROS—入门

上次我们通过机器人操作系统ROS—初探了解了ROS的基本概念和运行机制,并用内置的小龟模拟器进行了测试。本文我们开始学习如何编写自定义的Service/Client节点进行指定msg格式通信、尝试bag的录制和回放、并简单了解下三维可视化。

一、创建ROS msg消息和srv服务格式

参考:Creating a ROS msg and srv

温习一下,上一次我们了解到topic里的Message、ROS Services概念:

消息(msg):

 msg文件就是一个描述ROS中所使用消息类型的简单文本。它们会被用来生成不同语言的源代码。

msg文件存放在package的msg目录下,内容实际上就是每行声明一个数据类型和变量名。可以使用的数据类型如下:

  • int8, int16, int32, int64 (plus uint*)
  • float32, float64
  • string
  • time, duration
  • other msg files
  • variable-length array[] and fixed-length array[C]

在ROS中有一个特殊的数据类型:Header,它含有时间戳和坐标系信息。在msg文件的第一行经常可以看到Header header的声明.

下面是一个示例msg文件,它使用了Header,string,和其他另外两个消息类型。

  Header header
  string child_frame_id
  geometry_msgs/PoseWithCovariance pose
  geometry_msgs/TwistWithCovariance twist

服务(srv):

一个srv文件描述一项服务。它包含两个部分:请求和响应。

srv文件则存放在srv目录下,内容分为请求和响应两部分,由’—‘分隔。下面是一个示例srv:

int64 A
int64 B
---
int64 Sum

其中 A 和 B 是请求, 而Sum 是响应。

自定义一个msg消息格式:

cd ~/catkin_ws/src/beginner_tutorials

# 创建msg定义文件
mkdir msg
vim msg/Num.msg
    string first_name
    string last_name
    uint8 age
    uint32 score


# 配置msg/srv编译/运行依赖
vim package.xml
    <build_depend>message_generation</build_depend>    #将msg/srv文件编译为c++/python代码
    <exec_depend>message_runtime</exec_depend>    #执行依赖


vim CMakeLists.txt
    find_package(catkin REQUIRED COMPONENTS
      roscpp
      rospy
      std_msgs
      message_generation    #增加msg/srv编译依赖
    )

    catkin_package(
       CATKIN_DEPENDS message_runtime    #增加msg/srv运行依赖
    )

    add_message_files(
      FILES
      Num.msg    #指定msg文件列表
    )

    generate_messages(   #确保CMake调用generate_messages()函数
      DEPENDENCIES
      std_msgs
    )


# 测试定义的msg消息类型能否被识别
# rosmsg show [message type]
rosmsg show beginner_tutorials/Num
    string first_name
    string last_name
    uint8 age
    uint32 score

rosmsg show Num      #也可以不带package名直接查msgtype
    [beginner_tutorials/Num]:
        string first_name
        string last_name
        uint8 age
        uint32 score
    

自定义一个srv服务参数/返回值:

roscd beginner_tutorials

# 创建一个srv服务
mkdir srv
# roscp [package_name] [file_to_copy_path] [copy_path]
# roscp rospy_tutorials AddTwoInts.srv srv/AddTwoInts.srv    #从rospy_tutorials package中复制一个服务文件过来
vim srv/AddTwoInts.srv
    int64 a
    int64 b
    ---
    int64 sum

# 配置srv编译/运行依赖
vim CMakeLists.txt
  add_service_files(
    FILES
    AddTwoInts.srv
  )

# 测试srv服务能否被识别
rossrv show beginner_tutorials/AddTwoInts
    int64 a
    int64 b
    ---
    int64 sum

rossrv show AddTwoInts    #跟rosmsg类似, 你也可以不指定具体的package名来查找服务文件
    [rospy_tutorials/AddTwoInts]:
        int64 a
        int64 b
        ---
        int64 sum

编译msg/srv格式文件:

cd ~/catkin_ws
catkin_make

#所有在msg路径下的.msg文件都将转换为ROS所支持语言的源代码。生成的代码位置:
  C++:~/catkin_ws/devel/include/beginner_tutorials/
  Python:~/catkin_ws/devel/lib/python3/dist-packages/beginner_tutorials/msg/
  lisp:~/catkin_ws/devel/share/common-lisp/ros/beginner_tutorials/msg/

二、编写简单的消息发布器和订阅器

参考:Writing a Simple Publisher and Subscriber (C++)Writing a Simple Publisher and Subscriber (Python)

C++版本:

roscd beginner_tutorials
mkdir -p src

# 新建消息pub发布器 
vim src/talker.cpp
    #include "ros/ros.h"
    #include "std_msgs/String.h"
    #include <sstream>

    /**
     * ROS消息pub测试
     */
    int main(int argc, char **argv)
    {
      //初始化 ROS
      ros::init(argc, argv, "talker");
      //进程节点句柄
      ros::NodeHandle n;
      //告诉master我们将要在chatter topic上发布std_msgs/String消息类型的消息(缓冲区保留最近1000条消息)
      ros::Publisher chatter_pub = n.advertise<std_msgs::String>("chatter", 1000);
      //以 10Hz 的频率运行。
      ros::Rate loop_rate(10);  

      int count = 0;
      while (ros::ok())
      {
        //消息对象
        std_msgs::String msg;
        std::stringstream ss;
        ss << "hello world " << count;
        msg.data = ss.str();
        ROS_INFO("%s", msg.data.c_str());
        //发布消息
        chatter_pub.publish(msg);
        //接受回调
        ros::spinOnce();
        //休眠以保持发布频率为10Hz
        loop_rate.sleep();
        ++count;
      }


      return 0;
    }



# 新建消息sub订阅器 
vim src/listener.cpp
    #include "ros/ros.h"
    #include "std_msgs/String.h"

    /**
     * ROS消息sub测试
     */

    //sub到消息时的回调
    void chatterCallback(const std_msgs::String::ConstPtr& msg)
    {
      ROS_INFO("I heard: [%s]", msg->data.c_str());
    }

    int main(int argc, char **argv)
    {
      //初始化 ROS
      ros::init(argc, argv, "listener");
      //进程节点句柄
      ros::NodeHandle n;
      //告诉master我们要订阅chatter话题上的消息
      ros::Subscriber sub = n.subscribe("chatter", 1000, chatterCallback);
      //相当与waiting(有新消息、或需要退出时会跳过)
      ros::spin();

      return 0;
    }



# 配置
vim CMakeLists.txt 
    include_directories(
      #include 
      ${catkin_INCLUDE_DIRS}
    )
    #不要修改代码顺序
    add_executable(talker src/talker.cpp)
    target_link_libraries(talker ${catkin_LIBRARIES})
    add_dependencies(talker beginner_tutorials_generate_messages_cpp)

    add_executable(listener src/listener.cpp)
    target_link_libraries(listener ${catkin_LIBRARIES})
    add_dependencies(listener beginner_tutorials_generate_messages_cpp)


# 编译
cd ~/catkin_ws
catkin_make    #编译产出位置:~/catkin_ws/devel/lib/beginner_tutorials/talker、listener

# 测试运行
roscore
rosrun beginner_tutorials talker
rosrun beginner_tutorials listener

Python版本:

roscd beginner_tutorials
mkdir scripts
cd scripts

# 新建消息pub发布器
vim talker.py
    #!/usr/bin/env python
    # -*- coding: utf-8 -*-
    """
    File: talker.py
    Desc: 消息pub发布
    Author:yanjingang(yanjingang@mail.com)
    Date: 2020/6/15 22:37
    """
    import rospy
    from std_msgs.msg import String

    def talker():
        # 通知master我们将要在chatter topic上发布std_msgs/String 消息类型的消息
        pub = rospy.Publisher('chatter', String, queue_size=10)   #queue_size:缓冲区保留的最近消息条数
        # 初始化 ROS
        rospy.init_node('talker', anonymous=True)
        # 发送频率10hz
        rate = rospy.Rate(10) 
        while not rospy.is_shutdown():
            hello_str = "hello world %s" % rospy.get_time()
            rospy.loginfo(hello_str)
            # pub消息
            pub.publish(hello_str)
            # 休眠以确保10hz的频率
            rate.sleep()

    if __name__ == '__main__':
        try:
            talker()
        except rospy.ROSInterruptException:
            pass


# 新建消息sub订阅器
vim listener.py
    #!/usr/bin/env python
    # -*- coding: utf-8 -*-
    """
    File: listener.py
    Desc: 消息sub订阅
    Author:yanjingang(yanjingang@mail.com)
    Date: 2020/6/15 22:37
    """
    import rospy
    from std_msgs.msg import String

    def callback(data):
        '''sub消息回调'''
        rospy.loginfo(rospy.get_caller_id() + "I heard %s", data.data)
        
    def listener():
        # ros初始化
        rospy.init_node('listener', anonymous=True)
        # 告诉master我们要订阅chatter话题上的消息
        rospy.Subscriber("chatter", String, callback)
        # 相当与waiting(有新消息、或需要退出时会跳过)
        rospy.spin()


    if __name__ == '__main__':
        listener()


# 配置
vim CMakeLists.txt.
  catkin_install_python(PROGRAMS scripts/talker.py scripts/listener.py
    DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION}
  )

chmod +x talker.py  listener.py


# 编译
cd ~/catkin_ws
catkin_make


# 测试运行
roscore
rosrun beginner_tutorials talker.py
rosrun beginner_tutorials listener.py

三、编写简单的Service和Client

参考:Writing a Simple Service and Client (C++)Writing a Simple Service and Client (Python)

C++版本:

roscd beginner_tutorials

# 编写server
vim src/add_two_ints_server.cpp
    #include "ros/ros.h"
    #include "beginner_tutorials/AddTwoInts.h"
    bool add(beginner_tutorials::AddTwoInts::Request  &req,
            beginner_tutorials::AddTwoInts::Response &res)
    {
      res.sum = req.a + req.b;
      ROS_INFO("request: x=%ld, y=%ld", (long int)req.a, (long int)req.b);
      ROS_INFO("sending back response: [%ld]", (long int)res.sum);
      return true;
    }
    int main(int argc, char **argv)
    {
      ros::init(argc, argv, "add_two_ints_server");
      ros::NodeHandle n;
      ros::ServiceServer service = n.advertiseService("add_two_ints", add);
      ROS_INFO("Ready to add two ints.");
      ros::spin();
      return 0;
    }

# 编写client
vim src/add_two_ints_client.cpp
    #include "ros/ros.h"
    #include "beginner_tutorials/AddTwoInts.h"
    #include <cstdlib>
    int main(int argc, char **argv)
    {
      ros::init(argc, argv, "add_two_ints_client");
      if (argc != 3)
      {
        ROS_INFO("usage: add_two_ints_client X Y");
        return 1;
      }
      ros::NodeHandle n;
      ros::ServiceClient client = n.serviceClient<beginner_tutorials::AddTwoInts>("add_two_ints");
      beginner_tutorials::AddTwoInts srv;
      srv.request.a = atoll(argv[1]);
      srv.request.b = atoll(argv[2]);
      if (client.call(srv)){
        ROS_INFO("Sum: %ld", (long int)srv.response.sum);
      }else{
        ROS_ERROR("Failed to call service add_two_ints");
        return 1;
      }
      return 0;
    }


# 配置
vim CMakeLists.txt
    add_executable(add_two_ints_server src/add_two_ints_server.cpp)
    target_link_libraries(add_two_ints_server ${catkin_LIBRARIES})
    add_dependencies(add_two_ints_server beginner_tutorials_gencpp)

    add_executable(add_two_ints_client src/add_two_ints_client.cpp)
    target_link_libraries(add_two_ints_client ${catkin_LIBRARIES})
    add_dependencies(add_two_ints_client beginner_tutorials_gencpp)


# 编译
cd ~/catkin_ws
catkin_make

# 测试
roscore
rosrun beginner_tutorials add_two_ints_server
    [ INFO] [1592295430.720743006]: Ready to add two ints.
    [ INFO] [1592295447.819885626]: request: x=1, y=3
    [ INFO] [1592295447.819908758]: sending back response: [4]

rosrun beginner_tutorials add_two_ints_client 1 3
    [ INFO] [1592295452.507057100]: Sum: 4

Python版本:

roscd beginner_tutorials

# 新建server
vim scripts/add_two_ints_server.py
        #!/usr/bin/env python3
        # -*- coding: utf-8 -*-
        """
        File: add_two_ints_server.py
        Desc: server测试
        Author:yanjingang(yanjingang@mail.com)
        Date: 2020/6/15 23:12
        """
        import rospy
        from beginner_tutorials.srv import AddTwoInts,AddTwoIntsResponse

        def handle_add_two_ints(req):
            print("Returning [%s + %s = %s]"%(req.a, req.b, (req.a + req.b)))
            return AddTwoIntsResponse(req.a + req.b)

        def add_two_ints_server():
            # ROS初始化
            rospy.init_node('add_two_ints_server')
            # 新建名为add_two_ints的server,输入AddTwoInts,返回AddTwoIntsResponse
            s = rospy.Service('add_two_ints', AddTwoInts, handle_add_two_ints)
            print("Ready to add two ints.")
            rospy.spin()

        if __name__ == "__main__":
            add_two_ints_server()


#新建client
vim scripts/add_two_ints_client.py
        #!/usr/bin/env python3
        # -*- coding: utf-8 -*-
        """
        File: add_two_ints_client.py
        Desc: client测试
        Author:yanjingang(yanjingang@mail.com)
        Date: 2020/6/15 23:15
        """
        import sys
        import rospy
        from beginner_tutorials.srv import AddTwoInts,AddTwoIntsResponse

        def add_two_ints_client(x, y):
            # 连接名为add_two_ints的server
            rospy.wait_for_service('add_two_ints')
            try:
                # 初始化server对象(声明参数类型为AddTwoInts)
                add_two_ints = rospy.ServiceProxy('add_two_ints', AddTwoInts)
                # 调用server
                resp1 = add_two_ints(x, y)
                # 输出返回值
                return resp1.sum
            except rospy.ServiceException as e:
                print("Service call failed: %s"%e)

        def usage():
            return "%s [x y]"%sys.argv[0]

        if __name__ == "__main__":
            if len(sys.argv) == 3:
                x = int(sys.argv[1])
                y = int(sys.argv[2])
            else:
                print(usage())
                sys.exit(1)
            print("Requesting %s+%s"%(x, y))
            print("%s + %s = %s"%(x, y, add_two_ints_client(x, y)))


# 配置
vim CMakeLists.txt
    catkin_install_python(PROGRAMS scripts/talker.py scripts/listener.py  scripts/add_two_ints_server.py scripts/add_two_ints_client.py
      DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION}
    )

chmod +x scripts/add_two_ints_server.py
chmod +x scripts/add_two_ints_client.py


# 编译
cd ~/catkin_ws
catkin_make


# 测试
roscore
rosrun beginner_tutorials add_two_ints_server.py
    Ready to add two ints.
    Returning [1 + 3 = 4]
rosrun beginner_tutorials add_two_ints_client.py 1 3
    Requesting 1+3
    1 + 3 = 4

四、bag包的录制与回放

参考:Recording and playing back data

这里学习如何将ROS系统运行过程中的数据录制到一个.bag文件中,然后通过回放数据来重现相似的运行过程。

# 启动小龟模拟器和键盘控制节点(用于产生数据)
roscore
rosrun turtlesim turtlesim_node 
rosrun turtlesim turtle_teleop_key

# 录制数据
mkdir ~/bagfiles
cd ~/bagfiles
rosbag record -a    #-a表示将当前发布的所有话题数据都录制保存到一个bag文件中
或
rosbag record -O test /turtle1/cmd_vel /turtle1/pose  #-O表示录制指定topic到指定名称的bag文件中 
#现在用键盘控制小龟随处移动10秒钟左右,然后Ctrl-C退出rosbag record -a录制


# 查看bag包数据   (可以看到话题的名称、类型和消息数量)
rosbag info ~/bagfiles/2020-06-16-16-26-50.bag    #或test.bag
    path:        2020-06-16-16-26-50.bag
    version:     2.0
    duration:    48.7s
    start:       Jun 16 2020 16:26:50.47 (1592296010.47)
    end:         Jun 16 2020 16:27:39.14 (1592296059.14)
    size:        426.8 KB
    messages:    6081
    compression: none [1/1 chunks]
    types:       geometry_msgs/Twist [9f195f881246fdfa2798d1d3eebca84a]
                 rosgraph_msgs/Log   [acffd30cd6b6de30f120938c17c593fb]
                 turtlesim/Color     [353891e354491c51aabe32df673fb446]
                 turtlesim/Pose      [863b248d5016ca62ea2e895ae5265cf9]
    topics:      /rosout                    6 msgs    : rosgraph_msgs/Log   (2 connections)
                 /turtle1/cmd_vel          17 msgs    : geometry_msgs/Twist
                 /turtle1/color_sensor   3029 msgs    : turtlesim/Color    
                 /turtle1/pose           3029 msgs    : turtlesim/Pose



# 回放bag包数据
# 先Ctrl-C退出turtle_teleop_key键盘控制节点(如果想看到一模一样的效果,需要把小龟模拟器也重启)
rosbag play ~/bagfiles/2020-06-16-16-26-50.bag     #或test.bag。查看小龟模拟器能看到移动指令被重放了

五、三维仿真可视化

参考:Markers: Sending Basic Shapes (C++)Markers: Points and Lines (C++)

gazebo和rviz是ROS里比较常见的两个3D可视化工具,两者的主要功能不同,如果做ROS开发,一般两个都得会。
rviz是三维可视化工具,强调把已有的数据可视化显示;
rviz需要已有数据。
rviz提供了很多插件,这些插件可以显示图像、模型、路径等信息,但是前提都是这些数据已经以话题、参数的形式发布,rviz做的事情就是订阅这些数据,并完成可视化的渲染,让开发者更容易理解数据的意义。

gazebo不是显示工具,强调的是仿真,它不需要数据,而是创造数据。
我们可以在gazebo中免费创建一个机器人世界,不仅可以仿真机器人的运动功能,还可以仿真机器人的传感器数据。而这些数据就可以放到rviz中显示,所以使用gazebo的时候,经常也会和rviz配合使用。当我们手上没有机器人硬件或实验环境难以搭建时,仿真往往是非常有用的利器。

 

下面我们试下rviz的基础用法:

# 创建ROS程序包
cd ~/catkin_ws/src
# catkin_create_pkg <package_name> [depend1] [depend2] [depend3]
catkin_create_pkg using_markers roscpp visualization_msgs

# 基础图形绘制
cd using_markers/
vim src/basic_shapes.cpp
  #include <ros/ros.h>
  #include <visualization_msgs/Marker.h>
  /**
   * 基础形状三维可视化测试
   */
  int main( int argc, char** argv )
  {
    // 初始化ROS并新建publisher
    ros::init(argc, argv, "basic_shapes");
    ros::NodeHandle n;
    ros::Rate r(1);
    ros::Publisher marker_pub = n.advertise<visualization_msgs::Marker>("visualization_marker", 1);
    // 立方体
    uint32_t shape = visualization_msgs::Marker::CUBE;
    while (ros::ok())
    {
      visualization_msgs::Marker marker;
      // 设置帧ID和时间戳
      marker.header.frame_id = "/my_frame";
      marker.header.stamp = ros::Time::now();
      // 设置命名空间和id(同命名空间+id发送的数据会覆盖)
      marker.ns = "basic_shapes";
      marker.id = 0;
      // 设置类型为立方体
      marker.type = shape;
      // 设置动作
      marker.action = visualization_msgs::Marker::ADD;
      // 设置姿态
      marker.pose.position.x = 0;
      marker.pose.position.y = 0;
      marker.pose.position.z = 0;
      marker.pose.orientation.x = 0.0;
      marker.pose.orientation.y = 0.0;
      marker.pose.orientation.z = 0.0;
      marker.pose.orientation.w = 1.0;
      // 设置边界距离
      marker.scale.x = 1.0;
      marker.scale.y = 1.0;
      marker.scale.z = 1.0;
      // 设置颜色
      marker.color.r = 0.0f;
      marker.color.g = 1.0f;
      marker.color.b = 0.0f;
      marker.color.a = 1.0;   //0完全透明,1完全不透明
      // 设置过期时间
      marker.lifetime = ros::Duration();  //没传表示用不过期
      // pub maker
      while (marker_pub.getNumSubscribers() < 1)
      {
        if (!ros::ok())
        {
          return 0;
        }
        ROS_WARN_ONCE("Please create a subscriber to the marker");
        sleep(1);
      }
      marker_pub.publish(marker);
      // 在不同形状之间循环
      switch (shape)
      {
        case visualization_msgs::Marker::CUBE:
          shape = visualization_msgs::Marker::SPHERE;
          break;
        case visualization_msgs::Marker::SPHERE:
          shape = visualization_msgs::Marker::ARROW;
          break;
        case visualization_msgs::Marker::ARROW:
          shape = visualization_msgs::Marker::CYLINDER;
          break;
        case visualization_msgs::Marker::CYLINDER:
          shape = visualization_msgs::Marker::CUBE;
          break;
      }
      r.sleep();
    }
  }


# 配置
vim CMakeLists.txt
    add_executable(basic_shapes src/basic_shapes.cpp)
    target_link_libraries(basic_shapes ${catkin_LIBRARIES})

# 编译
cd ~/catkin_ws
catkin_make

# 运行maker绘制节点
roscore
rosrun using_markers basic_shapes

# 运行rviz渲染节点
rosmake rviz      #构架rviz使其能找到maker
rosrun rviz rviz    #frame填上/my_frame,如果没有maker节点就手工添加一个

# 点线绘制
roscd using_markers
vim src/points_and_lines.cpp
  #include <ros/ros.h>
  #include <visualization_msgs/Marker.h>
  #include <cmath>
  /**
   * 点/线三维可视化测试
   */
  int main( int argc, char** argv )
  {
    // 初始化ROS并新建publisher
    ros::init(argc, argv, "points_and_lines");
    ros::NodeHandle n;
    ros::Publisher marker_pub = n.advertise<visualization_msgs::Marker>("visualization_marker", 10);
    ros::Rate r(30);
    float f = 0.0;
    while (ros::ok())
    {
      // 设置点线marker
      visualization_msgs::Marker points, line_strip, line_list;
      points.header.frame_id = line_strip.header.frame_id = line_list.header.frame_id = "/my_frame";
      points.header.stamp = line_strip.header.stamp = line_list.header.stamp = ros::Time::now();
      points.ns = line_strip.ns = line_list.ns = "points_and_lines";
      points.action = line_strip.action = line_list.action = visualization_msgs::Marker::ADD;
      points.pose.orientation.w = line_strip.pose.orientation.w = line_list.pose.orientation.w = 1.0;
      points.id = 0;
      line_strip.id = 1;
      line_list.id = 2;
      points.type = visualization_msgs::Marker::POINTS;
      line_strip.type = visualization_msgs::Marker::LINE_STRIP;
      line_list.type = visualization_msgs::Marker::LINE_LIST;
      // 用x/y表示高宽
      points.scale.x = 0.2;
      points.scale.y = 0.2;
      line_strip.scale.x = 0.1;
      line_list.scale.x = 0.1;
      // 设置颜色
      points.color.g = 1.0f;
      points.color.a = 1.0;
      line_strip.color.b = 1.0;
      line_strip.color.a = 1.0;
      line_list.color.r = 1.0;
      line_list.color.a = 1.0;
      // 设置角点
      for (uint32_t i = 0; i < 100; ++i)
      {
        float y = 5 * sin(f + i / 100.0f * 2 * M_PI);
        float z = 5 * cos(f + i / 100.0f * 2 * M_PI);
        geometry_msgs::Point p;
        p.x = (int32_t)i - 50;
        p.y = y;
        p.z = z;
        points.points.push_back(p);
        line_strip.points.push_back(p);
        line_list.points.push_back(p);
        p.z += 1.0;
        line_list.points.push_back(p);
      }
      //发布点线
      marker_pub.publish(points);
      marker_pub.publish(line_strip);
      marker_pub.publish(line_list);
      r.sleep();
      f += 0.04;
    }
  }


# 设置
vim CMakeLists.txt
  add_executable(points_and_lines src/points_and_lines.cpp)
  target_link_libraries(points_and_lines ${catkin_LIBRARIES})

# 编译
cd ~/catkin_ws
catkin_make

# 运行
roscore
rosrun using_markers points_and_lines
rosrun rviz rviz  #frame填上/my_frame,如果没有maker节点就手工添加一个

一个乒乓仿真的示例:

# 下载乒乓仿真节点代码
cd ~/project
git clone https://github.com/ros-visualization/visualization_tutorials
cp -r visualization_tutorials/interactive_marker_tutorials ~/catkin_ws/src/

# 编译
cd ~/catkin_ws
catkin_make

# 运行
rosrun interactive_marker_tutorials pong   # 从~/catkin_ws/src/interactive_marker_tutorials/src/pong.cpp里找到frame_id,rviz接收消息用
rosrun rviz rviz    #设置frame_id,添加InteractiveMarkers后选择Update Topic即可

# 测试python控制rviz
cp ~/project/visualization_tutorials/rviz_python_tutorial/ ~/catkin_ws/src/ -r
cd ~/catkin_ws
catkin_make

# 运行
rosrun rviz_python_tutorial myviz.py

 

好的,今天我们主要学习了怎么编写自定义的Service/Client节点进行指定msg格式通信、尝试bag的录制和回放、以及基础的三维可视化用法。下一篇我们会尝试加入硬件,实现一个简单的实例。

yan 20.6.17 23:56

参考:

en – ROS Wiki

手把手教你用Gazebo仿真UUV水下机器人

欢迎关注下方“非著名资深码农“公众号进行交流~

发表评论

邮箱地址不会被公开。