ROS初学教程

梦想不抛弃苦心追求的人,只要不停止追求,你们会沐浴在梦想的光辉之中。再美好的梦想与目标,再完美的计划和方案,如果不能尽快在行动中落实,最终只能是纸上谈兵,空想一番。只要瞄准了大方向,坚持不懈地做下去,才能够扫除挡在梦想前面的障碍,实现美好的人生蓝图。ROS初学教程,希望对大家有帮助,欢迎收藏,转发!站点地址:www.bmabk.com,来源:原文

How to use ROS

ROS初学教程

安装与配置

跟据 Ubuntu 版本选择对应的 ROS 版本,其中 Ubuntu18.04 应安装 melodic,以下过程以 melodic 为例

按顺序执行以下命令以安装 ROS,建议选择网络良好的环境

sudo sh -c 'echo "deb http://packages.ros.org/ros/ubuntu $(lsb_release -sc) main" > /etc/apt/sources.list.d/ros-latest.list'
sudo apt-key adv --keyserver 'hkp://keyserver.ubuntu.com:80' --recv-key C1CF6E31E6BADE8868B172B4F42ED6FBAB17C654
sudo apt update
sudo apt install ros-melodic-desktop-full

配置 shell 环境

echo "source /opt/ros/melodic/setup.bash" >> ~/.bashrc
source ~/.bashrc

若 shell 为 zsh,则

echo "source /opt/ros/melodic/setup.zsh" >> ~/.zshrc
source ~/.zshrc

安装其他依赖

sudo apt install python-rosdep python-rosinstall python-rosinstall-generator python-wstool build-essential
sudo apt install python-rosdep
sudo rosdep init
rosdep update

创建工作区

mkdir -p ~/catkin_ws/src
cd ~/catkin_ws
catkin_make
source devel/setup.zsh	# 以zsh为例,下同

echo $ROS_PACKAGE_PATH 检验环境已覆盖,该指令将打印所有已添加的 ros package 路径,以分号分割


系统指令

命令

  • rospack

    获取与 package 相关信息,例如

    rospack find roscpp
    

    将返回 /opt/ros/melodic/share/roscpp

  • roscd

    直接切换目录到 package,例如

    roscd roscpp
    

    注意该命令只对 ROS_PACKAGE_PATH 中包含的 package 有效

    roscd log 将进入储存日志文件的文件夹,注意若此时尚未运行任何 ROS 程序,则该指令报错

  • rosls

    直接打印 package 中的文件名,例如

    rosls roscpp_tutorials
    

其他

ROS 命令支持 TAB 自动补全


ROS Package

目录结构

workspace_folder/        -- WORKSPACE
  src/                   -- SOURCE SPACE
    CMakeLists.txt       -- 'Toplevel' CMake file, provided by catkin
    package_1/
      CMakeLists.txt     -- CMakeLists.txt file for package_1
      package.xml        -- Package manifest for package_1
    ...
    package_n/
      CMakeLists.txt     -- CMakeLists.txt file for package_n
      package.xml        -- Package manifest for package_n

创建包

catkin_create_pkg <package_name> [depend1] [depend2]...[dependn]

例如在上文中创建的 catkin_ws/src 中执行

catkin_create_pkg beginner_tutorials std_msgs rospy roscpp

构建包

catkin_ws 目录下执行

catkin_make

将工作区添加到 ROS 环境中,执行

. ./devel/setup.zsh

查看包依赖

rospack depends1 beginner_tutorials	# 直接依赖
rospack depends beginner_tutorials	# 间接依赖

ROS Nodes

概念简述

  • 节点:节点是使用ROS与其他节点通信的可执行文件。
  • 消息:订阅或发布主题时使用的ROS数据类型。
  • 主题:节点可以消息发布到主题,也可以订阅主题以接收消息。
  • 主设备:ROS的名称服务(即帮助节点相互查找)
  • rosout:等效于stdout / stderr的ROS
  • roscore:Master + rosout +参数服务器(参数服务器将在以后介绍)

节点实际上是ROS包中的可执行文件。ROS节点使用ROS客户端库与其他节点进行通信,节点可以发布或订阅主题,也可以提供或使用服务。

ROS客户端库允许使用不同编程语言编写的节点进行通信:

  • rospy = python客户端库
  • roscpp = C ++客户端库

rosnode

先执行

roscore

打开新的终端,执行

rosnode list

将返回 rosout,说明有一个节点在运行

执行

rosnode info /rosout

将返回关于该节点的更多信息

rosrun

rosrun [package_name] [node_name]

例如

rosrun turtlesim turtlesim_node

可以打开海龟界面

加入 __name:=my_turtle 参数还可以改变节点名称,可以在 rosnode list 中查看

另外还可以执行

rosnode ping my_turtle

来查看该节点是否在运行


ROS Topic

例如,分别在三个终端中执行

roscore
rosrun turtlesim turtlesim_node
rosrun turtlesim turtle_teleop_key

可以控制海龟移动

该例程中的两个节点通过同一个主题进行通讯。一个发布按键信息,一个接受信息并控制海龟移动。

rqt_gragh

在第四个终端中执行

rqt_gragh

可以打开一个图表以展示当前的 ROS 节点状态。
将鼠标移到节点上可以看到相关节点变色。

可以看出海龟例程的主题名为 /turtle1/cmd_vel

rostopic

  • echo

    rostopic echo /turtle1/cmd_vel
    

    以获取主题中的通讯信息
    与此同时,rqt_gragh 中将出现新的节点

  • list

    rostopic list -v
    

    返回当前要发布和订阅的主题的详细列表

  • type

    rostopic type /turtle1/cmd_vel
    

    查看主题的通讯类型,此处返回 geometry_msgs/Twist

    另外还可以执行

    rosmsg show geometry_msgs/Twist
    

    查看详细信息

    或者结合使用

    rostopic type /turtle1/cmd_vel | rosmsg show
    
  • pub

    用于将信息发布到指定主题上,执行

    rostopic pub [topic] [msg_type] [args]
    

    例如

    rostopic pub -1 /turtle1/cmd_vel geometry_msgs/Twist -- '[2.0, 0.0, 0.0]' '[0.0, 0.0, 1.8]'
    

    其中 -1 使该信息只发布一条然后退出,--表明此后任何参数都不是选项,以防参数前的连字符(如复号)造成歧义

    又例如

    rostopic pub /turtle1/cmd_vel geometry_msgs/Twist -r 1 -- '[2.0, 0.0, 0.0]' '[0.0, 0.0, -1.8]'
    

    将发送稳定的命令流
    与此同时可以看到 rqt_gragh 中出现新的节点

  • hz

    执行

    rostopic hz [topic]
    

    查看信息发布的频率

rqt_plot

执行

rqt_plot

显示有关主题发布数据的滚动时间图


ROS Services and Parameters

服务是节点间沟通的另一种方式,它允许节点发出一个请求并接受回复

rosservice

  • list

    rosservice list
    

    打印提供的服务名

  • type

    rosservice type [service]
    

    返回服务类型

  • call

    rosservice call [service] [args]
    

    例如

    rosservice call /clear
    

    将清除海龟之前爬行所留下的轨迹

    执行

    rosservice type /spawn | rossrv show
    

    查看服务所需的参数,又执行

    rosservice call /spawn 2 2 0.2 ""
    

    将在指定位置创建一只新的海龟

rosparam

  • list

    rosparam list
    

    打印参数

  • set / get

    rosparam set [param_name] [value]
    rosparam get [param_name]
    

    用于设置或返回指定参数值。
    注:设置参数后需要执行 /clear 服务以应用参数

    另外也可以用

    rosparam get /
    

    获得整个服务上的参数列表

  • dump / load

    rosparam dump [file_name]
    rosparam load [file_name] [namespace]
    

    用于保存或加载参数文件


ROS 控制台

rqt_console 和 rqt_logger_level

rosrun rqt_console rqt_console
rosrun rqt_logger_level rqt_logger_level

可以打开两个控制窗口

此时重新打开 turtlesim_node 将可以看到一条消息

  • 记录器优先级

    Fatal
    Error
    Warn
    Info
    Debug
    

roslaunch

在 ROS 包内(下例在前文中所创建的包 beginner_tutorials)新建 launch 文件夹,编写文件 Launch.launch 形如

<launch>

  <group ns="turtlesim1">
    <node pkg="turtlesim" name="sim" type="turtlesim_node"/>
  </group>

  <group ns="turtlesim2">
    <node pkg="turtlesim" name="sim" type="turtlesim_node"/>
  </group>

  <node pkg="turtlesim" name="mimic" type="mimic">
    <remap from="input" to="turtlesim1/turtle1"/>
    <remap from="output" to="turtlesim2/turtle1"/>
  </node>

</launch>
  • 对以上代码的解释

    建立两个组,从而启动两个节点而不出现名称冲突
    将输入输出重定向,使第二只海龟与第一只海龟协同

再执行

roslaunch beginner_tutorials Launch.launch
rostopic pub /turtlesim1/turtle1/cmd_vel geometry_msgs/Twist -r 1 -- '[2.0, 0.0, 0.0]' '[0.0, 0.0, -1.8]'

可以看到,虽然命令仅向第一只海龟发出,第二只海龟依然同步运动

同时可以查看 rqt_gragh 中的情况


ROS Editor

rosed [package_name] [filename]

默认设置与 vim 并无不同,其他拓展选项可参阅官网


ROS msg and srv

关于消息和服务的简介与区别参考前文。

创建 msg

在 ROS 包中新建 msg 文件夹,编辑文件 Msg.msg 内容形如

string first_name
string last_name
uint8 age
uint32 score

接下来修改 CMakeLists.txt 中的部分内容如下

find_package(catkin REQUIRED COMPONENTS
   roscpp
   rospy
   std_msgs
   message_generation
)
...
catkin_package(
  ...
  CATKIN_DEPENDS message_runtime ...
  ...
)
...
add_message_files(
  FILES
  Num.msg
)
...
generate_messages(
  DEPENDENCIES
  std_msgs
)

执行

rosmsg show Msg

验证消息是否已经成功创建

创建 src

在 ROS 包中新建 srv 文件夹,执行

roscp rospy_tutorials AddTwoInts.srv srv/AddTwoInts.srv

从 ros_tutorials 中拷贝一个服务文件到 srv 文件夹中

同时再修改 CMakeLists.txt 中的部分内容如下

find_package(catkin REQUIRED COMPONENTS
   roscpp
   rospy
   std_msgs
   message_generation
)
...
catkin_package(
  ...
  CATKIN_DEPENDS message_runtime ...
  ...
)
...
add_service_files(		# 此处与msg不同
  FILES
  AddTwoInts.srv
)
...
generate_messages(
  DEPENDENCIES
  std_msgs
)

执行

rossrv show AddTwoInts

验证服务是否已成功创建
注:此处因未指定包名,将返回包括复制来源的 rospy 包中同名服务在内的两个服务

编译

确保在 package.xml 文件中包含如下

<build_depend>message_generation</build_depend>
<exec_depend>message_runtime</exec_depend>

在工作区下(该例中为 catkin_ws)执行 catkin_make,将会在 devel/include/beginner_tutorials/ 目录下创建相应的头文件(C++)


Publisher and Subscriber (C++)

Publisher

在 ROS 包内的 src 文件夹中创建 talker.cpp 源代码文件如下

#include "ros/ros.h"
#include "std_msgs/String.h"

#include <sstream>

/**
 * This tutorial demonstrates simple sending of messages over the ROS system.
 */
int main(int argc, char **argv)
{
  /**
   * The ros::init() function needs to see argc and argv so that it can perform
   * any ROS arguments and name remapping that were provided at the command line.
   * For programmatic remappings you can use a different version of init() which takes
   * remappings directly, but for most command-line programs, passing argc and argv is
   * the easiest way to do it.  The third argument to init() is the name of the node.
   *
   * You must call one of the versions of ros::init() before using any other
   * part of the ROS system.
   */
  ros::init(argc, argv, "talker");

  /**
   * NodeHandle is the main access point to communications with the ROS system.
   * The first NodeHandle constructed will fully initialize this node, and the last
   * NodeHandle destructed will close down the node.
   */
  ros::NodeHandle n;

  /**
   * The advertise() function is how you tell ROS that you want to
   * publish on a given topic name. This invokes a call to the ROS
   * master node, which keeps a registry of who is publishing and who
   * is subscribing. After this advertise() call is made, the master
   * node will notify anyone who is trying to subscribe to this topic name,
   * and they will in turn negotiate a peer-to-peer connection with this
   * node.  advertise() returns a Publisher object which allows you to
   * publish messages on that topic through a call to publish().  Once
   * all copies of the returned Publisher object are destroyed, the topic
   * will be automatically unadvertised.
   *
   * The second parameter to advertise() is the size of the message queue
   * used for publishing messages.  If messages are published more quickly
   * than we can send them, the number here specifies how many messages to
   * buffer up before throwing some away.
   */
  ros::Publisher chatter_pub = n.advertise<std_msgs::String>("chatter", 1000);

  ros::Rate loop_rate(10);

  /**
   * A count of how many messages we have sent. This is used to create
   * a unique string for each message.
   */
  int count = 0;
  while (ros::ok())
  {
    /**
     * This is a message object. You stuff it with data, and then publish it.
     */
    std_msgs::String msg;

    std::stringstream ss;
    ss << "hello world " << count;
    msg.data = ss.str();

    ROS_INFO("%s", msg.data.c_str());

    /**
     * The publish() function is how you send messages. The parameter
     * is the message object. The type of this object must agree with the type
     * given as a template parameter to the advertise<>() call, as was done
     * in the constructor above.
     */
    chatter_pub.publish(msg);

    ros::spinOnce();

    loop_rate.sleep();
    ++count;
  }

  return 0;
}

Subscriber

在 ROS 包内的 src 文件夹中创建 listener.cpp 源代码文件如下

#include "ros/ros.h"
#include "std_msgs/String.h"

/**
 * This tutorial demonstrates simple receipt of messages over the ROS system.
 */
void chatterCallback(const std_msgs::String::ConstPtr& msg)
{
  ROS_INFO("I heard: [%s]", msg->data.c_str());
}

int main(int argc, char **argv)
{
  /**
   * The ros::init() function needs to see argc and argv so that it can perform
   * any ROS arguments and name remapping that were provided at the command line.
   * For programmatic remappings you can use a different version of init() which takes
   * remappings directly, but for most command-line programs, passing argc and argv is
   * the easiest way to do it.  The third argument to init() is the name of the node.
   *
   * You must call one of the versions of ros::init() before using any other
   * part of the ROS system.
   */
  ros::init(argc, argv, "listener");

  /**
   * NodeHandle is the main access point to communications with the ROS system.
   * The first NodeHandle constructed will fully initialize this node, and the last
   * NodeHandle destructed will close down the node.
   */
  ros::NodeHandle n;

  /**
   * The subscribe() call is how you tell ROS that you want to receive messages
   * on a given topic.  This invokes a call to the ROS
   * master node, which keeps a registry of who is publishing and who
   * is subscribing.  Messages are passed to a callback function, here
   * called chatterCallback.  subscribe() returns a Subscriber object that you
   * must hold on to until you want to unsubscribe.  When all copies of the Subscriber
   * object go out of scope, this callback will automatically be unsubscribed from
   * this topic.
   *
   * The second parameter to the subscribe() function is the size of the message
   * queue.  If messages are arriving faster than they are being processed, this
   * is the number of messages that will be buffered up before beginning to throw
   * away the oldest ones.
   */
  ros::Subscriber sub = n.subscribe("chatter", 1000, chatterCallback);

  /**
   * ros::spin() will enter a loop, pumping callbacks.  With this version, all
   * callbacks will be called from within this thread (the main one).  ros::spin()
   * will exit when Ctrl-C is pressed, or the node is shutdown by the master.
   */
  ros::spin();

  return 0;
}

编译

在 CMakelists.txt 中加入如下内容

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)

在工作区下执行 catkin_make,将默认在 <workspace_name>devel/lib/<package_name> 目录下生成可执行文件

注意:如果编译出错原因来已执行的 cmake 编译文件,即使其他部分修改正确也无法刷新,此时可以在任意 CMakeList.txt 中添加无关空行使 catkin_make 重新创建编译文件

运行

先执行 roscore,然后打开新的终端进入工作区

为了让 shell 能找到 ROS 包,记得执行 source devel/setup.zsh

先后执行

rosrun beginner_tutorials talker
rosrun beginner_tutorials listener

Service and Client (C++)

Service

在 ROS 包内的 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

在 ROS 包内的 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;
}

编译

在 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)

在工作区下执行 catkin_make

运行

先执行 roscore,然后打开新的终端进入工作区

为了让 shell 能找到 ROS 包,记得执行 source devel/setup.zsh

先后执行

rosrun beginner_tutorials add_two_ints_server
rosrun beginner_tutorials add_two_ints_client 1 3

此时应该在两个终端分别看到请求和结果相关的信息


Data Bagfile

record

仍然以海龟为例,在三个终端中分别执行

roscore
rosrun turtlesim turtlesim_node
rosrun turtlesim turtle_teleop_key

在工作区下新建 bagfiles 文件夹,在文件夹内执行

rosbag record -a

持续一段时间后杀死记录进程,执行

rosbag info <your_bagfile>

打印数据包信息,或执行

rosbag play <your_bagfile>

打印所有数据信息

也可以记录数据集的子集

rosbag record -O subset /turtle1/cmd_vel /turtle1/pose

子集名称可以从数据包信息中找到

read

在工作区下新建 bin 文件夹,新建脚本文件

#!/usr/bin/python2

"""
This file is part of eRCaGuy_dotfiles: https://github.com/ElectricRCAircraftGuy/eRCaGuy_dotfiles
Author: Gabriel Staples
INSTALLATION INSTRUCTIONS:
0. Install dependencies:
        sudo apt install python-rosbag 
1. Create a symlink in ~/bin to this script so you can run it from anywhere:
        cd /path/to/here
        mkdir -p ~/bin
        ln -si "${PWD}/ros_readbagfile.py" ~/bin/gs_ros_readbagfile
2. Now you can use the `gs_ros_readbagfile` command directly anywhere you like.
References:
1. http://wiki.ros.org/rosbag/Cookbook
1. https://pypi.org/project/pyrosbag/
1. Python2 `rosbag` Code API documentation: https://docs.ros.org/api/rosbag/html/python/
- `read_messages()` API documentation: 
   https://docs.ros.org/api/rosbag/html/python/rosbag.bag.Bag-class.html#read_messages
1. http://wiki.ros.org/rospy/Overview/Time
1. https://www.geeksforgeeks.org/python-exit-commands-quit-exit-sys-exit-and-os-_exit/
Install Dependencies:
Source: https://zoomadmin.com/HowToInstall/UbuntuPackage/python-rosbag
    sudo apt install python-rosbag 
Note: as far as I can tell, rosbag runs only in Python2, not Python3 :(
Pros of this script: really easy to use; requires only 1 terminal, and NO `roscore` running.
Cons: this Python implementation runs ~13x slower than "OPTION 1", as described in 
"eRCaGuy_dotfiles/git & Linux cmds, help, tips & tricks - Gabriel.txt", so it might take up to 
1 to 2+ minutes to process an entire bag file instead of only like 5 to 10 seconds.
TODO: 
1. convert this entire Python script to a C++ program using the [C++ rosbag
API](http://wiki.ros.org/rosbag/Code%20API#cpp_api), to hopefully achieve a speed-up of ~13x
or so.
"""

import rosbag

import os
import sys

# `topics=None` means to read ALL topics; see:
# https://docs.ros.org/api/rosbag/html/python/rosbag.bag.Bag-class.html#read_messages
READ_ALL_TOPICS = None


def printHelp():
    cmd_name = os.path.basename(sys.argv[0])
    help = """
Usage: {} <mybagfile.bag> [topic1] [topic2] [topic3] [...topicN]
Reads and prints all messages published on the specified topics from the specified ROS bag file. If
no topics are specified, it will print ALL messages published on ALL topics found in the bag file.
For large bag files, on the order of 10 to 20 GB or so, expect the script to take on the order of
1 to 4 minutes or so assuming you have a fast Solid-State Drive (SSD). 
TODO: converting this script from Python to C++ could potentially speed this up by an estimated
factor of 13x or so, decreasing the processing time from a couple minutes to perhaps a dozen
seconds.
Examples: 
1. Print all messages published to the "/speed", "/vel", and "/dist" topics and stored in the 
"mybagfile.bag" ROS bag file to the screen:
    {} mybagfile.bag /speed /vel /dist
2. Same as above, except also stores the printed output into an output file, "output.txt" as well:
    {} mybagfile.bag /speed /vel /dist | tee output.txt
3. [MY FAVORITE] Same as above, except also times how long the whole process takes:
    time {} mybagfile.bag /speed /vel /dist | tee output.txt
""".format(cmd_name, cmd_name, cmd_name, cmd_name)

    print(help)


class Args:
    """
    Argument variables for the `main()` func
    """
    bag_file_in = ""
    topics_to_read = READ_ALL_TOPICS


def printArgs(args):
    print("args.bag_file_in = {}".format(args.bag_file_in))
    print("args.topics_to_read = {}".format(args.topics_to_read))


def parseArgs():
    args = Args()

    if len(sys.argv) == 1:
        print("ERROR: no input args; 1 minimum required.")
        printHelp()
        sys.exit()
    
    if len(sys.argv) >= 2:
        if sys.argv[1] == "-h" or sys.argv[1] == "--help":
            printHelp()
            sys.exit()

        args.bag_file_in = sys.argv[1] 
    
    if len(sys.argv) >= 3:
        args.topics_to_read = sys.argv[2:]

    print("Scanning ROS bag file \"{}\"".format(args.bag_file_in))
    print("for the following topics:")
    if not args.topics_to_read:
        # list is empty
        print("  ALL TOPICS in the bag file")
    else:
        for topic in args.topics_to_read:
            print("  {}".format(topic))

    print("=======================================")
    return args


def printMsgsInBagFile(args):
    no_msgs_found = True
    # Establish counters to keep track of the message number being received under each topic name
    msg_counters = {} # empty dict
    total_count = 0
    bag_in = rosbag.Bag(args.bag_file_in)
    for topic, msg, t in bag_in.read_messages(args.topics_to_read):
        total_count += 1
        no_msgs_found = False
        # Keep track of individual message counters for each message type
        if msg_counters.has_key(topic) == False:
            msg_counters[topic] = 1;
        else:
            msg_counters[topic] += 1;

        # Print topic name and message receipt info
        print("topic:           " + topic)
        print("msg #:           %u" % msg_counters[topic])
        # the comma at the end prevents the newline char being printed at the end in Python2; see:
        # https://www.geeksforgeeks.org/print-without-newline-python/
        print("timestamp (sec):"),
        print("%.9f" % t.to_sec()) 
        print("- - -")

        # Print the message
        print(msg)
        print("=======================================")

    if no_msgs_found:
        print("NO MESSAGES FOUND IN THESE TOPICS")

    print("Total messages found = {}.".format(total_count))
    ##### TODO: PRINT MESSAGE COUNT FOR EACH MSG TYPE TOO! ie: just print all key/value pairs in the 
    # `msg_counters` dict. What order to print them in? Probably just alphabetical.

    print("DONE.")


# If this file is called directly, as opposed to imported, run this:
if __name__ == '__main__':
    args = parseArgs()
    # printArgs(args) # for debugging
    printMsgsInBagFile(args)

通过执行

ros_readbagfile <mybagfile.bag> [topic1] [topic2] [topic3] [...]

可以读取信息,例如

./ros_readbagfile.py ../bagfiles/<your_bagfile> /turtle1/cmd_vel | tee topics.yaml

Debug

roswtf

将打印错误信息以供参考


新手教程

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/150992.html

(0)
飞熊的头像飞熊bm

相关推荐

发表回复

登录后才能评论
极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!