1.rosrun package-name executable-name 比如 rosrun turtlesim turtlesim_node
2.一旦启动roscore后,便可以运行ROS程序了。ROS程序的运行实例被称为节点(node),roscore叫做节点管理器
3.查看节点列表rosnode list
4.需要注意节点名并不一定与对应可执行文件名称相同
5.可以使用 rosrun 命令显式设置节点的名称rosrun package-name executable-name __name:=node-name这种方法将使用 node-name 参数给出的名称覆盖节点的默
认名。
6.查看节点信息rosnode info node-name 终止节点 rosnode kill node-name
7.用 Ctrl-C 命令终止节点。但使用这种方法时可能不会在节点管理器中注销该节点,因此会导致已终止的节点仍然在 rosnode 列表中。这虽然没有什么坏处,但可能会让用户对当前系统的行为感到困扰。此时可以使用下面的命令将节点从列表中删除:rosnode cleanup
8.ROS节点之间进行通信所利用的最重要的机制就是消息传递。在ROS中,消息有组织地存放在话题里。消息传递的理念是:当一个节点想要分享信息时,它就会发布(publish)消息到对应的一个或者多个话题;当一个节点想要接收信息时,它就会订阅(subscribe)它所需要的一个或者多个话题。ROS节点管理器负责确保发布节点和订阅节点能找到对方;而且消息是直接地从发布节点传递到订阅节点,中间并不经过节点管理器转交
9.在 ROS 系统中查看节点之间的发布-订阅关系的最简单方式就是在终端输入如下命令:rqt_graph
10.所有的节点发布都向话题/rosout 发布消息,该话题由同名的/rosout 节点订阅。这个话题的作用是用来生成各个节点的文本日志消息。
11.ROS 节点通常设计成了只管发布它们有用的信息,而不需要担心是否有其他节点来订阅这些消息。这样有助于减少各个节点之间的耦合度。
12.获得话题列表 rostopic list这个列表列举的话题和 rqt_graph 中展示的话题应该是一样的。
13.打印消息内容 rostopic echo topic-name
14.测量发布频率rostopic hz topic-name,带宽rostopic bw topic-name
15.查看话题rostopic info topic-name,可以获得消息类型等信息
16.查看消息类型rosmsg show message-type-name
17.用命令发布消息rostopic pub –r rate-in-hz topic-name message-type message-content,如rostopic pub –r 1 /turtle1/cmd_vel geometry_msgs/Twist ’[2,0,0]’ ’[0,0,0]’
18.问题检查:roswtf
19.创建工作区caktin_ws并创建src子目录用于存放功能包代码,mkdir -p ~/catkin_ws/src
20.src目录下创建功能包catkin_create_pkg package-name,会产生两个文件package.xml和CMakeLists.txt
21.头文件 ros/ros.h 包含了标准 ROS 类的声明,你将会在每一个你写的 ROS 程序中包含它。下面是一个ros helloworld程序
// This is a ROS version of the standard "hello , world"
// program.
// This header defines the standard ROS classes .
#include <ros / ros.h>
int main ( int argc , char ** argv ) {
// Initialize the ROS system .
ros::init ( argc , argv , " hello _ros " ) ;
// Establ ish this program as a ROS node .
ros::NodeHandle nh ;
// Send some output as a log message .
ROS_INFO_STREAM( " Hello , ␣ ROS! " ) ;
}
22.编译hello程序
(1)声明依赖库
在CmakeList.txt中修改 find_package(catkin REQUIRED COMPONENTS package-names)
在package.xml中修改package-name,package-name例如这里的package-name应该是roscpp
(2)声明可执行文件
在CmakeList.txt中add_executable(executable-name source-files),target_link_libraries(executable-name ${catkin_LIBRARIES})
(3)编译工作区catkin_make
(4)Sourcing setup.bash source devel/setup.bash
23.执行hello程序,rosrun 包名 可执行文件名
编写一个发布者程序
#include <ros/ros.h>
#include <geometry_msgs/Twist.h> // For geometry_msgs:: Twist
#include <stdlib.h> // For rand() and RAND_MAXint main (int argc, char** argv) {// Initialize the ROS system and become a node .ros::init(argc, argv, "publish_velocity");ros::NodeHandle nh;// Create a publisher obj ect .ros::Publisher pub = nh.advertise<geometry_msgs::Twist>("turtle1/cmd_vel", 1000) ;// Seed the random number generator .srand(time(0));// Loop at 2Hz until the node is shut down.ros::Rate rate(2);while(ros::ok()) {// Create and fill in the message. The other four// fields, which are ignored by turtlesim, default to 0.geometry_msgs::Twist msg;msg.linear.x = double(rand()) / double(RAND_MAX);msg.angular.z = 2 * double(rand()) / double(RAND_MAX) - 1;// Publish the message .pub.publish(msg);// Send a message to rosout with the details .ROS_INFO_STREAM("Sending random velocity command : "<<" linear=" << msg.linear.x<< " angular=" << msg.angular.z);// Wait untilit's time for another iteration .rate.sleep();}
}
上面程序用来给turtlesim仿真器中的海龟发布随机生成的指令,在添加完依赖后,执行结果如下图
编写一个订阅者程序
我们继续使用 turtlesim 作为测试平台,订阅 turtlesim_node发布的/turtle1/pose 话题。这一话题的消息描述了海龟的位姿(位置和朝向)。
这里有三点需要注意:
1)编写回调函数
发布和订阅消息的一个重要的区别是订阅者节点无法知道消息什么时候到达。为了应对这一事实,我们必须把响应收到消息事件的代码放到回调函数里,ROS 每接收到一个新的消息将调用一次这个函数。订阅者的回调函数类似于:
void function_name(const package_name::type_name &msg)
{
}
其中参数 package_name 和 type_name 和发布消息时的相同,它们指明了我们想订阅的话题的消息类。回调函数的主体有权限访问接收到消息的所有域,并以它认为合适的方式存储、使用或丢弃接收到的数据。与往常一样,我们必须包含定义该类的头文件。
2)创建订阅者对象
为了订阅一个话题,我们需要创建一个ros::Subscriber对象 :
ros::Subscriber sub = node_handle.subscribe(topic_name,queue_size, pointer_to_callback_function);
这个构造函数有三个形参,其中大部分与 ros::Publisher 声明中的类似,最后一个参数是回调函数的指针
3)给ROS控制权
最后的复杂之处在于只有当我们明确给ROS许可时,它才会执行我们的回调函数 。实际上有两个略微不同的方式来做到这一点,其中一个版本如下所示:
ros::spinOnce();
这个代码要求 ROS 去执行所有挂起的回调函数,然后将控制权限返回给我们。另一个方法如下所示:
ros::spin();
这个方法要求 ROS 等待并且执行回调函数,直到这个节点关机。换句话说,ros::spin()大体等于这样一个循环:
while(ros::ok( ))
{
ros::spinOnce();
}
使用 ros::spinOnce()还是使用 ros::spin()的建议如下:你的程序除了响应回调函数,还有其他重复性工作要做吗?如果答案是“否”,那么使用 ros::spin();否则,合理的选择是写一个循环,做其他需要做的事情,并且周期性地调用 ros::spinOnce()来处理回调。
订阅者代码
// This program subscribes to turtle1/pose and shows its
// messages on the screen .
#include <ros/ros.h>
#include <std_msgs/String.h>
#include <turtlesim/Pose.h>
#include <iomanip> // for std::setprecision and std::fixed// A callback function . Executed each time a new pose
// message arrives .
void poseMessageReceived ( const turtlesim::Pose& msg ) {ROS_INFO_STREAM( std::setprecision(2) << std::fixed << " position =(" << msg.x << " , " << msg.y << " ) "<< " *direction=" << msg.theta) ;
}
int main(int argc, char** argv) {// Initialize the ROS system and become a node .ros::init(argc, argv,"subscribe_to_pose");ros::NodeHandle nh;// Create a subscri ber obj ect .ros::Subscriber sub = nh.subscribe("turtle1/pose", 1000, &poseMessageReceived);// Let ROS take over.ros::spin();
}
注意在CmakeList.txt添加turtlesim依赖后还会出现找不到turtlesim/Pose.h的情况,这时看看CmakeList中build中的include_directories块有没有被注释掉,如果注释掉就要打开
试验结果:
左边是订阅者收到的消息,右边是随机发送的指令
---
24.通过 rosparam get /run_id 查看 run_id通过runid来查看日志消息
25.清除日志rosclean check ,rosclean purge
26.roslanch启动多个节点的。其基本思想是在一个XML格式的文件内将需要同时启动的一组节点罗列出来
一个launch文件例子
<launch>
<node name="turtlesim_node" pkg="turtlesim" type="turtlesim_node" ns="sim1" respawn="true" />
<node pkg="learn_ros" type="sub" name="sub_pose" output="screen" />
<node pkg="learn_ros" type="pub" required="true" launch-prefix="xterm -e" ns="sim1" name="pub"/><node name="turtlesim_node" pkg="turtlesim" type="turtlesim_node" ns="sim2" respawn="true" />
<node pkg="turtlesim" type="turtle_teleop_key" required="true" launch-prefix="xterm -e" ns="sim2" name="pub2"/></launch>
说明:respawn参数为真代表如果节点崩了过一会会自动重启节点
output="screen"将结果输出到屏幕
type的参数是可执行的文件名
pkg的参数是功能包名
required为真代表如果这个节点崩了,那么整个launch结束
launch-prefix="xterm -e"表示新开个终端显示数据
ns是命名空间,用于分开控制两只乌龟
上面launch执行后的结果如下:
launch中的重映射
重映射是基于替换的思想:每个重映射包含一个原始名称和一个新名称。每当节点使用重映射中的原始名称时,ROS客户端库就会将它默默地替换成其对应的新名称。
<remap from="turtle1 /cmd_vel" to="turtle1 /cmd_vel_reversed" />
这样原来订阅turtle1 /cmd_vel的节点就会订阅turtle1 /cmd_vel_reversed的消息了
下面是一个包含其他launch文件的示例
<launch>
<include file ="$(find learn_ros)/doublesim.launch" />
<arg name="use_sim3" default="0" /><group ns="sim3" if="$(arg use_sim3)" >
<node name="turtlesim_node" pkg="turtlesim " type="turtlesim_node" />
<node pkg="turtlesim " type="turtle_teleop_key" name="teleop_key" required="true " launch-prefix="xterm -e"/>
</group></launch>
其中use_sim3是参数,可以通过roslaunch learn_ros example.launch use_sim3:=1 来赋值
group可以将一些节点分组到同一个命名空间 sim3
用来查找learn_ros功能包中的doublesim文件,并添加进来