ROS2学习笔记(humble)
1、工作空间
工作空间包括
build
install
log(日志)
src(用户代码编写空间)
工作空间创建流程:
1.1、 创建工作目录:
mkdir -p TOWN_WS/src #创建TOWN_WS的工作目录,并且创建src的代码编写空间
1.2、创建功能包:
ros2 pkg create --build-type {cmake或ament_cmake或ament_python} --dependencies <依赖名字>
ros2 pkg create village_li --build-type ament_python --dependencies rclpy
1.3、编译功能包
注意:应该回到工作空间目录下执行colcon build
命令
编译单个指定功能包colcon build --packages-select <package-name>
2、节点
2.1面向过程创建方式
import rclpy
from rclpy.node import Node
def main(args=None):
"""
编写ROS2节点的一般步骤
1. 导入库文件
2. 初始化客户端库
3. 新建节点对象
4. spin循环节点
5. 关闭客户端库
"""
rclpy.init(args=args) # 初始化rclpy
node = Node("node_02") # 新建一个节点
###################################
############节点执行的功能############
node.get_logger().info("大家好,我是node_02.")
###############################################
rclpy.spin(node) # 保持节点运行,检测是否收到退出指令(Ctrl+C)
rclpy.shutdown() # 关闭rclpy
2.2面向对象创建方式
#!/usr/bin/env python3
import rclpy
from rclpy.node import Node
class Node(Node):
"""
创建一个Node02_class节点,并在初始化时输出一个话
"""
def __init__(self,name):
super().__init__(name)
self.get_logger().info(f"大家好,我是{name}")
def main(args=None):
rclpy.init(args=args) # 初始化rclpy
node = Node("node_02_class") # 新建一个节点
rclpy.spin(node) # 保持节点运行,检测是否收到退出指令(Ctrl+C)
rclpy.shutdown() # 关闭rclpy
2.3、添加节点到setup.py文件
节点名称 = 功能包.节点所在文件:main
"li4= village_li.li4:main",
2.4 、节点相关命令(后续继续补充)
列出所以正在运行节点
ros2 node list
运行节点
ros2 run <功能包名称> <节点名称>
查看节点信息
ros2 node info <node_name>
2.5、rclpy相关函数的补充
rclpy.spin(node)
:循环节点,主要是循环(timer、话题)的回调函数,按ctrl+C退出循环
rclpy.spin_once(node)
:循环一次节点
node.destroy_node() # 销毁节点对象
:销毁指定节点
3、话题
3.1 topic相关的终端命令
ros2 topic list
列出当下正在运行的话题
ros2 topic echo /<话题名>
截获指定话题的内容
ros2 topic info /<话题名>
查看话题信息
ros2 topic pub /<话题名> std_masgs/msg/<消息类型> "{data: <对应数据>}"
发布数据
3.2话题发布
- 定义发布消息的功能
主要调用Node类下的create_publisher(消息类型,话题名称,缓存长度)
方法,例如:
self.Pub_novel = self.create_publisher(String,"sey_girl",10) ###定义发送功能
定义一个话题名称为“sey_girl"的话题,类型为String,缓存长度为10. - 发布消息(一般需要循环发送)
2.1 使用Node类下的create_timer(秒数,回调函数)
创建一个定时器
self.timer = self.create_timer(5,self.pub_mag)
2.2 编写回调函数
使用定义的发布消息的功能下的pubilsh(消息)
消息类型为String,所以必须要使用String()接口传递参数def pub_mag(self): msg=String() msg.data = self.msg_crate() #self.get_logger().info(msg.data) self.Pub_novel.publish(msg)
- 使用终端命令发布消息
3.3 话题订阅
- 使用Node类下的
create_subscription(消息类型,话题名称,回调函数,缓存长度)
方法定义订阅者功能。self.Sub_money=self.create_subscription(UInt32,"sey_girl_money",self.Sub_money_callback,10) ###定义接受消息
- 编写回调函数
从形参msg.data
中读取受到的数据def Sub_money_callback(self,msg):#回调函数的格式,形参为受到的数据 self.account += msg.data self.get_logger().info(f"收到{msg.data}元,账户余额{self.account}元。")
3.4 例子
li4和wang5对话的例子
li4.py
如下:
import rclpy
from rclpy.node import Node
from std_msgs.msg import String,UInt32
import time
class Node(Node):
def __init__(self,name):
super().__init__(name)
self.get_logger().info(f"大家好,我是{name}")
self.account = 0
self.Z = 0#章节号
self.H = 0#章回号
#########rclpy.spin()控制的线程,这里相当于开了两个线程
self.Sub_money = self.create_subscription(UInt32,"sey_girl_money",self.Sub_money_callback,10) ###定义接受消息
self.Pub_novel = self.create_publisher(String,"sey_girl",10) ###定义发送功能
self.timer = self.create_timer(5,self.pub_mag) ###定时发布消息
def Sub_money_callback(self,msg):#回调函数的格式,形参为受到的数据
self.account += msg.data
self.get_logger().info(f"收到{msg.data}元,账户余额{self.account}元。")
########发送String类型的消息################
def pub_mag(self):
msg=String()
msg.data = self.msg_crate()
self.get_logger().info(msg.data)
self.Pub_novel.publish(msg)
############实际上这里不用这样写,只是为了搭建一个格式##############
def msg_crate(self):
self.Z = self.Z + 1
self.H = self.H + 1
data = f'艳娘传奇:第{self.Z}章,第{self.H}回'
return str(data)
def main(args=None):
rclpy.init(args=args) # 初始化rclpy
li4 = Node("li4")
rclpy.spin(li4)
li4.destroy_node() # 销毁节点对象
rclpy.shutdown() # 关闭rclpy
wang5.py
如下:
import rclpy
from rclpy.node import Node
from std_msgs.msg import String,UInt32
class Node(Node):
"""
创建一个Node02_class节点,并在初始化时输出一个话
"""
def __init__(self,name):
super().__init__(name)
self.get_logger().info(f"大家好,我是{name}")
self.money = 1
self.Sub_Novel = self.create_subscription(String,"sey_girl",self.Sub_Novel_callback,10) ###定义接受消息
self.Pub_money = self.create_publisher(UInt32,"sey_girl_money",10) ###定义发送功能
self.timer = self.create_timer(5,self.pub_msg) ###定时发布消息
def Sub_Novel_callback(self,msg):
self.get_logger().info(f"{msg.data}")
def pub_msg(slef):
msg=UInt32()
msg.data = slef.msg_creat()
slef.get_logger().info(f"我支付了:{msg.data}元")
slef.Pub_money.publish(msg)
def msg_creat(self):
self.money += 1
return int(self.money)
def main(args=None):
rclpy.init(args=args) # 初始化rclpy
wang5 = Node("wang5") # 新建一个节点
rclpy.spin(wang5) # 保持节点运行,检测是否收到退出指令(Ctrl+C)
wang5.destroy_node() # 销毁节点对象
rclpy.shutdown() # 关闭rclpy