ROS学习笔记
学习内容:ROS的第一部分学习
- Node节点和Package包
- Topic话题与Message消息
- 发布订阅节点
- launch启动多个节点
- 机器人运动控制
- 激光雷达
学习时间:
- 2026.3.15
学习产出:
一、Node节点和Package包
1.1节点与包
node是ROS最基本的程序单元,节点组织形式是package。包为node的载体,包里面有多个节点。ROS使用CMake和catkin作为编译工具。包是节点的容器。
1.2第一个Node节点
创建的节点需要放在包中。
1.2.1创建package包(流程)



依赖项就是容易出现在多个包内的节点的功能包,比如rospy,roscpp,std_msgs(标准消息包)。package.xml存在极有可能是package包。
回访依赖项。roscd可以跳转到功能包的地址,例如roscd roscpp。
1.2.2创建节点(src和scripts下的内容就是节点)
src目录下创建文件.cpp。在CMake.list中加入编译规则,如下

启动ros的核心:roscore(工作空间的环境参数一定要加入到终端程序里),其实ros里的节点就是一个应用程序。
要想使用ros::init的话需要在CMake.list中加入如下内容

ctrl+shift+w强制关闭终端。::当成_。响应外部信号需要写成ros::ok(),不能使用true。
示例代码:
#include <ros/ros.h>
int main(int argc, char *argv[])
{
ros::init(argc, argv, “chao_node”);
printf(“我的枪去而复返,你的生命有去无回!\n”);
while (ros::ok())
{
printf(“别投,我还能秀!\n”);
}
return 0;
}
2、Topic话题与Message消息(节点通讯方式)

小结
话题Topic是节点间进行持续通讯的一种形式。
话题通讯的两个节点通过话题的名称建立起话题通讯连接。
话题中通讯的数据,叫做消息Message。
消息Message通常会按照一定的频率持续不断的发送,以 ensure 消息数据的 real time性。
消息的发送方叫做话题的发布者Publisher。
消息的接收方叫做话题的订阅者Subscriber。
外延补充
一个ROS节点网络中,可以同时存在多个话题。
一个话题可以有多发布者,也可以有多个订阅者。
一个节点可以对多个话题进行订阅,也可以发布多个 topics。
不不同的传感器消息通常会拥有各自独立话题名称,每个话题只有一个发布者。
机器人的速度指令通常会有多个发布者,但是同一时间只能有一个发言人。
index.ros.org这个是学习ros的网站
2.2.1发布者C++实现
// 头文件
#include <ros/ros.h>
// 包含std_msgs/ String类型
#include <std_msgs/String.h>
int main(int argc, char *argv[])
{
// 初始化ROS节点
ros::init(argc,160
// 初始化ROS节点
ros::init(argc, argv, "chao_node");
// 打印启动提示
printf("我的枪去而复返,你的生命有去无回!\n");
// 创建节点句柄
ros::NodeHandle nh;
// 创建发布者,发布类型为 std_msgs:: String, 话题名为“kuaishangchekaiheiqun”,队列长度为10
ros::Publisher pub = nh.advertise<std_msgs:: String>("kuaishangchekaiheiqun", 10);
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 /话题名称可以查看话题发送频率
小结
确定话题名称和消息类型。
在代码文件中include消息类型对应的头文件。
在main函数中通过NodeHandle大管家发布一个话题并得到消息发送对象。
生成要发送的消息包并进行发送数据的赋值。
调用消息发送对象的publish()函数将消息包发送到话题当中。
常用工具
rostopic list
列出当前系统中所有活跃着的话题。
rostopic echo 主题名称
显示指定话题中发送的消息包内容。
rostopic hz 主题名称
统计指定话题中消息包发送频率。
2.2.2订阅者C++实现
#include <ros/ros.h>
#include <std_msgs/String.h>
void chao_callback(std_msgs::String msg)
{
printf(msg.data.c_str());
printf("\n");
}
int main(int argc, char *argv[])
{
ros::init(argc, argv, "ma_node");
ros::NodeHandle nh;
ros::Subscriber sub = nh.subscribe("kuai_shang_che_kai_hei_qun", 10, chao_callback);
while (ros::ok())
{
ros::spinOnce();
}
return 0;
}
rqt_graph用于查看节点及话题通讯关系
话题的订阅
确定话题名称和消息类型。
在代码文件中include <ros.h>和消息类型对应的头文件。
在main函数中通过NodeHandler大管家订阅一个话题并设置消息接收回调函数。
定义一个回调函数,对接收到的消息包进行处理。
main函数中需要执行ros::spinOnce(),让回调函数能够响应接收到的消息包。
2.2.3发布者Python实现
新建scripts文件夹
#!/usr/bin/env python3
#coding=utf-8
import rospy
from std_msgs.msg import String
if __name__ == "__main__":
rospy.init_node("chao_node")
rospy.logwarn("我的枪去而复返,你的生命有去无回!")
pub = rospy.Publisher("kuai_shang_che_kai_hei_qun", String, queue_size=10)
rate = rospy.Rate(10)
while not rospy.is_shutdown():
rospy.loginfo("我要开始刷屏了")
msg = String()
msg.data = "国服马超,带飞"
pub.publish(msg)
rate.sleep()
注意:要添加可执行权限
2.2.4订阅者Python实现
#!/usr/bin/env python3
#coding=utf-8
import rospy
from std_msgs.msg import String
def chao_callback(msg):
rospy.loginfo(msg.data)
def yao_callback(msg):
rospy.logwarn(msg.data)
if __name__ == "__main__":
rospy.init_node("ma_node")
sub = rospy.Subscriber("kuai_shang_che_kai_hei_qun", String, chao_callback, queue_size=10)
sub_2 = rospy.Subscriber("gie_gie_dai_wo", String, yao_callback, queue_size=10)
rospy.spin()
3.launch启动多个节点
大纸盒套小纸盒

- 使用launch文件,可以通过roslaunch指令一次启动多个节点。
- 在launch文件中,为节点添加 output=“screen” 属性,可以让节点信息输出在终端中。(ROS_WARN不受该属性控制)
- 在launch文件中,为节点添加 launch-prefix=“gnome-terminal -e” 属性,可以让节点单独运行在一个独立终端中。
- 机器人运动控制

4.1.1C++实现机器人运动控制
#include <ros/ros.h>
#include <geometry_msgs/Twist.h>
int main(int argc, char *argv[])
{
ros::init(argc, argv, "vel_node");
ros::NodeHandle n;
ros::Publisher vel_pub = n.advertise<geometry_msgs::Twist>("/cmd_vel", 10);
geometry_msgs::Twist vel_msg;
vel_msg.linear.x = 0.1;
vel_msg.linear.y = 0;
vel_msg.linear.z = 0;
vel_msg.angular.x = 0;
vel_msg.angular.y = 0;
vel_msg.angular.z = 0;
ros::Rate r(30);
while (ros::ok())
{
vel_pub.publish(vel_msg);
r.sleep();
}
return 0;
}

4.1.2Python实现机器人运动控制
#!/usr/bin/env python3
#coding=utf-8
import rospy
from geometry_msgs.msg import Twist
if __name__ == "__main__":
rospy.init_node("vel_node")
vel_pub = rospy.Publisher("cmd_vel", Twist, queue_size=10)
vel_msg = Twist()
vel_msg.linear.x = 0.1
rate = rospy.Rate(30)
while not rospy.is_shutdown():
vel_pub.publish(vel_msg)
rate.sleep()
5.雷达(话题是/scan)
5.1.1获取激光雷达数据C++节点
读取正前方距离值
#include <ros/ros.h>
#include <sensor_msgs/LaserScan.h>
void LidarCallback(const sensor_msgs::LaserScan msg)
{
float fMidDist = msg.ranges[180];
ROS_INFO("前方测距 ranges[180] = %f 米", fMidDist);
}
int main(int argc, char *argv[])
{
setlocale(LC_ALL,"");
ros::init(argc, argv, "lidar_node");
ros::NodeHandle n;
ros::Subscriber lidar_sub = n.subscribe("/scan", 10, &LidarCallback);
ros::spin();
return 0;
}
5.1.2获取激光雷达数据Python节点
#!/usr/bin/env python3
#coding=utf-8
import rospy
from sensor_msgs.msg import LaserScan
def LidarCallback(msg):
dist = msg.ranges[180]
rospy.loginfo("前方测距 ranges[180] = %f 米", dist)
if __name__ == "__main__":
rospy.init_node("lidar_node")
lidar_sub = rospy.Subscriber("/scan", LaserScan, LidarCallback, queue_size=10)
rospy.spin()
5.2.1激光雷达避障C++实现
#include <ros/ros.h>
#include <sensor_msgs/LaserScan.h>
#include <geometry_msgs/Twist.h>
ros::Publisher vel_pub;
void LidarCallback(const sensor_msgs::LaserScan &msg)
{
float fMidDist = msg.ranges[180];
ROS_INFO("前方测距 ranges[180] = %f 米", fMidDist);
geometry_msgs::Twist vel_cmd;
if (fMidDist < 1.5)
{
vel_cmd.angular.z = 0.3;
}
else
{
vel_cmd.linear.x = 0.05;
}
vel_pub.publish(vel_cmd);
}
int main(int argc, char *argv[])
{
setlocale(LC_ALL, "");
ros::init(argc, argv, "lidar_node");
ros::NodeHandle n;
ros::Subscriber lidar_sub = n.subscribe("/scan", 10, &LidarCallback);
vel_pub = n.advertise<geometry_msgs::Twist>("/cmd_vel", 10);
ros::spin();
return 0;
}
5.2.2激光雷达避障Python实现
```cpp
```python
#!/usr/bin/env python3
#coding=utf-8
import rospy
from sensor_msgs.msg import LaserScan
from geometry_msgs.msg import Twist
def LidarCallback(msg):
global vel_pub
dist = msg.ranges[180]
rospy.loginfo("前方测距 ranges[180] = %f 米", dist)
vel_cmd = Twist()
if dist < 1.5:
vel_cmd.angular.z = 0.3
else:
vel_cmd.linear.x = 0.05
vel_pub.publish(vel_cmd)
if __name__ == "__main__":
rospy.init_node("lidar_node")
lidar_sub = rospy.Subscriber("/scan", LaserScan, LidarCallback, queue_size=10)
vel_pub = rospy.Publisher("/cmd_vel", Twist, queue_size=10)
rospy.spin()
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐



所有评论(0)