ROS2 学习笔记

Startup

安装

wget http://fishros.com/install -O fishros && bash fishros

请添加图片描述

  • humble:稳定版本
  • rolling:持续更新版本

文档:ros2版本文档

在安装完成之后,可以输入 ros2 来检查是否安装成功。

海龟模拟器

打开一个终端输入ros2 run turtlesim turtlesim_node
采用键盘控制海龟移动,打开一个新的终端输入 ros2 run turtlesim turtle_teleop_key (上下左右键),
再打开一个终端,输入 rqt (ros2 自带的图形开发工具)点击 Plugins -> Introspection -> Node Graph 可以查看当前的节点图。
请添加图片描述

/teleop_turtle 节点和 /turtlesim 节点之间通过了 /turtle1/cmd_vel 话题进行了通讯,也就是可以通过键盘控制的窗口控制了海龟的移动。

常见指令

echo $ROS_VERSION # 打印ros的版本
echo $ROS_DISTRO  # 打印ros的发行版本

节点

编写第一个节点

运行该代码后,可通过 ros2 node list 查看节点。可以通过修改环境变量的方式控制输出的内容 export RCUTILS_CONSOLE_OUTPUT_FORMAT=[{function_name}:{line_number}]:{message}

import rclpy
from rclpy.node import Node
  
def main():
	rclpy.init() # 初始化
	node = Node("python_node") # 节点名字
	# [日志级别] [1970年到现在经过的秒数] [节点名称] :打印的内容
	node.get_logger().info('你好 Python 节点!') # info级别日志 呈现白色
	node.get_logger().warn('你好 Python 节点!') # 警告级别日志 呈现黄色
	rclpy.spin(node)
	rclpy.shutdown()

if __name__ == "__main__":
	main()

如果遇到 version GLIBCXX_3.4.30‘ not found 问题,先查看系统和anaconda环境下是否有 libstdc++.so 以及他们对应的 GLIBC 版本(ls -al xx)

strings /usr/lib/x86-linux-gnu/libstdc++.so.6 | grep GLIBC
strings /home/xx/anaconda3/envs/xx/lib/libstdc++.so.6 | grep GLIBC

如果anaconda底下的 libstdc++.so 以及 libstdc++.so.6 指向的版本比系统低(通常anaconda3指向 libstdc++.so.6.0.29 而系统最高是 libstdc++.so.6.30)那么通过删除原来的,建立软连接修复即可。

ln -s /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.30 libstdc++.so.6
ln -s /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.30 libstdc++.so

使用功能包

使用 ros2 pkg create --build-type ament_python --license Apache-2.0 demo_python_pkg 创建功能包。
–build-type 默认是 cmake,使用python必须手动指定。

功能包结构包含:节点代码目录(与功能包名字一致)、resource(功能包标识)、test(测试代码目录)、LICENSE(许可证)、package.xml(功能包的清单文件)、setup.cfg(python包的配置选项)、setup.py(功能包的构建脚本)。

请添加图片描述
创建完功能包后,可以在 demo_python_pkg/demo_python_pkg/ 下编写节点文件代码函数同上。
在 setup.py 中修改 entry_points为如下:

entry_points={
	'console_scripts': [
	'python_node = demo_python_pkg.python_node:main' # 包名字.文件名字.函数
	],
}

由于代码中使用了 rclpy 这个库,需要在 package.xml 中声明,添加 <depend>rclpy<depend>
在这之后,通过 colcon 构建功能包:colcon build

注意:运行的是拷贝到 install 里面的文件,每次修改代码后需要重新构建或者构建软链接!
因为python是解释执行的,所以install下是py文件。如果是c++,则是二进制文件。

执行 source install/setup.bash 修改了环境变量,输入 ros2 run demo_python_pkg python_node 运行。

多线程与回调函数

注:在ros2中每个节点默认在一个线程中执行

在终端执行 echo "第一章 少年踏上休闲路" > novel1.txtecho "第二章 学习修仙,马上升天" > novel2.txtecho "第三章 女大三千,位列仙班" > novel3.txt 并上传至本地网页 python3 -m http.server

import requests
import threading

class Download:
	def download(self, url, callback_word_count):	
		print(f"线程:{threading.get_ident()} 开始下载:{url}")
		response = requests.get(url)
		response.encoding = 'utf-8'
		callback_word_count(url, response.text) # 调用回调函数
		def start_downloading(self, url, callback_word_count):
		thread = threading.Thread(target=self.download, args=(url, callback_word_count)) # 创建线程
		thread.start() # 启动线程

def word_count(url, result):
	print(f"{url}:{len(result)}->{result[:5]}")

def main():
	download = Download()download.start_downloading("http://0.0.0.0:8000/novel1.txt", word_count)
download.start_downloading("http://0.0.0.0:8000/novel1.txt", word_count)
download.start_downloading("http://0.0.0.0:8000/novel1.txt", word_count)

然后在终端执行以下代码:

cd chapt2/chapt2_ws/
colcon build
source install/setup.bash
ros2 run demo_python_pkg learn_thread

话题

使用 ros2 run turtlesim turtlesim_node 启动海龟模拟器,可通过 ros2 node list 查看节点名字,再通过 ros2 node info /turtlesim 查看节点的详细信息,包括节点的发布和订阅等。可以看出 /turtle1/pose 是小海龟的实时位姿信息 ros2 topic echo /turtle1/pose。也可以通过 ros2 topic info xx 来查看是订阅者还是发布者。
可以查看每个节点下的话题信息,比如 ros2 topic info /turtle1/cmd_vel,对于显示的 type 类型,则用 ros2 interface show geometry_msgs/msg/Twist,对此,则是显示了角速度和线速度的信息。
结合以上信息,我们就可以向其进行发布数据,控制海龟移动。ros2 topic pub /turtle1/cmd_vel geometry_msgs/msg/Twist "{linear: {x: 0.5, y: 0.0}, angular: {z: 0.0}}" (数据格式是 yaml 格式!)

通过话题发布小说

需求:下载小说并通过话题间隔5s发布一行。
同样地,接下来用以下命令创建功能包:

ros2 pkg create demo_python_topic --build-type ament_python --dependencies rclpy example_interfaces --license Apache-2.0
colcon build

可以看到本次指令中多了依赖(dependencies)这一项,可以在 package.xml 中看到:

<depend>rclpy</depend>
<depend>example_interfaces</depend>

在终端中输入 ros2 interface list | grep example_interfaces 可以看到引入了 example_interfaces/msg/String 的消息类型,进一步地,可以用 ros2 interface show example_interfaces/msg/String查看具体信息。

编写以下脚本:

import requests
from queue import Queue

import rclpy
from rclpy.node import Node

  
class NovelPubNode(Node):

	def __init__(self, node_name):
		super().__init__(node_name)
		self.get_logger().info(f'{node_name} 启动!')
		self.novel_queue = Queue() # 创建队列
		# 创建一个定时器
		self.create_timer(5, callback=self._timer_callback) # 时间周期(s),回调函数
		# 创建一个发布者
		self.novel_publisher = self.create_publisher(String, 'novel', 10) # 消息类型,话题名字,QoS配置
		
	def _timer_callback(self):
		if self.novel_queue.qsize() > 0:
			line = self.novel_queue.get()
			msg = String()
			msg.data = line
			self.novel_publisher.publish(msg)
			self.get_logger().info(f'发布了:{msg}')

	def download(self, url):
		response = requests.get(url)
		response.encoding = 'utf-8'
		text = response.text
		self.get_logger().info(f'下载{url},{len(text)}')
		for line in text.splitlines():
			self.novel_queue.put(line)
	
	def main():
		rclpy.init()
		node = NovelPubNode('novel_pub')
		node.download('http://0.0.0.0:8000/novel1.txt')
		rclpy.spin(node)
		rclpy.shutdown()

仍不要忘记在 setup.py 中添加以下信息

entry_points={
	'console_scripts': [
		'novel_pub_node=demo_python_topic.novel_pub_node:main',
	],
},

在这之后运行代码,请不要忘记:

colcon build
source install/setup.bash
ros2 run demo_python_topic novel_pub_node

可以通过以下命令检查是否成功发送内容:

ros2 topic list # 查看是否有novel话题
ros2 topic echo /novel # 输出话题内容
ros2 topic hz /novel # 输出话题频率

订阅小说并合成语音

需求:订阅小说并逐行朗读。
通过以下命令安装 espeakng:

pip install espeakng
sudo apt install espeak-ng

注:如果是用 anaconda,需要修改 PYTHONPATH 系统变量,或者采取:

pip install colcon-common-extensions catkin_pkg lark

编写以下脚本实现订阅和合成语音,采用 espeakng 作为 TTS:

import time
import threading
import espeakng
from queue import Queue


import rclpy
from rclpy.node import Node
from example_interfaces.msg import String

  
class NovelSubNode(Node):
	def __init__(self, node_name):
		super().__init__(node_name)
		self.get_logger().info(f'{node_name} 启动!')
		self.novel_queue = Queue()
		self.speech_thread_ = threading.Thread(target=self.speaker_thread)
		self.novel_subscriber = self.create_subscription(String, 'novel', self._novel_callback, 10)
		self.speech_thread_.start()
	
	def _novel_callback(self, msg):
		self.novel_queue.put(msg.data)
	
	def speaker_thread(self):
		speaker = espeakng.Speaker()
		speaker.voice = 'zh'
	
		while rclpy.ok(): # 检测当前ros上下文是否ok
			if self.novel_queue.qsize() > 0:
				text = self.novel_queue.get()
				self.get_logger().info(f'朗读:{text}')
				speaker.say(text) # 说
				speaker.wait() # 等待说话完毕
			else:
				# 当前的线程休眠
				time.sleep(1)

def main():
	rclpy.init()
	node = NovelSubNode('novel_sub')
	rclpy.spin(node)
	rclpy.shutdown()

Reference

  1. B 站视频
  2. 鱼香ros论坛
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值