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.txt、echo "第二章 学习修仙,马上升天" > novel2.txt和echo "第三章 女大三千,位列仙班" > 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()
1249

被折叠的 条评论
为什么被折叠?



