ROS 快速入门教程–机器人工匠阿杰
11. 年轻人的第一个node节点
cd ~/catkin_ws/src ; // 进入工作空间
catkin_create_p kg ssr_pkg rospy roscpp std_msgs ; // 创建一个名为ssr_pkg的工程,依赖包是:rospy roscpp std_msgs
// 此时,利用code指令进入vscode,打开工作空间目录下的ssr_pkg
// 再src下面的目录下,新建一个cpp文件,chao_node.cpp
chao_node.cpp:
#include<ros/ros.h>
int main(int argc, char const *argv[]){
printf("hello, world");
return 0;
}
// 注意这时候可能include的文件标红,这时候只需要删除掉.vscode下面的c_cpp_properties.json文件,然后重新打开vscode即可。
// 接下来,打开CMakeList.txt文件(注意这里用的注释格式)
// 找到下面的注释文件中的"build"栏目中一行
add executable(${name}_node src/ssr_pkg_node.cpp) // 后面表示地址和文件名
// 前面是节点名称
add executable(chao_nodes src/chao_node.cpp)
// 注意 每一次修改文件以后,都一定要记得保存
// 然后是ctrl+shift+B来编译。
步骤二:
// 打开新的终端
roscore;
// 配置环境空间
source ~/catkin_ws/devel/setup.bash;
// 运行超声波传感器节点
rosrun ssr_pkg chao_node
步骤三:
// 在主函数中加入ros:init()
// 构建while循环,循环条件为ros:ok(); ,这样可以直接ctrl + c推出。
// 在cmake文件中找到设置节点源码的编译规则,"build"的最后面
target_link_libraries(chao_node
${catkin_LIBRIES}
)
12 Topic话题和Message消息
Topic: 持续通讯的一种形式
Message: 通讯过程中发送的消息。
Publisher: 消息的发送方
Subscriber: 消息的接收方。
注意:一个话题里面一般不会发布多条信息,那样容易让接收者混乱。
所以比如另外有一个传感器也要发布关于姿态信息,那它就必须新建一个Topic,然后在这个Topic中发布message,作为接收者来说,就可以选择性的接受来自Topic的话题。
13. Publisher发布者和代码实现
注意:以上问题,rostopic话题不能是中文的。
// chao_node的代码
#include<ros/ros.h>
#include<std_msgs/String.h>
int main(int argc, char *argv[])
{
ros::init(argc, argv, "chao_node");
/* code */
ros::NodeHandle nh;
// 注意:话题名称
ros::Publisher pub = nh.advertise<std_msgs::String>("go_car_kai_hei", 10); // first : message. seconde : queue
ros::Rate loop_rate(10); // 设置频率。一秒钟发送十次。
while(ros::ok()){
printf("我要发布消息了!\n");
std_msgs::String msg;
msg.data = "超声波数据";
pub.publish(msg);
loop_rate.sleep(); // 实现延迟阻塞
}
return 0;
}
rostopic list : 列出系统中活跃的话题
rostopic echo + 主题名称:显示指定话题中发送的信息
rostopic hz + 主题名称:统计指定话题中消息发送频率
同理,复制节点,命名为yao_node.cpp
14. 在ros中,使用c++编写subcriber
#include<ros/ros.h>
#include<std_msgs/String.h>
void chao_callback(std_msgs::String msg){ // 这个接受回溯函数用来处理接受到的信息
ROS_INFO(msg.data.c_str()); // 带时间戳的信息
}
int main(int argc, char *argv[])
{
setlocale(LC_ALL, ""); // ""代表跟随系统文字,可以正常输出中文
/* code */
ros::init(argc, argv, "ma_node");
ros::NodeHandle nh;
ros::Subscriber sub = nh.subscribe("go_car_kai_hei", 10, chao_callback); // 注意:""这里的是对应要接受的topic名称。
while(ros::ok()){
ros::spinOnce(); // 这个函数为了让系统把注意力放在接受信息上。
}
return 0;
}
// 对应的编译CMake文件:结尾处加入这个
add_executable(ma_node src/ma_node.cpp)
target_link_libraries(ma_node
${catkin_LIBRARIES}
)
一个工具:rqt_graph 一个查看节点关系的工具。
15. ROS中,使用launch文件一次性启动多个节点
在上一接中,我们如果要实现接收者接收到多个发布者的信息,就需要打开多个窗口来分别运行,这样比较麻烦,于是launch文件运用而生。只需要用标记语言来对多个节点进行标记,就可以实现一次性运行。
接下来,我们来实践操作一下
- 首先,在pkg文件下,新建一个launch文件夹,然后在这个文件夹下新建一个kai_hei.launch文件。然后编辑如下:
<launch>
<node pkg="ssr_pkg" type="chao_node" name="chao_node" launch-prefix="gnome-terminal -e"/>
<node pkg="ssr_pkg" type="yao_node" name="yao_node"/>
<node pkg="atr_pkg" type="ma_node" name="ma_node" output="screen"/>
</launch>
19. 在ROS中,用C++实现机器人的运动控制
// 1 首先新建一个速度发布节点
cd catkin_ws/src/
catkin_create_pkg vel_pkg roscpp rospy geometry_msgs
// 2 创建一个速度节点 vel_node.cpp
#include<ros/ros.h>
#include<geometry_msgs/Twist.h>
int main(int argc, char *argv[])
{
/* code */
// 首先是ros初始化,节点命名
ros::init(argc, argv, "vel_node");
// 引入一个ros管家
ros::NodeHandle n;
ros::Publisher vel_pub = n.advertise<geometry_msgs::Twist>("/cmd_vel", 10);
// 新建一个变量来存储数据
geometry_msgs::Twist vel_msg;
// Twish 有两个变量:速度、角速度
vel_msg.linear.x = 0.1; // x轴方向的速度
vel_msg.linear.y = 0;
vel_msg.linear.z = 0;
vel_msg.angular.x = 0; // x轴方向的角速度
vel_msg.angular.y = 0;
vel_msg.angular.z = 0;
// 通过while循环来实现循环播报
ros::Rate r(30);
while(ros::ok()){
vel_pub.publish(vel_msg);
r.sleep();
}
return 0;
}
// 对应的编译文件修改一下
# catkin_add_nosetests(test)
add_executable(vel_node srcel_node.cpp)
add_dependencies(vel_node ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS})
target_link_libraries(vel_node
${catkin_LIBRARIES}
)
22. ROS中,使用RViz观测传感器数据
可以使用rviz进行添加模型,然后添加观测机器人的传感器,在左侧的状态栏可以修改传感器的一些参数。
如果要保存rviz的配置,直接file–save as保存为.rviz文件即可,下一次直接打开。
在这个模型里面,可以通过:
roslaunch wpr_simulation wpb_rviz.launch来实现配置好的rviz界面
23 ROS系统中激光雷达的消息包
在实际ros项目中,激光雷达的数据如下:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LJe5mJws-1687785842657)(C:\Users\风净尘\Desktop\QQ图片20230311111300.jpg)]
range是每一个方向的障碍物距离,有360个角度线。 如果超出了范围,就是INF表示无穷大。
24. 用C++实现获取激光雷达数据的接收器
首先继续按照之前的方式创建一个pkg,然后创建lidar_node.cpp文件如下:
#include<ros/ros.h>
#include<sensor_msgs/LaserScan.h>
//回调函数
void lidar_callback(sensor_msgs::LaserScan msg){
float fMidDist = msg.ranges[180]; // 这里指向的是正前方,从6点钟方向来算0度。
ROS_INFO("前方测距 range[180] = %f 米", fMidDist);
}
int main(int argc, char *argv[])
{
// 初始化
setlocale(LC_ALL, ""); // 设置全局语言跟随系统
ros::init(argc, argv, "lidar_node"); // 节点名字
// 引入管家
ros::NodeHandle nh;
// 创建接受者
ros::Subscriber lidar_sub = nh.subscribe("/scan", 10, lidar_callback);
ros::spin(); // 让系统监视这个信息
return 0;
}
28. IMU惯性测量单元
注意区别,这里的是线性加速度x,y,z轴。
orientation——covariance:协方差矩阵