ROS是什么
作用:提高机器人研发中心的软件服用率。
- 通信机制:松耦合分布式通信。
- 开发工具:TF坐标变换、QT工具箱、RVIZ、Gazebo。
- 应用功能:Navigation、SLAM。
- 生态系统:
ROS社区资源的组织形式
通信机制
节点与节点管理器
-
节点(Node) -------执行单元
1)执行具体任务的进程、独立运行的可执行文件;
2)不同节点可使用不同的编程语言,可分布式运行在不同的主机;
3)节点在系统中的名称必须是唯一的。 -
节点管理器(ROS Master)------控制中心
1)为节点提供命名和注册服务。
2)跟踪和记录话题/服务通信,辅助节点相互查找、建立连接。
3)提供参数服务器,节点使用此服务器存储和检索运行时的参数。
通信方法
话题通信(适用于:数据传输)
- 话题(Topic)-----异步通信机制
- 节点间用来传输数据的重要总线。
- 使用发布/订阅模型,数据由发布者传输至订阅者,同一个话题的订阅者或发布者可以不唯一。
- 消息(Message) -----话题数据
1)具有一定的类型和数据结构,包括ROS提供的标准类型和用户自定义类型;
2)使用编程语言无关的.msg文件定义,编译过程中生成对应的代码文件。
服务通信(适用于:逻辑处理)
- 服务(Service)--------同步通信机制
1)使用客户端/服务器模型,客户端发送请求数据,服务器完成处理后返回应答数据;
2)使用编程语言无关的.srv文件定义请求和应答数据结构,编译过程中生成对应的代码文件。
ROS命令行工具
- 常用命令
rostopic rosservice rosnode rosparam rosmsg rossrv rosrun
rosrun:第一个参数为功能包名,第二个参数为具体节点名。如:rosrun turtlesim turtlesim_node
话题记录rosbag record -a -O cmd_record.bag(保存运行时的数据)
话题复现rosbag play cmd_record.bag
参数
- 参数(Parameter)-----全局共享字典
1)可通过网络访问的共享、多变量字典。
2)节点使用此服务器来存储和检索运行时的参数。
3)适合存储静态、非二进制的配置参数,不适合存储动态配置的数据。
创建工作空间
工作空间相关的文件夹
- src:代码空间(Source Space)
- build:编译空间(Build Space)
- devel:开发空间(Development Space)
- install:安装空间(Install Space)
建立工作空间
- 在新建的工作空间下的src目录下:
catkin_init_workspace
- 在工作空间下:
catkin_make
- 设置环境变量:
source devel/setup.bash
- 检查环境变量:
echo $ROS_PACKAGE_PATH
- 产生install文件夹:
catkin_make install
创建功能包
同一个工作空间下,不予许存在同名功能包,不同工作空间下,允许存在同名功能包。
创建功能包:cd ~/catkin_ws/src
catkin_create_pkg test_pkg std_msgs rospy roscpp
编译功能包:cd ~/catkin_ws
catkin_make
source ~/catkin_ws/devel/setup.bash
ROS中Topic相关组成元素的实现
如何实现一个发布者:
- 初始化ROS节点;
- 向ROS Master注册节点信息,包括发布的话题名和话题中的消息类型;(初始化)
- 创建消息数据;(填充)
- 按照一定频率循环发布消息。(发布)
// 创建一个订阅者,包括msg结构体以及Topic名字
ros::Publisher pubfun_name = nodehandle.advertise<msg_name::msg>("/Topic_name", queue_number);
// ROS c++ 循环发布,发布数据
ros::Rate loop_rate(10);
loop_rate.sleep();
pubfun_name.publish(msg_name::msg);
如何实现一个订阅者:
- 初始化ROS节点;
- 订阅需要的话题;
- 循环等待话题消息,接收到消息后进入回调函数;
// 创建一个订阅者
ros::Subscriber subfun_name = nodehandle.subscribe("/Topic_name", queue_number, Callbackfun());
// 一直死锁在这个死循环,等待消息到来,有消息就调用回调函数
ros::spin();
- 在回调函数中完成消息处理。
配置CMakeLists.txt中的编译规则
- 设置需要编译的代码和生成的可执行文件;
- 设置连接库;
add_executable(node_name src/node_name.cpp)
target_link_libraries(node_name ${catkin_LIBRARIES})
设置脚本文件
每次打开中端重新设置:source devel/setup.bash
或一次性设置:在主文件夹.bashrc隐藏文件下添加source /home/ly/catkin_ws/devel/setup.bash
移植ROS系统时也会把.bash文件加入到这个文件夹下:
source /opt/ros/melodic/setup.bash
自定义话题消息
定义msg文件:msg_name.msg
在package.xml中添加功能包依赖:
<build_depend>message_generation</build_depend>
<exec_depend>message_runtime</exec_depend>
在CMakeLists.txt添加编译选项:
- find_package(… message_generation)
- add_message_file(FILES msg_name.msg)
generate_messages(DEPENDENCIES std_msgs) - catkin_package(… message_runtime)
最后会在devel/include/topic_name目录下生成一个msg_name.h的头文件
编译自定义消息的Publisher和Subscriber
- 设置需要编译的代码和生成的可执行文件;
- 设置连接库;
- 添加依赖项。(与生成的头文件相联系)
add_executable(publisher_name src/publisher_name.cpp)
target_link_libraries(publisher_name ${catkin_LIBRARIES})
add_dependencies(publisher ${PROJECT_NAME}_generate_messages_cpp)
ROS中Service相关组成元素的实现
实现一个客户端
- 初始化ROS节点;
- 创建一个Client实例;
- 发布服务请求数据;
- 等待Server处理之后的应答结果。
// 创建一个Client
ros::service::waitForService("/service_name") //阻塞型API,循环等待服务数据,这里的name是spawn
ros::ServiceClient add_turtle = node.serviceClient<turtlesim::Spawn>("/service_name"); //创建一个Client
//填充service数据
turtlesim::Spawn srv;
//请求服务调用
add_turtle.call(srv); //发送填充好的数据,等待server端的responce到来
实现一个服务端
- 初始化ROS节点;
- 创建一个Server实例,注册回调函数;
- 循环等待回调函数;
- 在回调函数中进行相关处理。
//创建一个名为/turtle_command的server,注册回调函数commandCallback
ros::ServiceServer command_service = n.advertiseService("/turtle_command", commandCallback);
// 回调函数中填充responce的内容
// 循环等待回调函数
ros::spin();
bool commandCallback(std_srvs::Trigger::Request &req, std_srvs::Trigger::Response &res)
{} //填充responce
// 循环等待回调函数
while(1)
{
ros::spinOnce();
}
客户端发布Call指令
rosservice call /turtle_command "{}" //turtle_command是发送的service的名字
服务数据的定义和使用
定义srv文件:srv_name.srv
文件中---
之前的是request数据,之后是response数据。
在package.xml中添加功能包依赖
<build_depend>message_generation</build_depend>
<exec_depend>message_runtime</exec_depend>
在CMakeLists.txt添加编译选项
- find_package(… message_generation)
- add_service_files(FILES srv_name.srv)
generate_messages(DEPENDENCIES std_msgs) - catkin_package(… message_runtime)
编译生成相应的头文件catkin_make
使用自己定义的srv配置编译规则
- 设置需要编译的代码和生成的可执行文件;
- 设置链接库;
- 添加依赖项。
add_executable(person_server src/person_server.cpp)
target_link_libraries(person_server ${catkin_LIBRARIES})
add_dependencies(person_server ${PROJECT_NAME}_gencpp)
add_executable(person_client src/person_client.cpp)
target_link_libraries(person_client ${catkin_LIBRARIES})
add_dependencies(person_client ${PROJECT_NAME}_gencpp)
机器人中的坐标变换
*参考:《机器人学导论》
TF功能包的作用
- 五秒钟之前,机器人头部坐标系相对于全局坐标系的关系是什么样的
- 机器人夹取的物体相对于机器人中心坐标系的位置在哪里
- 机器人中心坐标系相对于全局坐标系的位置在哪里
TF坐标变换实现
- 广播TF变换
- 监听TF变换
TF坐标变换实例
实现两只小海龟跟随
- 安装TF功能包:
sudo apt-get install ros-melodic-turtle-tf
- 启动launch文件:
roslaunch turtle_tf turtle_tf_demo.launch
- 启动小海龟运动键盘:
rosrun turtlesim turtle_teleop_key
- 启动坐标树界面,可以看到坐标树之间的关系:
rosrun tf view_frames
TF变换相关的命令行工具
- 查看所有的坐标树:
rosrun tf view_frames
- 查看某两个坐标树之间的关系:
rosrun tf tf_echo turtle1 turtle2
实现一个TF广播器
- 定义TF广播器;
- 创建坐标变换值;
- 发布坐标变换。
//创建tf的广播器
static tf::TransformBroadcaster br;
//初始化tf数据
tf::Transform transform;
transform.setOrigin(tf::Vector3(msg->x, msg->y, 0.0)); //初始化平移值
tf::Quaternion q;
q.setRPY(0, 0, msg->theta); //设置旋转值
transform.setRotation(q);
// 广播world与海龟坐标系之间的tf数据
br.sendTransform(tf::StampedTransform(transform, ros::Time::now(), "world", turtle_name)); // "world"坐标系与海龟之间的坐标关系
实现一个TF监听器
- 定义TF监听器;
- 查找坐标变换;
// 创建tf的监听器
tf::TransformListener listener;
//获取turtle1与turtle2坐标系之间的tf数据
tf::stampedTransform transform;
listener.waitForTransform("/turtle2", "/turtle1", ros::Time(0), ros::Duration(3.0)); //Duration为查询等待时间,超时就会出错
listener.lookupTransform("/turtle2", "/turtle1", ros::Time(0), transform); //transform为保存tf坐标之间的关系,包括平移和旋转
//发布turtle2的速度控制指令
geometry_msgs::Twist vel_msg;
vel_msg.angular.z = 4.0 * atan2(transform.getOrigin().y(), transform.getOrigin().x());
vel_msg.linear.x = 0.5 * sqrt(pow(transform.getOrigin().x(), 2) + pow(transform.getOrigin().y(), 2));
turtle_vel.publish(vel_msg);
重映射机制
同一个话题拥有两个同名的节点名字
rosrun learning_tf turtle_tf_broadcaster __name:=turtle1_tf_broadcaster /turtle1
rosrun learning_tf turtle_tf_broadcaster __name:=turtle2_tf_broadcaster /turtle2
launch文件的使用
可自动启动ROS Master
<launch>
<node pkg="turtlesim" name="sim1" type="turtlesim_node"/>
<node pkg="turtlesim" name="sim2" type="turtlesim_node"/>
</launch>
创建launch功能包
// launch文件需要依赖其他的文件,所以不需要添加依赖的库
catkin_creat_pkg learning_launch
launch
launch文件中的根元素采用标签定义
node
启动节点
- pkg:节点所在的功能包名称
- type:节点的可执行文件名称
- name:节点运行时的名称
- output、respawn、required、ns、args
name可以取代初始化时的节点名
param/rosparam
设置ROS系统运行中的参数,存储在参数服务器中。
<param name="output_frame" value="odom"/>
- name:参数名
- value:参数值
加载参数文件中的多个参数
<rosparam file="params.yaml" command="load" ns="params" />
arg
launch文件内部的局部变量,仅限于launch文件使用
- name:参数名
- value:参数值
调用:
<param name="foo" value="$(arg arg-name)" />
<node name="node" pkg="package" type="type" args="$(arg arg-name)" />
<node name="node" pkg="package" type="type" args="$(arg arg-name)" />
remap
重映射ROS计算图资源的命名,修改Topic名字
<remape from="/turtlebot/cmd_vel" to="/cmd_vel"/>
- from:原名字
- to:映射之后的命名
include
包含其他launch文件,类似C语言中的头文件包含。
<include file="$(dirname)/other.launch" />
- file:包含的其他launch文件路径
使用launch文件
roslaunch learning_launch simple.launch
launch文件实例
// 启动海龟仿真器,启动键盘节点,设置参数到Master中,将键盘输出到频幕上
<launch>
<param name="/turtle_number" value="2"/>
<node pkg="turtlesim" type="turtlesim_node" name="turtlesim_node">
<param name="turtle_name1" value="Tom"/>
<param name="turtle_name2" value="Jerry"/>
<rosparam file="$(find learning_launch)/config/param.yaml" command="load">
</node>
<node pkg="turtlesim" type="turtle_teleop_key" name="turtle_teleop_key" output="screen"/>
</launch>
// 创建两次broadcaster,使用args来进行区分,args也就是Topic名字
<launch>
<node pkg="turtlesim" type="turtlesim_node" name="sim"/>
<node pkg="turtlesim" type="turtle_teleop_key" name="teleop" output="screen"/>
<node pkg="learning_tf" type="turtle_tf_broadcaster" args="/turtle1" name="turtle1_tf_broadcaster"/>
<node pkg="learning_tf" type="turtle_tf_broadcaster" args="/turtle2" name="turtle2_tf_broadcaster"/>
</launch>
可视化工具的使用
日志输出工具:rqt_console
- 显示报错信息
计算图可视化工具:rqt_graph
数据绘图工具:rqt_plot
- 订阅相关的数据并绘制曲线图,比如某个Topic话题/turtle1/pose
图像渲染工具:rqt_image_view
- 显示摄像头图像信息
综合工具:rqt
- 可以打开所有其他的工具
机器人开发过程中的数据可视化界面:Rviz
rosrun rviz rviz
三维物理仿真平台:Gazebo
- 测试机器人算法
- 机器人的设计
- 现实情景下的回溯测试
roslaunch gazebo_ros willowgarage_world.launch