当前位置: 首页 > news >正文

ROS1基础入门:从零搭建机器人通信系统(Python/C++)

文章目录

  • 前言
  • 一、ROS核心概念:5分钟理解机器人通信架构
    • 1. 节点(Node):功能最小单元
    • 2. 主节点(Master):通信调度中心
    • 3. 话题(Topic):异步消息总线
    • 4. 服务(Service):同步请求-响应
    • 5. 参数服务器(Parameter Server):全局配置仓库
  • 二、实战第一步:创建ROS工作空间
    • 1. 创建目录结构
    • 2. 编译空工作空间
    • 3. 配置环境变量
    • 4.工作空间组成
  • 三、实战2:话题通信(Python/C++)
    • 1. Python实现(ros-noetic默认python版本为Python3,18.04的系统安装的是melodic,默认版本为Python2)
      • (1)发布者节点(talker.py)
      • (2)订阅者节点(listener.py)
    • 2. C++实现
      • (1)发布者节点(talker.cpp)
      • (2)订阅者节点(listener.cpp)
    • 3. 编译与运行
  • 四、实战3:服务通信(Python/C++)
    • 1. Python实现
      • (1)服务端(add_two_ints_server.py)
      • (2)客户端(add_two_ints_client.py)
    • 2. C++实现
      • (1)服务端(add_two_ints_server.cpp)
      • (2)客户端(add_two_ints_client.cpp)
  • 五、实战4:参数服务器(Python/C++)
    • 1. Python实现
    • 2. C++实现
  • 六、调试神器:ROS命令行工具箱
    • 1. 基础命令
    • 2. 可视化工具
  • 七、总结与进阶路线
    • 核心结论
    • 进阶方向


前言

ROS(Robot Operating System)是机器人领域的“瑞士军刀”,通过分布式节点通信模块化设计,解决了机器人软件开发中的复杂性问题。本文将从工作空间搭建开始,手把手带你实现话题发布/订阅服务请求/响应参数服务器配置,并提供完整的Python/C++代码示例与调试技巧。


一、ROS核心概念:5分钟理解机器人通信架构

1. 节点(Node):功能最小单元

  • 作用:独立运行的功能模块(如摄像头驱动、PID控制器)。
  • 特点
    • 每个节点是一个可执行程序(如talker_node)。
    • 支持多语言(C++/Python/Java)。
    • 通过节点名唯一标识(如/camera_node)。

2. 主节点(Master):通信调度中心

  • 作用
    • 注册节点信息(如节点名、提供的服务)。
    • 匹配话题发布者与订阅者、服务请求者与服务提供者。
  • 特点
    • 单实例运行(通过roscore启动)。
    • 无主节点时,节点间无法通信。

3. 话题(Topic):异步消息总线

  • 通信模式
    • 发布-订阅(Pub/Sub):一对多广播(如传感器数据流)。
    • 特点
      • 数据自动序列化传输。
      • 发布者与订阅者无需直接交互。
      • 支持多语言混合通信(Python发布者+C++订阅者)。

4. 服务(Service):同步请求-响应

  • 通信模式
    • 请求-响应(RPC):一对一调用(如查询电池电量)。
    • 特点
      • 客户端发送请求后立即阻塞,等待服务端返回结果。
      • 适用于需要确定性结果的场景。

5. 参数服务器(Parameter Server):全局配置仓库

  • 作用
    • 存储机器人全局配置(如最大速度、传感器校准参数)。
    • 支持动态参数更新(无需重启节点)。
  • 访问方式
    • 通过rosparam命令行工具。
    • 在代码中通过节点句柄读写。

二、实战第一步:创建ROS工作空间

1. 创建目录结构

# 创建工作空间根目录(catkin_ws可以任意替换你喜欢的名字)
mkdir -p ~/catkin_ws/src
cd ~/catkin_ws/

2. 编译空工作空间

# 编译(生成开发环境)
catkin_make

我创建了ros_learn/ros1用于存放ros1的相关代码
![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/c5d48ea4077f4c989111c070ccb457fa.png

3. 配置环境变量

# 临时生效
source devel/setup.bash# 永久生效(添加到~/.bashrc,根据自己的情况进行替换即可)
echo "source ~/ros_lean/ros1/devel/setup.bash" >> ~/.bashrc
source ~/.bashrc

4.工作空间组成

catkin_ws/(工作空间根目录)
src/(源码包目录,放置 ROS 的包)
build/(编译时的构建空间,生成中间文件)
devel/(开发空间,包含可直接运行的产物、环境设置脚本)
install/(安装空间,可选;完整安装后对外暴露的产物放在这里)
logs/(构建/运行日志,某些工具会生成)


三、实战2:话题通信(Python/C++)

对于ros1而已,一个工作空间下可以放多个程序包实现,源代码一般放在src目录下。
包级目录示例:my_pkg/
CMakeLists.txt(包的构建脚本)
package.xml(包的元数据与依赖声明)
src/(实现源码,可按需要放子目录)
include/(头文件,便于对外暴露的接口)
msg/(自定义消息定义,.msg 文件)
srv/(自定义服务定义,.srv 文件)
action/(自定义动作定义,.action 文件,若有)
launch/(启动文件,.launch 文件,使用 roslaunch 启动多个节点)
config/(配置文件,如 YAML/JSON,用于参数化节点)
scripts/(Python 脚本等可执行程序)
test/(测试用例)

1. Python实现(ros-noetic默认python版本为Python3,18.04的系统安装的是melodic,默认版本为Python2)

这里我创建名为talk_listen/scripts存放以下两个python代码。
可以在vsode中管理你的代码并安装喜欢的插件,往往有事半功倍的效果。
在这里插入图片描述

(1)发布者节点(talker.py)

#!/usr/bin/env python3
import rospy
from std_msgs.msg import Stringdef talker():# 初始化节点(名称唯一)rospy.init_node('talker', anonymous=True)# 创建话题发布者(队列大小10)pub = rospy.Publisher('chatter', String, queue_size=10)# 设置发布频率(10Hz)rate = rospy.Rate(10)count = 0while not rospy.is_shutdown():msg = f"Hello ROS {count}"rospy.loginfo(msg)pub.publish(msg)rate.sleep()count += 1if __name__ == '__main__':try:talker()except rospy.ROSInterruptException:pass

(2)订阅者节点(listener.py)

#!/usr/bin/env python3
import rospy
from std_msgs.msg import Stringdef callback(msg):rospy.loginfo(f"Received: {msg.data}")def listener():rospy.init_node('listener', anonymous=True)rospy.Subscriber('chatter', String, callback)rospy.spin()if __name__ == '__main__':listener()

在这里插入图片描述

这里我们简单的实现最基础的话题通信。
代码写好后我们可以直接使用python命令,无需编译。因为python3已经安装了ros的相关包
我们可以直接执行看一下效果。
ros1的程序执行都依赖于roscore。因此我们需要开三个终端进行测试。
在这里插入图片描述
单独执行talk.py,每0.1秒发送一次,Hello ROS并计数
在这里插入图片描述
执行listener.py,以同样的频率进行接受
在这里插入图片描述
你会发现在网络良好的状态下接受和发送接近同步

2. C++实现

python执行ros1代码并不依赖于本身的工作空间,但是在实际生产过程中,我们需要通过各种ros包的相互依赖关系完成作业。python只是快速实现我们所需功能的方法,它简单易上手,能够快速观察到想要的结果。
这里我将讲述正确创建一个ros包的过程。

#首先让我们进入工作空间下创建的src文件夹,将之前创建的talk_listen文件夹删除,在src目录下输入这样一行指令
#示例包名为 talk_listen,依赖 roscpp、std_msgs,
catkin_create_pkg talk_listen roscpp std_msgs

在这里插入图片描述
此时才正式出现了我在python代码中所写的正常的ros包组成。scripts可以自己创建。
接着我们在刚自动创建的src文件夹下写好我们的代码

(1)发布者节点(talker.cpp)

#include "ros/ros.h"
#include "std_msgs/String.h"int main(int argc, char **argv) {ros::init(argc, argv, "talker");ros::NodeHandle nh;ros::Publisher pub = nh.advertise<std_msgs::String>("chatter", 10);ros::Rate rate(10); // 10Hzint count = 0;while (ros::ok()) {std_msgs::String msg;msg.data = "Hello ROS " + std::to_string(count++);ROS_INFO("%s", msg.data.c_str());pub.publish(msg);rate.sleep();}return 0;
}

(2)订阅者节点(listener.cpp)

#include "ros/ros.h"
#include "std_msgs/String.h"void callback(const std_msgs::String::ConstPtr& msg) {ROS_INFO("Received: %s", msg->data.c_str());
}int main(int argc, char **argv) {ros::init(argc, argv, "listener");ros::NodeHandle nh;ros::Subscriber sub = nh.subscribe("chatter", 10, callback);ros::spin();return 0;
}

在这里插入图片描述
红色波浪线可以不用管,哈哈,这是找不到依赖头文件,我们会使用cmake工具来找到我们的依赖,你也可以试着去解决,如果你觉得看着别扭。实际上这不影响我们代码的实现。

3. 编译与运行

对于c/c++代码而已,需要将代码编译链接为可执行文件。这里我们需要用到cmake工具。实际上一个ros包乃至一个工作空间一般都是用cmake工具作为依赖管理的。
在这里插入图片描述
创建ros包后会自动在ros包的目录下创建cmakelist文件,里面写了各种示例,英语好的同学肯定能够看懂~
一个典型的ROS包中的CMakeLists.txt包含以下部分:

cmake_minimum_required(VERSION 3.0.2)  # 指定CMake最低版本
project(my_ros_package)                # 定义项目名称(需与包名一致)# 查找依赖的CMake包(包括ROS组件)
find_package(catkin REQUIRED COMPONENTSroscppstd_msgsmessage_generation  # 若需生成消息/服务,需添加此依赖
)# 配置catkin相关参数(如安装路径、系统依赖等)
catkin_package(CATKIN_DEPENDS roscpp std_msgs  # 声明本包依赖的ROS包DEPENDS system_lib              # 声明非ROS系统依赖(如Eigen、OpenCV)
)# 添加头文件路径
include_directories(include ${catkin_INCLUDE_DIRS})# 定义可执行文件
add_executable(my_node src/my_node.cpp)
target_link_libraries(my_node ${catkin_LIBRARIES})# 安装规则(将文件安装到系统目录)
install(TARGETS my_nodeRUNTIME DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION}
)

find_package(catkin REQUIRED COMPONENTS …)
用于声明构建本包所需的ROS依赖包(如roscpp、std_msgs)。
若依赖包未安装,CMake会报错。
catkin_package()
配置包的元信息,供其他包调用时使用。重要参数:
INCLUDE_DIRS:声明本包的头文件路径。
LIBRARIES:声明本包生成的库。
CATKIN_DEPENDS:声明本包运行时依赖的ROS包。

其他的相信聪明的你肯定会自己下去偷偷学习了

这里就直接给大家现成的cmake文件去使用

cmake_minimum_required(VERSION 3.0.2)
project(talk_listen)# 查找依赖的ROS包
find_package(catkin REQUIRED COMPONENTSroscppstd_msgs
)# 配置catkin包
catkin_package(CATKIN_DEPENDS roscpp std_msgs
)# 设置包含目录
include_directories(include${catkin_INCLUDE_DIRS}
)# 创建C++可执行文件
add_executable(talk_node src/talker.cpp)
target_link_libraries(talk_node ${catkin_LIBRARIES})add_executable(listener_node src/listener.cpp)
target_link_libraries(listener_node ${catkin_LIBRARIES})# 安装Python脚本
install(PROGRAMSscripts/listener.pyscripts/talker.pyDESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION}
)# 安装可执行文件
install(TARGETS talk_nodelistener_nodeRUNTIME DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION}
)
# 回到工作空间目录下,编译工作空间
catkin_make

在这里插入图片描述
如果没有报错,编译百分百通过
在这里插入图片描述
在这里插入图片描述
此时会出现build和devel文件夹存放我们编译过程和产物
此时我们重新打开一个终端或者在当前终端中刷新环境变量

source ~/.bashrc

仍然打开三个终端

#终端一
roscore
#终端二
rosrun talk_listen talk_node
#终端三
rosrun talk_listen listener_node

在这里插入图片描述
如果rosrun执行提示找不到某文件,可能需要重新刷新环境变量哦~

如果你觉得一次开三个终端太麻烦,那么你可以学习launch文件的使用。

Launch文件是ROS(Robot Operating System)中的一种XML格式的配置文件,用于批量启动和管理多个ROS节点。它允许通过单个命令启动整个ROS应用程序,而不需要手动逐个启动每个节点。(一条指令管饱)
在原有cmake文件的结尾添加

# 安装launch文件
install(DIRECTORY launch/DESTINATION ${CATKIN_PACKAGE_SHARE_DESTINATION}/launch
)

这里给出启动两种代码launch文件,在ros包中创建launch文件夹并创建文件即可
在这里插入图片描述

<launch><!-- 同时启动C++版本的talker和listener --><node pkg="talk_listen" type="talk_node" name="talker" output="screen"/><node pkg="talk_listen" type="listener_node" name="listener" output="screen"/>
</launch>
<launch><!-- 启动Python版本的节点 --><node pkg="talk_listen" type="talker.py" name="python_talker" output="screen"/><node pkg="talk_listen" type="listener.py" name="python_listener" output="screen"/>
</launch>

来到工作空间目录重新编译(每次修改cmake文件或者c++文件等都需要进行编译哦~)

catkin_make
source ~/.bashrc
roslaunch talk_listen talk_listen.launch

在这里插入图片描述
launch文件会自动检测是否加载ros核心如果没有会自动创建。
在这里插入图片描述
之前说过,我们写的python代码没有包含在ros包中,现在我们在cmake中添加了增加.py文件的支持
我们可以使用rosrun代码执行python代码
在执行代码前我们需要进行权限赋予,否则会权限报错

sudo chmod +x scripts/*
roscore
rosrun talk_listen talker.py 
rosrun talk_listen listener.py 

在这里插入图片描述
在这里插入图片描述
文章后面的代码就不给大家示例和教程了,相信大家可以自己补全,我只把最后结果贴出来。


四、实战3:服务通信(Python/C++)

1. Python实现

(1)服务端(add_two_ints_server.py)

#!/usr/bin/env python3
import rospy
from rospy_tutorials.srv import AddTwoInts, AddTwoIntsResponsedef handle_add(req):result = req.a + req.brospy.loginfo("Adding %d + %d = %d", req.a, req.b, result)return AddTwoIntsResponse(result)def add_two_ints_server():rospy.init_node('add_two_ints_server')s = rospy.Service('add_two_ints', AddTwoInts, handle_add)rospy.loginfo("AddTwoInts server ready.")rospy.spin()if __name__ == '__main__':add_two_ints_server()

(2)客户端(add_two_ints_client.py)

#!/usr/bin/env python3
import rospy
from rospy_tutorials.srv import AddTwoIntsdef add_two_ints_client(a, b):rospy.wait_for_service('add_two_ints', timeout=10)try:add_two_ints = rospy.ServiceProxy('add_two_ints', AddTwoInts)response = add_two_ints(a, b)return response.sumexcept rospy.ServiceException as e:rospy.logerr("Service call failed: %s", e)return Noneif __name__ == '__main__':rospy.init_node('add_two_ints_client')result = add_two_ints_client(10, 20)if result is not None:print("10 + 20 = %d" % result)else:print("Service call failed")

在这里插入图片描述

2. C++实现

(1)服务端(add_two_ints_server.cpp)

#include "ros/ros.h"
#include "std_srvs/AddTwoInts.h"bool handle_add(std_srvs::AddTwoInts::Request &req,std_srvs::AddTwoInts::Response &res) {res.sum = req.a + req.b;ROS_INFO("Request: a=%ld, b=%ld", (long int)req.a, (long int)req.b);ROS_INFO("Sending back sum: %ld", (long int)res.sum);return true;
}int main(int argc, char **argv) {ros::init(argc, argv, "add_two_ints_server");ros::NodeHandle nh;ros::ServiceServer service = nh.advertiseService("add_two_ints", handle_add);ROS_INFO("Ready to add two ints.");ros::spin();return 0;
}

(2)客户端(add_two_ints_client.cpp)

#include "ros/ros.h"
#include "std_srvs/AddTwoInts.h"int main(int argc, char **argv) {ros::init(argc, argv, "add_two_ints_client");ros::NodeHandle nh;if (argc != 3) {ROS_ERROR("Usage: add_two_ints_client X Y");return 1;}ros::ServiceClient client = nh.serviceClient<std_srvs::AddTwoInts>("add_two_ints");std_srvs::AddTwoInts srv;srv.request.a = atoll(argv[1]);srv.request.b = atoll(argv[2]);if (client.call(srv)) {ROS_INFO("Sum: %ld", (long int)srv.response.sum);} else {ROS_ERROR("Service call failed");return 1;}return 0;
}

![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/8a46116cb08e491aa4ff3b94030b8ab4.png

![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/734a0f27baf64da0a7ab657d07f1ab7a.pn
在这里插入图片描述


五、实战4:参数服务器(Python/C++)

1. Python实现

#!/usr/bin/env python3
import rospydef param_demo():rospy.init_node('param_demo')rospy.loginfo("Parameter Demo Started")try:# 设置参数rospy.set_param("robot_name", "Robo1")rospy.set_param("/global_speed", 5.0)rospy.set_param("~private_param", True)# 获取参数(带默认值)robot_name = rospy.get_param("robot_name", "DefaultRobot")global_speed = rospy.get_param("/global_speed", 1.0)private_param = rospy.get_param("~private_param", False)rospy.loginfo("Robot Name: %s", robot_name)rospy.loginfo("Global Speed: %.1f", global_speed)rospy.loginfo("Private Param: %s", str(private_param))# 检查参数是否存在if rospy.has_param("global_speed"):rospy.loginfo("global_speed exists")else:rospy.loginfo("global_speed deleted")# 搜索参数param_names = rospy.get_param_names()rospy.loginfo("Available parameters:")for name in param_names:rospy.loginfo("  %s", name)# 获取所有参数all_params = rospy.get_param("/")rospy.loginfo("All parameters on root: %s", str(all_params))# 删除参数rospy.delete_param("global_speed")# 验证删除if rospy.has_param("global_speed"):rospy.logwarn("global_speed still exists!")else:rospy.loginfo("global_speed successfully deleted")# 设置参数列表和字典rospy.set_param("sensor_ids", [1, 2, 3, 4])rospy.set_param("robot_config", {"max_speed": 10.0, "min_speed": 0.5})# 获取复杂参数sensor_ids = rospy.get_param("sensor_ids", [])robot_config = rospy.get_param("robot_config", {})rospy.loginfo("Sensor IDs: %s", str(sensor_ids))rospy.loginfo("Robot Config: %s", str(robot_config))except rospy.ROSException as e:rospy.logerr("ROS error occurred: %s", str(e))except Exception as e:rospy.logerr("Unexpected error: %s", str(e))if __name__ == '__main__':param_demo()

在这里插入图片描述

2. C++实现

#include "ros/ros.h"int main(int argc, char **argv) {ros::init(argc, argv, "param_demo");ros::NodeHandle nh;// 设置参数nh.setParam("robot_name", "Robo1");nh.setParam("/global_speed", 5.0);nh.setParam("~private_param", true);// 获取参数std::string robot_name;double global_speed;bool private_param;nh.getParam("robot_name", robot_name);nh.getParam("/global_speed", global_speed);nh.getParam("~private_param", private_param);ROS_INFO("Robot Name: %s", robot_name.c_str());ROS_INFO("Global Speed: %.1f", global_speed);ROS_INFO("Private Param: %d", private_param);// 删除参数nh.deleteParam("global_speed");// 检查参数是否存在if (nh.hasParam("global_speed")) {ROS_INFO("global_speed exists");} else {ROS_INFO("global_speed deleted");}return 0;
}

在这里插入图片描述


六、调试神器:ROS命令行工具箱

1. 基础命令

# 查看活跃节点
rosnode list# 查看节点详情
rosnode info /talker# 查看当前话题
rostopic list# 查看话题消息类型
rostopic type /chatter# 查看实时数据(文本模式)
rostopic echo /chatter# 查看服务列表
rosservice list# 调用服务(手动输入参数)
rosservice call /add_two_ints "a: 10\nb: 20"

2. 可视化工具

# 启动rqt图形界面
rqt# 使用rqt_plot实时绘图
rqt_plot /chatter# 启动rviz三维可视化
rviz

七、总结与进阶路线

核心结论

  1. 话题:适合传感器数据流(如激光雷达、摄像头)。
  2. 服务:适合需要即时反馈的操作(如导航目标设定)。
  3. 参数服务器:适合全局配置管理(如机器人物理参数)。

进阶方向

  1. 消息记录与回放:使用rosbag保存/复现实验数据。
  2. 动态参数配置:通过dynamic_reconfigure实时调整参数。
  3. 多机通信:配置ROS_MASTER_URI实现多机器人协同。

通过掌握这些技能,你已经具备了开发复杂机器人系统的核心能力。下一步可以尝试:

  • 集成摄像头实现目标检测
  • 使用SLAM算法构建地图
  • 开发自主导航功能

遇到问题时,善用rostopicrosservice等命令行工具,或查阅http://wiki.ros.org/。祝你在机器人世界探索愉快! 🚀

http://www.dtcms.com/a/598521.html

相关文章:

  • Scikit-learn 入门指南:从零到一掌握机器学习经典库(2025 最新版)
  • 做那个的网站谁有手机如何制作小程序
  • 自己做的网站把密码改忘了怎么办wordpress 表格 插件
  • 成都园林景观设计公司推荐南京seo培训
  • InvivoCrown丨艾美捷代理(货号:SIM0053)BioSIM抗人IL-13抗体(来瑞组单抗生物类似药)研究级探索2型免疫反应的精密研究
  • oracle数据库网站开发网站建设和成本
  • 太原网页设计厦门网站排名优化软件
  • 专题网站建设意义何在网址大全2345
  • 网站建设视频教程最新企业品牌文化建设学习网站
  • CI/CD集成工程师前景分析:与开发岗位的全面对比
  • 网站建设费计入哪个科目汕头网站优化公司
  • 智慧团建网站什么时候维护好中国招商平台
  • 自己做的网站访问不栅格化系统制作网页界面设计
  • 做定制网站多少钱四川网络推广公司哪家好
  • Paint Net(windows免费绘画软件) v5.1.10
  • 东莞网站建设方案表短链接生成源码
  • 翻墙到国外网站怎么做网页设计岗位职责
  • JavaEE入门--计算机是怎么工作的
  • GRPO(Group Relative Policy Optimization)
  • .net空网站做九九乘法表wordpress怎样上传主题
  • 网站建设包括备案吗方象科技服务案例
  • 从 ps -ef 之后怎么获得这个进程的更多信息
  • Tkinter Canvas 方案和OpenCV+PIL 方案的差别
  • 深入解析socket函数:从服务端创建到内核实现原理
  • 吴江住房城乡建设局网站广州专业建网站公司
  • 网站上的美工图片要怎么做做物理的网站
  • 找单位做网站需要注意什么手机建站程序源码
  • 做服务器的网站都有哪些淄博乐达网站建设吧
  • 电子商城网站开发价格江苏网站建设开发
  • 做网站用是内网穿透好美食的网页设计