ros模块化设计理念
单一节点完成简单的功能
包和节点
包 pkg
ros1 使用cmake构建
节点 node
年轻人的第一个node和pkg
在 ~/catkin_ws/src/
目录下 输入
catkin_create_pkg ssr_pkg rospy roscpp std_msgs
注解
- ssr_pkg 包名
- rospy roscpp std_msgs 依赖项
- rospy roscpp 貌似是ros的 py和cpp相关
- std_msgs 是ros的标准信息库
执行完 后的文件目录效果如下:
注解:
- package.xml : 有一个文件有这个东西极有可能是ros的包
内容大概呈现成这样
创建一个超声波节点
在 ssr_pkg/src
下
创建一个 chao_node.cpp
内容如下:
创建代码
#include <ros/ros.h>
int main(int args,char const *args[])
{
printf("Hello World!\n");
return 0;
}
编写cmake文件
CmakeLists.txt文件中
- ## 双#号是告诉你是什么东西
- # 单#号是让你方便拷贝的
编译相关
在末尾插入
- 原注释
#add_executable(${PROJECT_NAME}_node src/ssr_pkg_node.cpp)
- 修改后
add_executable(chao_node src/chao_node.cpp)
${PROJECT_NAME}_node:——–>是编译后的文件名称
src/ssr_pkg_node.cpp:—–>是源文件的位置
链接库
- 源注释
# target_link_libraries(${PROJECT_NAME}_node
# ${catkin_LIBRARIES}
# )
- 改为
target_link_libraries(chao_node
${catkin_LIBRARIES}
)
启动节点
启动 ros
roscore
启动我们编写的节点
rosrun ssr_pkg chao_node
踩坑
当 vscode 添加了ros的插件后 ,如果找不到ros的依赖库
可以直接删除c++本身的配置
c_cpp_properties.json
ros插件会自动帮你加载环境
总结
创建 ros 节点的大概过程
消息发布与订阅
创建两个发布者发布两个消息
实现这样的结构
chao_node.cpp
#include <ros/ros.h>
#include <std_msgs/String.h>
int main(int argc, char *argv[])
{
ros::init(argc,argv,"chao_node");
printf("Hello World!\n");
// add topic
ros::NodeHandle nh; // nh means node_hander
ros::Publisher pub = nh.advertise<std_msgs::String>("game_topic",10); // publisher,10 buffers
ros::Rate loop_rate(10); // 1s exc 10
while(ros::ok())
{
printf("Don't shorw \n");
std_msgs::String msg;
msg.data = "I'm no.1 !come on!";
pub.publish(msg);
}
return 0;
}
python实现方式,
catkin_create
pkg_name
rospy
std_msgs
- li_node.py
#!/usr/bin/env python3
# coding=utf-8
import rospy
from std_msgs.msg import String
def main():
rospy.init_node("li_node")
rospy.logwarn("Hello ROS1")
pub = rospy.Publisher("learn_topic", String, queue_size=10)
rate = rospy.Rate(10) # 10 hz
while not rospy.is_shutdown():
rospy.loginfo("Let's Learn ROS")
msg = String()
msg.data = "I want learn ROS1"
pub.publish(msg)
rate.sleep()
if __name__ == "__main__":
main()
py的文件一般放在 scripts
文件夹下
不需要写CmakeLists.txt文件
创建完的文件要赋予执行权限,
chmod +x xxx_node.py
运行
rosrun ssr_pkg li_node.py
yao_node.cpp
#include <ros/ros.h>
#include <std_msgs/String.h>
int main(int argc, char *argv[])
{
ros::init(argc,argv,"yao_node");
printf("Hello World!\n");
// add topic
ros::NodeHandle nh; // nh means node_hander
ros::Publisher pub = nh.advertise<std_msgs::String>("sex_topic",10); // publisher,10 buffers
ros::Rate loop_rate(10); // 1s exc 10
while(ros::ok())
{
printf("Don't shorw \n");
std_msgs::String msg;
msg.data = "Come on sex!";
pub.publish(msg);
}
return 0;
}
发布的话题
- game_topic
- sex_topic
创建订阅者
缓存有长度限制,如果先到的数据一直没处理就丢弃,接受最新的数据包
创建 atr_pkg
包,创建 ma_node
节点
ma_node.cpp
#include <ros/ros.h>
#include <std_msgs/String.h>
void chao_callback(const std_msgs::String::ConstPtr& msg)
{
// 使用 printf 格式化输出
// printf("%s\n", msg->data.c_str());
ROS_INFO("%s \n",msg->data.c_str());
}
void yao_callback(const std_msgs::String::ConstPtr& msg)
{
ROS_WARN("%s \n",msg->data.c_str());
}
int main(int argc,char *argv[])
{
ros::init(argc,argv,"ma_node");
ros::NodeHandle nh;
ros::Subscriber sub = nh.subscribe("game_topic",10,chao_callback); // call_back function
ros::Subscriber sub_yao = nh.subscribe("sex_topic",10,yao_callback);
while(ros::ok())
{
ros::spinOnce(); // back look node
}
return 0;
}
hong_node.py
#!/usr/bin/env python3
# coding=utf-8
import rospy
from std_msgs.msg import String
def li_callback(msg):
rospy.loginfo(msg.data)
def ma_callback(msg):
rospy.loginfo(msg.data)
def main():
rospy.init_node("hong_node")
rospy.logwarn("Hello ROS1")
sub = rospy.Subscriber("learn_topic", String, li_callback,queue_size=10)
rospy.spin()
if __name__ == "__main__":
main()
topic 的 发布 和 订阅 不是单个节点管理的
而是由管家系节点来管理的,所有,一个节点可以订阅
rostopic指令
发布一个 game_topic
话题
发送 "I'm no.1 !come on!"
消息
查看现有的话题
- 列出当前系统中所有活跃着的话题
rostopic list
查看话题中的消息
- 显示指定话题中发送的消息包内容
rostopic echo /game_topic
ros1 对 unicode的编码支持不是很友好,能用英文尽量用英文
查看消息发布的频率
- 统计指定话题中消息包发送频率
rostopic hz xxx
查询当前活跃的topic
图形化显示当前系统活跃的节点以及节点间的话题通讯关系
rqt_graph
使用lanuch来启动
<launch>
<node pkg="ssr_pkg" type="yao_node" name="yao_node" />
<node pkg="ssr_pkg" type="chao_node" name="chao_node" launch-prefix="gnome-terminal -e" />
<node pkg="atr_pkg" type="ma_node" name="ma_node" />
</launch>
Topic 话题 和Messige 消息
概念
持续通讯
通过话题名称来建立通讯连接
- 通讯中的数据叫做
Message
- 消息Message
按照一定频率持续不断发送
- 发包者叫
Publisher
- 接收者叫
Subsciber
多个发布者和一个订阅者
要控制好消息的顺序
补充
程序的流程
使用launch文件启动多个节点
launch文件是一种遵循XML文件的
XML语法:
- 描述嵌套逻辑
例如
<launch>
<node pkg="ssr_pkg" type="yao_node" name="yao_node" />
<node pkg="ssr_pkg" type="chao_node" name="chao_node" launch-prefix="gnome-terminal -e" />
<node pkg="atr_pkg" type="ma_node" name="ma_node" />
</launch>
存放位置
ros1来执行launch会逐层遍历
多终端调试
启动 launch 文件打开多个终端来方便调试
- 加上 launch-prefix=”gnome-terminal -e”
< launch-prefix="gnome-terminal -e"/>
小结
launch是一个软件包重要的入口
当我们不知道这个包如何使用时,我们可以先看lauch文件
从launch文件如上就很方便