ROS学习笔记

目录

1 创建、编译和运行

1.1 创建程序包

1.2 编译

1.3 运行

2 ROS话题

2.1 rqt_graph

2.2 rostopic

2.3 rqt_plot

3 ROS服务和参数

3.1 rosservice call

3.2 rosparam

4 rqt_console、roslaunch和rosed

4.1 rqt_console

4.2 roslaunch

4.3 rosed

5 创建ROS消息和ROS服务

5.1 ROS消息(msg)

5.2 ROS服务(srv)

5.3 msg和srv都需要的步骤

6 c++消息发布器和订阅器代码解析

6.1 发布器代码

6.2 订阅器代码

6.3 编译发布器和订阅器

7 c++服务端和客户端代码解析

7.1 服务端代码

7.2 客户端代码


1 创建、编译和运行

1.1 创建程序包

$ cd ~/catkin_ws/src

# catkin_create_pkg <package_name> [depend1] [depend2] [depend3]

例子:

$ catkin_create_pkg beginner_tutorials std_msgs rospy roscpp

1.2 编译

# catkin_make [make_targets] [-DCMAKE_VARIABLES=...]

1.3 运行

$ roscore

新开一个终端:

# rosrun [package_name] [node_name]

包名+节点名 可在CMakeLists.txt文件中找到

 

2 ROS话题

两个节点间通过话题进行通信。在一个节点发布信息,然后另一个节点订阅该话题接受信息。

2.1 rqt_graph

rqt_graph能够创建一个显示当前系统运行情况的动态图形。即看清楚看出两个节点之间的通信。

$ rosrun rqt_graph rqt_graph

2.2 rostopic

$ rostopic -h
rostopic bw     display bandwidth used by topic
rostopic echo   可以显示在某个话题上发布的数据。
rostopic hz     可以用来查看数据发布的频率。
rostopic list   能够列出所有当前订阅和发布的话题。
rostopic pub    可以把数据发布到当前某个正在广播的话题上。
rostopic type   用来查看所发布话题的消息类型。

rostopic pub用法:

# rostopic pub [topic] [msg_type] [args]

[topic] 话题名称

[msg_type] 消息类型,可以用命令 rostopic type 获得

[args] 需要发布的参数 可以用命令 rosmsg show [topic] 获得需要输入的参数类型

例子:

$ rostopic type /turtle1/command_velocity
$ rosmsg show turtlesim/Velocity
$ rostopic pub -1 /turtle1/command_velocity turtlesim/Velocity  -- 2.0  1.8

注:-1 (单个破折号)这个参数选项使rostopic发布一条消息后马上退出。

   --  (双破折号)这会告诉命令选项解析器接下来的参数部分都不是命令选项。这在参数里面包含有破折号-(比如负号)时是必须要添加的。

2.3 rqt_plot

rqt_plot命令可以实时显示一个发布到某个话题上的数据变化图形。

$ rosrun rqt_plot rqt_plot

 

3 ROS服务和参数

服务(services)是节点之间通讯的另一种方式。服务允许节点发送请求(request) 并获得一个响应(response)

rosservice list         输出可用服务的信息
rosservice call         调用带参数的服务
rosservice type         输出服务类型
rosservice find         依据类型寻找服务find services by service type
rosservice uri          输出服务的ROSRPC uri

3.1 rosservice call

# rosservice call [service] [args]

args通过以下命令获取:

$ rosservice type [service]| rossrv show

3.2 rosparam

rosparam使得我们能够存储并操作ROS 参数服务器(Parameter Server)上的数据。参数服务器能够存储整型、浮点、布尔、字符串、字典和列表等数据类型。rosparam使用YAML标记语言的语法。一般而言,YAML的表述很自然:1 是整型, 1.0是浮点型, one是字符串, true是布尔, [1, 2, 3]是整型列表, {a: b, c: d}是字典. rosparam有很多指令可以用来操作参数。

rosparam set            设置参数
rosparam get            获取参数
rosparam load           从文件读取参数
rosparam dump           向文件中写入参数
rosparam delete         删除参数
rosparam list           列出参数名

Usage:

rosparam set [param_name]
rosparam get [param_name]
rosparam dump [file_name]
rosparam load [file_name] [namespace]
 

可以使用rosparam get /来显示参数服务器上的所有内容:

$ rosparam get /

将所有的参数写入params.yaml文件:

$ rosparam dump params.yaml

 

4 rqt_console、roslaunch和rosed

4.1 rqt_console

rqt_console属于ROS日志框架(logging framework)的一部分,用来显示节点的输出信息。rqt_logger_level允许我们修改节点运行时输出信息的日志等级(logger levels)(包括 DEBUG、WARN、INFO和ERROR)。

$ rosrun rqt_console rqt_console
$ rosrun rqt_logger_level rqt_logger_level

 

4.2 roslaunch

roslaunch可以用来启动定义在launch文件中的多个节点。

$ roslaunch [package] [filename.launch]

例子:

   1 <launch>
在这里我们创建了两个节点分组并以'命名空间(namespace)'标签来区分,其中一个名为turtulesim1,另一个名为turtlesim2,两个组里面都使用相同的turtlesim节点并命名为'sim'。这样可以让我们同时启动两个turtlesim模拟器而不会产生命名冲突。

   3   <group ns="turtlesim1">
   4     <node pkg="turtlesim" name="sim" type="turtlesim_node"/>
   5   </group>
   6 
   7   <group ns="turtlesim2">
   8     <node pkg="turtlesim" name="sim" type="turtlesim_node"/>
   9   </group>
在这里我们启动模仿节点,并将所有话题的输入和输出分别重命名为turtlesim1和turtlesim2,这样就会使turtlesim2模仿turtlesim1。

  16 </launch>

 

4.3 rosed

rosed 是 rosbash 的一部分。利用它可以直接通过package名来获取到待编辑的文件而无需指定该文件的存储路径了。

$ rosed [package_name] [filename]

rosed默认的编辑器是vim。如果想要将其他的编辑器设置成默认的,你需要修改你的 ~/.bashrc 文件。

 

5 创建ROS消息和ROS服务

  1. 消息(msg): msg文件就是一个描述ROS中所使用消息类型的简单文本。它们会被用来生成不同语言的源代码。
  2. 服务(srv): 一个srv文件描述一项服务。它包含两个部分:请求和响应。

msg文件存放在packagemsg目录下,srv文件则存放在srv目录下。

5.1 ROS消息(msg)

msg文件实际上就是每行声明一个数据类型和变量名。

可以使用的数据类型如下:

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

创建一个msg:

$ cd ~/catkin_ws/src/beginner_tutorials

$ mkdir msg

$ echo "int64 num" > msg/Num.msg

更复杂的消息:

Header header

  string child_frame_id

  geometry_msgs/PoseWithCovariance pose

geometry_msgs/TwistWithCovariance twist

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

 

接下来,还有关键的一步:我们要确保msg文件被转换成为C++,Python和其他语言的源代码。查看package.xml, 确保它包含一下两条语句: 

 <build_depend>message_generation</build_depend>

  <run_depend>message_runtime</run_depend>

注:在构建的时候,我们只需要"message_generation"。然而,在运行的时候,我们只需要"message_runtime"。

在 CMakeLists.txt文件中,利用find_packag函数,增加对message_generation的依赖,这样就可以生成消息了。 你可以直接在COMPONENTS的列表里增加message_generation,就像这样:

find_package(catkin REQUIRED COMPONENTS roscpp rospy std_msgs message_generation)

设置运行依赖:

catkin_package(

    ...

    CATKIN_DEPENDS message_runtime ...

...)

添加message文件:

add_message_files(

  FILES

  Num.msg

)

手动添加.msg文件后,我们要确保CMake知道在什么时候重新配置我们的project。 确保添加了如下代码:

generate_messages()

以上就是你创建消息的所有步骤。下面通过rosmsg show命令,检查ROS是否能够识消息。

$ rosmsg show [message type]

 

5.2 ROS服务(srv)

在刚刚那个package中创建一个服务:

$ roscd beginner_tutorials

$ mkdir srv

srv文件分为请求和响应两部分,由'---'分隔。下面是srv的一个样例:

int64 A

int64 B

---

int64 Sum

也可以从其他的package中复制一个服务。

$ roscp [package_name] [file_to_copy_path] [copy_path]

下面步骤和msg步骤类似:

# Do not just add this line to your CMakeLists.txt, modify the existing line

find_package(catkin REQUIRED COMPONENTS

  roscpp

  rospy

  std_msgs

message_generation)

add_service_files(

  FILES

  AddTwoInts.srv

)

下面通过rosmsg show命令,检查ROS是否能够识该服务。

$ rossrv show <service type>

5.3 msg和srv都需要的步骤

去掉注释并附加上所有你消息文件所依赖的那些含有.msg文件的package:

generate_messages(

  DEPENDENCIES

  std_msgs

)

 

6 c++消息发布器和订阅器代码解析

6.1 发布器代码

#include "ros/ros.h"

#include "std_msgs/String.h"



#include <sstream>



int main(int argc, char **argv)

{

  ros::init(argc, argv, "talker");



  ros::NodeHandle n;



  /**

   将要在 chatter(话题名) 上发布 std_msgs/String 消息类型的消息。

第二个参数是发布序列的大小。1000表示最多存储1000个数据,多了,就会丢弃先前发布的数据

NodeHandle::advertise() 返回一个 ros::Publisher 对象,它有两个作用: 1) 它有一个 publish() 成员函数可以让你在topic上发布消息; 2) 如果消息类型不对,它会拒绝发布。

   */

  ros::Publisher chatter_pub = n.advertise<std_msgs::String>("chatter", 1000);



/**

   指定自循环的频率 10Hz

   */

  ros::Rate loop_rate(10);



  int count = 0;



/**

如果下列条件之一发生,ros::ok() 返回false:



SIGINT 被触发 (Ctrl-C)

被另一同名节点踢出 ROS 网络

ros::shutdown() 被程序的另一部分调用

节点中的所有 ros::NodeHandles 都已经被销毁

   */

  while (ros::ok())

  {

    std_msgs::String msg;



    std::stringstream ss;

    ss << "hello world " << count;

    msg.data = ss.str();



/**

     ROS_INFO 和其他类似的函数可以用来代替 printf/cout 等函数。

     */

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



    chatter_pub.publish(msg);



/**如果你的程序里包含其他回调函数,最好在这里加上 ros::spinOnce()这一语句,否则你的回调函数就永远也不会被调用了。此例子中不需要…

*/

    ros::spinOnce();



//调用 ros::Rate 对象来休眠一段时间以使得发布频率为 10Hz。

    loop_rate.sleep();

    ++count;

  }



  return 0;

}

6.2 订阅器代码

#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() 进入自循环,可以尽可能快的调用消息回调函数。如果没有消息到达,它不会占用很多 CPU,所以不用担心。一旦 ros::ok() 返回 false,ros::spin() 就会立刻跳出自循环。这有可能是 ros::shutdown() 被调用,或者是用户按下了 Ctrl-C,使得 master 告诉节点要终止运行。也有可能是节点被人为关闭的。   */

  ros::spin();



  return 0;

}

 

6.3 编译发布器和订阅器

修改CMakeLists.txt:

cmake_minimum_required(VERSION 2.8.3)

project(beginner_tutorials)



## Find catkin and any catkin packages

find_package(catkin REQUIRED COMPONENTS roscpp rospy std_msgs genmsg)



## Declare ROS messages and services

add_message_files(FILES Num.msg)

add_service_files(FILES AddTwoInts.srv)



## Generate added messages and services

generate_messages(DEPENDENCIES std_msgs)



## Declare a catkin package

catkin_package()



## Build talker and listener

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)

编译:

$ catkin_make 

 

7 c++服务端和客户端代码解析

7.1 服务端代码

#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;

}

 

7.2 客户端代码

#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;

//传入请求消息

/** C标准库了提供了 atoi, atof, atol, atoll(C++11标准) 函数将字符串转换成int,double, long, long  long 型。*/

  srv.request.a = atoll(argv[1]);

  srv.request.b = atoll(argv[2]);



//call发送请求并获取响应

  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;

}

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值