本教程将从 零基础 带你创建一个包含两个节点的 ROS 包:
一个用键盘控制小车方向,另一个接收控制信息并解析动作。
本章使用ROS Noetic版本,如果对ROS背景,ROS主题,ROS架构和工作空间概念不了解的读者,可以先阅读我的专栏中的前两篇文章《01-ROS安装详细指南》和《02-ROS架构介绍》
🧱 第一步:创建工作空间与包
✅ 创建工作空间
这里我们给工作空间起名为catkin_ws
你可以根据需要命名工作空间。catkin_ws 是"catkin workspace"(catkin工作空间)的缩写,其中,catkin 是ROS中的构建系统的名称,ws 代表工作空间workspace。
mkdir -p ~/catkin_ws/src
cd ~/catkin_ws
catkin_make
source devel/setup.bash
✅ 创建 ROS 包
cd ~/catkin_ws/src
catkin_create_pkg my_robot_control rospy std_msgs geometry_msgs
解释:
my_robot_control
:你的包名;rospy
:使用 Python 写 ROS 节点;std_msgs
和geometry_msgs
:标准消息类型,geometry_msgs/Twist
是控制速度的关键消息类型。
✍️ 第二步:编写 Python 节点
1️⃣ keyboard_control_node.py
:读取键盘输入,发布 /cmd_vel
路径:~/catkin_ws/src/my_robot_control/scripts/keyboard_control_node.py
#!/usr/bin/env python3
import rospy
from geometry_msgs.msg import Twist
def main():
# 创建一个Publisher,发布到 /cmd_vel,消息类型为Twist
pub = rospy.Publisher('/cmd_vel', Twist, queue_size=10)
# 初始化节点,名称为 keyboard_control_node
rospy.init_node('keyboard_control_node')
rate = rospy.Rate(10) # 发布频率 10Hz
print("=== 使用键盘控制小车 ===")
print("w: 前进 | s: 后退 | a: 左转 | d: 右转 | q: 退出")
while not rospy.is_shutdown():
key = input("请输入方向键:")
msg = Twist() # 初始化速度消息
if key == 'w':
msg.linear.x = 0.5 # 前进
elif key == 's':
msg.linear.x = -0.5 # 后退
elif key == 'a':
msg.angular.z = 0.5 # 左转
elif key == 'd':
msg.angular.z = -0.5 # 右转
elif key == 'q':
print("退出控制程序")
break
else:
print("无效输入,请输入 w/s/a/d/q")
continue
pub.publish(msg) # 发布消息
rate.sleep()
if __name__ == '__main__':
main()
2️⃣ motor_controller_node.py
:接收 /cmd_vel
,输出控制信息
路径:~/catkin_ws/src/my_robot_control/scripts/motor_controller_node.py
#!/usr/bin/env python3
import rospy
from geometry_msgs.msg import Twist
# 回调函数,当接收到 /cmd_vel 消息时触发
def callback(msg):
linear = msg.linear.x
angular = msg.angular.z
# 判断动作类型
if linear > 0:
action = "前进"
elif linear < 0:
action = "后退"
elif angular > 0:
action = "左转"
elif angular < 0:
action = "右转"
else:
action = "停止"
# 输出动作和速度信息
print(f"[MotorController] 动作: {action} | 线速度: {linear:.2f} m/s | 角速度: {angular:.2f} rad/s")
def main():
rospy.init_node('motor_controller_node') # 初始化节点
rospy.Subscriber('/cmd_vel', Twist, callback) # 订阅 /cmd_vel
rospy.spin() # 等待回调
if __name__ == '__main__':
main()
🔑 第三步:配置可执行权限与 CMakeLists.txt
✅ 设置可执行权限
chmod +x ~/catkin_ws/src/my_robot_control/scripts/*.py
✅ 修改 CMakeLists.txt
确保添加如下内容来安装你的 Python 脚本,修改~/catkin_ws/src/my_robot_control/CMakeLists.txt
,在find_package
之后添加如下语句
catkin_package()
catkin_install_python(PROGRAMS
scripts/keyboard_control_node.py
scripts/motor_controller_node.py
DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION}
)
🔨 第四步:编译项目
cd ~/catkin_ws
catkin_make
source devel/setup.bash
🧪 第五步:单独运行每个节点
✅ 先启动 roscore
roscore
如果没有安装或者安装后命令无法识别,请参考我专栏中的《01-ROS安装详细指南》
✅ 运行 keyboard 控制节点
source ~/catkin_ws/devel/setup.bash
rosrun my_robot_control keyboard_control_node.py
含义解释:
rosrun
:运行单个 ROS 节点;my_robot_control
:你的包名;keyboard_control_node.py
:脚本名称,必须在scripts/
下并有可执行权限。
✅ 在另一个终端运行 motor controller 节点
source ~/catkin_ws/devel/setup.bash
rosrun my_robot_control motor_controller_node.py
此时,在keyboard控制节点终端输入方向按键(wsad)并输入回车后,就可以看到另一个终端的输出信息。
🚀 第六步:使用 Launch 文件同时启动两个节点
目前每个节点都需要独立运行,当节点数量多了后,尤其是生产环境,可能有几十个甚至数百个节点,如果还是这样一个一个运行,就会非常麻烦,且启动的参数也不容易文档化管理。
这时,我们就可以使用Launch文件同时启动多个节点。
✅ 创建 launch 文件夹
mkdir -p ~/catkin_ws/src/my_robot_control/launch
✅ 编写 my_robot_launch.launch
路径:~/catkin_ws/src/my_robot_control/launch/my_robot_launch.launch
<launch>
<!-- 启动键盘控制节点 -->
<node pkg="my_robot_control" type="keyboard_control_node.py" name="keyboard_control" output="screen"/>
<!-- 启动电机控制节点 -->
<node pkg="my_robot_control" type="motor_controller_node.py" name="motor_controller" output="screen"/>
</launch>
参数说明:
pkg
:节点所在的包名;type
:节点的可执行文件(脚本)名称;name
:运行时给节点起的名字(可用于调试);output="screen"
:将日志输出显示在终端。
✅ 启动 launch 文件
roslaunch my_robot_control my_robot_launch.launch
含义解释:
roslaunch
:用于运行 launch 文件,支持同时启动多个节点;my_robot_control
:包名;my_robot_launch.launch
:启动文件名称,必须放在launch/
文件夹下。
此时,已经在一个窗口中通过roslaunch命令同时启动了两个节点,我们在窗口中同时输入控制指令并看到另一个节点的输出。
📂 最终项目结构
my_robot_control/
├── CMakeLists.txt
├── package.xml
├── launch/
│ └── my_robot_launch.launch
├── scripts/
│ ├── keyboard_control_node.py
│ └── motor_controller_node.py
常用调试命令
通过结合以下 ROS 相关命令,可以从另一个角度观察程序的运行状态。
在启动两个节点后:
-
查看当前话题:
使用rostopic list
命令可以列出当前系统中所有的话题,确以看到我们两个节点使用的/cmd_vel
话题。$:~/catkin_ws$ rostopic list /cmd_vel
-
查看当前节点:
使用rosnode list
命令可以列出当前运行的所有节点,可以看到我们启动的两个节点:keyboard_control
和motor_controller
。$:~/catkin_ws$ rosnode list /keyboard_control /motor_controller
-
实时监听话题数据:
使用rostopic echo /cmd_vel
可以在终端中持续监听/cmd_vel
话题的数据。如果该话题有数据发布,命令行中会实时打印出来。比如在执行后,在之前启动的keyboard_control
终端中,输入wsad
控制时,便能同步看到输出数据。$:~/catkin_ws$ rostopic echo /cmd_vel linear: x: 0.5 y: 0.0 z: 0.0 angular: x: 0.0 y: 0.0 z: 0.0
这样,你就可以通过这些命令更直观地调试和监控 ROS 系统的运行状态。
✅ 小结
你现在拥有了一个完整的 ROS 包:
- ✅ 可用键盘控制小车;
- ✅ 发布
/cmd_vel
控制速度; - ✅ 模拟电机接收速度并输出动作信息;
- ✅ 支持手动运行和 launch 一键启动!
- ✅ 使用ros的常用命令进行调试。
如果想继续扩展,可以加入:
- 🔋 控制真实电机(通过串口或 GPIO);
- 🖥️ 用 GUI 或者接受远端遥控信号替代命令行键盘输入;
- 🧠 使用导航算法,实现自动规划。