目录
前言
在对 ROS 有一定了解后,大多情况下,大家都会有一定的迷茫:
① 这一个一个的字我都看懂了,但我该怎么用他呢?
② 如果是别人开发的 ROS 程序,又该怎么使用呢?
总体步骤
主要采用三个步骤:What(做什么)、Which(用什么)、How(怎么干)
第一步:What(做什么)
自己开发的:
- 首先需要明确最终实现结果,即使无法估计全貌,也要明确一个总体开发方向。
他人开发的:
- 在获取代码后,可以看包中的 README.md 文件,开发者一般会说明程序开发目的,以及程序的使用方法;
- 当 README.md 文件中未提及任何有用信息时,可以按如下步骤启动程序:
- 若存在 launch 文件,则在包文件处于工作空间中的前提下,直接
roslaunch launch文件名
; - 若不存在 launch 文件,则查看 CMakeLists.txt 文件中的 add_executable() 项,该项括号中包含两个参数:编译生成的可执行文件名称(即节点名称),所要编译的源文件。最后在工作空间的更目录下执行
rosnode 包名 节点名
。
有几个节点,启动几个,尝试着去运行各个节点
- 若存在 launch 文件,则在包文件处于工作空间中的前提下,直接
- 当然还有一点就是读代码,这是最直接、最彻底的,当然也是最耗时的,尤其是无注释的情况下;
- 最后根据已知信息得出开发方向。
第二步:Which(用什么)
自己开发的:
- 在明确大方向后,要考虑在开发过程中会涉及到哪些数据;
- 对应的设计一个个数据结构,即每个所设计到对象的属性,及其所要用到的变量类型。
他人开发的:
-
在相关程序运行之后,通过以下方式获取节点间关系、各种服务信息:
- 运行命令:
rqt_graph
,获取节点间关系; - 运行命令:
rosnode list
,获取所有节点名称; - 运行命令:
rostopic list
,获取所有话题名称; - 运行命令:
rosservice list
,获取所有服务名称; - 运行命令:
rosparam list
,获取所有参数名称,运行命令:rosparam get 参数名称
,获取特定参数值。
- 运行命令:
-
在获取到节点名、话题名、服务名、参数名后,运行以下命令,在输出中Type项即为节点所用数据类型
- 运行命令:
rosnode info 节点名
,获取特定节点信息 - 运行命令:
rostopic info 话题名称
,获取特定话题信息 - 运行命令:
rosservice info 服务名称
,获取特定服务信息。
- 运行命令:
-
通过以下方式获取具体的数据结构:
- 运行命令:
rosmsg show 消息名称
,获取特定消息的具体数据结构信息 - 运行命令:
rossrv show 服务名称
,获取特定服务的具体数据结构信息
- 运行命令:
第三步:How(怎么干)
- 根据第二步获取到的信息,并结合第一步得出的开发方向,总结得出适宜的通信方式,代码总体结构框架,最后补全适宜的算法完成整个 ROS 程序的开发。
实例展示
- 以经典案例小乌龟的运动来完成本次实例展示。
原始小乌龟程序的运作机理
- 原始的小乌龟案例是:创建一个小乌龟节点,创建一个小乌龟手动运动控制节点,最后人为手控运动。
原始小乌龟运作涉及到的具体事项
- 运用 上面 第二步:Which(用什么) 提到的方法,获得以下信息:
- 主要存在两个节点:
/teleop_turtle
/turtlesim - 主要存在三个话题:
/turtle1/cmd_vel
/turtle1/color_sensor
/turtle1/pose - 主要存在七个服务:
/clear:清除小乌龟行走轨迹
/kill:杀死一个小乌龟
/reset:重置 /turtlesim 节点
/spawn:生成一只新的小乌龟
/turtle1/set_pen:设置小乌龟运动轨迹形态
/turtle1/teleport_absolute:设置小乌龟的绝对位姿
/turtle1/teleport_relative:设置小乌龟的相对位姿 - 主要存在三个参数:
/turtlesim/background_b
/turtlesim/background_g
/turtlesim/background_r
- 主要存在两个节点:
新小乌龟程序改进需求
- 现对这一案例进行改进,具体需求如下:
- 需求1:发布话题——小乌龟自动转圈
- 需求2:订阅话题——接收小乌龟位姿
- 需求3:发布请求——创建一个新的小乌龟
- 需求4:修改参数值——修改小乌龟所处环境的背景色
具体实现
添加依赖项
- 修改 package.xml 文件:在文件加入依赖 turtlesim
<build_depend>turtlesim</build_depend>
<exec_depend>turtlesim</exec_depend>
- 修改 CMakeLists.txt 文件:在 find_package() 中添加 turtlesim
find_package(catkin REQUIRED COMPONENTS
geometry_msgs
roscpp
rospy
std_msgs
turtlesim
)
需求1:发布话题——小乌龟自动转圈
- 创建 ROS C++文件:pub_twist.cpp
#include "ros/ros.h"
#include <geometry_msgs/Twist.h>
int main(int argc, char *argv[])
{
// 设置中文编码
setlocale(LC_ALL, "");
// 初始化 ROS 节点
ros::init(argc, argv, "turtle_twist");
// 创建节点句柄
ros::NodeHandle nh;
// 创建发布者
ros::Publisher pub = nh.advertise<geometry_msgs::Twist>("/turtle1/cmd_vel", 10);
// 设置运动速率
geometry_msgs::Twist twist;
twist.linear.x = 1.0;
// twist.linear.y = 0.0;
// twist.linear.z = 0.0;
// twist.angular.x = 0.0;
// twist.angular.y = 0.0;
twist.angular.z = 1.5;
// 设置发布评率
ros::Rate rate(10);
while(ros::ok())
{
pub.publish(twist);
// 休眠以控制频率
rate.sleep();
// ros::spinOnce();
}
return 0;
}
- 修改- 修改 CMakeLists.txt 文件:
add_executable(turtle_twist_node src/pub_twist.cpp)
target_link_libraries(turtle_twist_node
${catkin_LIBRARIES}
)
需求2:订阅话题——接收小乌龟位姿
- 创建 ROS C++文件:pub_twist.cpp
#include "ros/ros.h"
#include <turtlesim/Pose.h>
void getPose(const turtlesim::Pose::ConstPtr &pose)
{
ROS_INFO("小乌龟位姿信息:坐标 ( %.2f, %.2f ),朝向:%.2f, 线速度:%.2f,角速度:%.2f",
pose->x, pose->y, pose->theta, pose->linear_velocity, pose->angular_velocity);
}
int main(int argc, char *argv[])
{
// 设置中文编码
setlocale(LC_ALL, "");
// ros 初始化
ros::init(argc, argv, "sub_pose_node");
// ros 句柄初始化
ros::NodeHandle nh;
// 创建订阅者
ros::Subscriber sub = nh.subscribe("/turtle1/pose", 10, getPose);
// // 不断调用回调函数,保证一直订阅
// ros::spin();
// 设置订阅频率
ros::Rate rate(1);
// 开始订阅
while (ros::ok())
{
rate.sleep();
ros::spinOnce();
}
return 0;
}
- 修改- 修改 CMakeLists.txt 文件:
add_executable(sub_pose_node src/sub_pose.cpp)
target_link_libraries(sub_pose_node
${catkin_LIBRARIES}
)
需求3:发布请求——创建一个新的小乌龟
- 创建 ROS C++文件:pub_twist.cpp
#include "ros/ros.h"
#include <turtlesim/Spawn.h>
int main(int argc, char *argv[])
{
// 设置中文编码
setlocale(LC_ALL, "");
// ROS 初始化
ros::init(argc, argv, "new_turtle_node");
// ROS 句柄创建
ros::NodeHandle nh;
// 创建客户端对象
ros::ServiceClient client = nh.serviceClient<turtlesim::Spawn>("/spawn");
// 创建请求数据载体
turtlesim::Spawn spawn;
// 设置小乌龟坐标参数
spawn.request.name = "new_turtle1";
spawn.request.theta = 1.57;
spawn.request.x = 1.0;
spawn.request.y = 5.0;
// 判断服务器状态
// ros::service::waitForService("/spawn");
client.waitForExistence();
// 发送 spawn
bool flag_call = client.call(spawn);
// 处理申请姐夫哦
if(flag_call)
{
ROS_INFO("小乌龟 %s 生成成功!", spawn.response.name.c_str());
}
else
{
ROS_INFO("小乌龟生成失败!");
}
return 0;
}
- 修改- 修改 CMakeLists.txt 文件:
add_executable(new_turtle_node src/client_new_turtle.cpp)
target_link_libraries(new_turtle_node
${catkin_LIBRARIES}
)
需求4:修改参数值——修改小乌龟所处环境的背景色
- 创建 ROS C++文件:pub_twist.cpp
#include "ros/ros.h"
int main(int argc, char *argv[])
{
// 设置中文编码
setlocale(LC_ALL, "");
// ROS 初始化
ros::init(argc, argv, "bg_color_node");
// 修改背景颜色参数
// 方法一:ros::param::set
// ros::param::set("/turtlesim/background_r", 0);
// ros::param::set("/turtlesim/background_g", 255);
// ros::param::set("/turtlesim/background_b", 0);
// 方法二:ros::NodeHandle
// ROS 句柄创建
ros::NodeHandle nh("turtlesim"); // 附加命名空间,即参数主地址,之后可以简略代码
nh.setParam("background_r", 0);
nh.setParam("background_g", 0);
nh.setParam("background_b", 255);
return 0;
}
- 修改- 修改 CMakeLists.txt 文件:
add_executable(bg_color_node src/param_new_bg_color.cpp)
target_link_libraries(bg_color_node
${catkin_LIBRARIES}
)