项目场景:
ROS2 foxy 小车 传感器融合
*本文编写规则
1、大写斜体 需替换为自定义名称
相关命令
1、节点启动
遥控控制
ros2 launch wheeltec_joy wheeltec_wire_joy.launch.py
动作捕获定位
ros2 launch vrpn_client_ros sample.launch.py
ros2 run fusion Mocap_node
底盘运动+寻磁
ros2 run chassis_control Car_control
ros2 run chassis_magnetic magnetic
ros2 run pid_c pid
ros2 launch ums_fiction_driver ums_fiction_v1.launch.py
寻磁启止
ros2 topic pub /Turn std_msgs/msg/Int8 data:\ 1
ros2 topic pub /Turn std_msgs/msg/Int8 data:\ 0
RFID
ros2 run data_publishing rfid
imu
ros2 run chassis_control car_motion_control
ros2 run data_publishing imu
UWB
ros2 run fusion UWB_node
融合定位
ros2 run fusion fusion_node
轨迹追踪
ros2 run path_track mpc_tracker
ros2 run path_track stanley_tracker
雷达建图
~/map_ws$ ros2 launch sllidar_ros2 sllidar_a1_launch.py
2、ROS2安装配置
(1) ROS2
ros2一键安装:wget http://fishros.com/install -O fishros && . fishros
ros2一键卸载:sudo apt remove ros-foxy-* && sudo apt autoremove
查看ros版本号:rosversion -d
创建工作空间
mkdir -p town_ws/src
cd town_ws/src
创建python功能包
ros2 pkg create <package_name> --build-type ament_python --dependencies rclpy
(2) 工具
1、RQT安装:
sudo apt-get install ros-$ROS_DISTRO-rqt
sudo apt install ros-$ROS_DISTRO-rqt*
2、rviz IMU插件:
sudo apt-get install ros-$ROS_DISTRO-imu-tools
3、python库安装:
pip install pyserial
pip install heapdict
(3) 更新环境变量
更新工作空间环境变量(每次build后都要)
source ./install/setup.bash
将source写入系统全局变量(build后自动source)
echo “source /home/用户名/文件夹/install/setup.bash” >> ~/.bashrc
source ~/.bashrc
(4) 指定源安装
-i https://pypi.tuna.tsinghua.edu.cn/simple some-package
(5) 编译指令
全局编译: colcon build
单独编译: colcon build --packages-select PACKAGE_NAME
python 静态链接编译 :colcon build --symlink-install
(6) 串口绑定
1、查看串口详细信息
$ udevadm info --attribute-walk --name=/dev/ttyUSB1 |grep KERNELS
>>>
KERNELS==“ttyUSB1”
KERNELS==“2-1.2.2:1.0”
KERNELS==“2-1.2.2”
KERNELS==“2-1.2”
KERNELS==“2-1”
KERNELS==“usb2”
KERNELS==“fc880000.usb”
KERNELS==“platform”
2、绑定串口(串口重命名)
$ sudo vim /etc/udev/rules.d/robotbase_port.rules
ACTION==“add”,KERNELS==“2-1.3.1:1.0”,SUBSYSTEMS==“usb”,MODE:=“0777”,SYMLINK+=“com_car”
3、重载串口
$ service udev reload
$ service udev restart
重新拔插串口
( ( 1.78 - 0.455 ) ^ 2 + 1.2 ^ 2 ) ^ ( 0.5 )
3、测试
(1) rosbag记录器
记录全部话题 ros2 bag record -a
命名记录文件并挑选记录话题 ros2 bag record -o BAG-NAME /PACKAGE-NAME
播放纪录包并指定话题 ros2 bag play BAG-NAME --topics /PACKAGE-NAME
查看纪录包详情 ros2 bag info BAG-NAME
ros2 bag record -o RosbagRecord /test_car_1 /imu /uwb_distance /rfid_data /car1_Marker3/pose /Fused/pose /Mocap/pose /Fused/path /Mocap/path /Error
(2) 计算器欧式距离公式
((4.2−0.6)2+(4.8−1.2)2+(0.52−0.29)2)0.5
(3) ros系统桌面UI foxglove
1.启动桥:ros2 launch foxglove_bridge foxglove_bridge_launch.xml
2.打开foxglove studio
4、常用指令
(1) 话题相关
查看话题列表: ros2 topic list
查看话题列表及消息类型:ros2 topic list -t
订阅话题:ros2 topic echo TOPIC_NAME
查看话题频率:ros2 topic hz TOPIC_NAME
查看话题详情 (消息类型和发布者/订阅者的数量): ros2 topic info TOPIC_NAME
(2) 消息相关
查看消息定义:ros2 interface show geometry_msgs/msg/PoseStamped
5、ubuntu快捷指令
(1) linux 命令行指令
查看所有历史命令:history
查看包含关键词‘KEYWORD‘历史命令:history |grep KEYWORD
根据序号选择命令并执行:!001
查找包含输入字符的历史命令:ctrl R
(2)主目录查看隐藏文件(.bashrc)
ctrl H
Debug记录
编译问题
Q1、功能包编译 部分代码在install下不更新
python:将python功能包做静态链接 colcon build --symlink-install
c++:删除install 、build文件夹重新编译
Q2、找不到依赖功能包编译失败
方法一:先单独编译依赖功能包再全局编译 编译完后更新环境变量
colcon build --packages-select car_interfaces
colcon build
source ./install/setup.bash
colcon build --symlink-install
方法二:修改功能包的 package.xml 文件和 CMakeLists.txt 文件
在ROS2中,如果一个包(例如B_package)依赖于另一个包(例如A_package),需要在B_package的package.xml和CMakeLists.txt文件中声明这种依赖关系。
1.修改 package.xml 文件
在 package.xml 文件中,你需要添加 标签来声明对 A_package 的依赖。例如:<package format="3"> <name>B_package</name> <!-- 其他元数据... --> <depend>A_package</depend> <!-- 其他依赖... --> </package>
2.修改 CMakeLists.txt 文件
需要在 find_package() 方法中添加 A_package 这个依赖。例如:cmake_minimum_required(VERSION 3.5) project(B_package) # Default to C99 if(NOT CMAKE_C_STANDARD) set(CMAKE_C_STANDARD 99) endif() # Default to C++14 if(NOT CMAKE_CXX_STANDARD) set(CMAKE_CXX_STANDARD 14) endif() find_package(ament_cmake REQUIRED) find_package(A_package REQUIRED) # 添加这行代码 \# 其他的 'find_package' 调用... \# 剩下的 CMakeLists.txt 内容...
同时,如果你在 B_package 中使用了 A_package 的消息,则还需要在 add_dependencies() 方法中添加目标依赖。例如,如果你创建了一个名为 my_node 的可执行文件,那么应该这样做:
add_executable(my_node src/my_node.cpp) ament_target_dependencies(my_node A_package) # 添加这行代码
使用这种方法,Ament工具(ROS 2的构建系统)将首先构建A_package,然后再构建B_package。
方法三:使用–packages-up-to命令,找到并编译所有依赖后再编译该包
colcon build --packages-up-to cartographer_ros
Q3、时钟错误编译失败
cmake会先查看文件的最新修改时间,跟log记录的时间比较决定是否进行更新。可以将系统设置为自动更新时间,或者输入命令强制更新时间
sudo date -s ‘2023-11-09 15:47:00’
Q4、python静态链接编译通过却无法rosrun
Traceback (most recent call last):
File "/home/cat/agv_ws/install/fusion/lib/fusion/testHZ_node", line 33, in <module>
sys.exit(load_entry_point('fusion', 'console_scripts', 'testHZ_node')())
File "/home/cat/agv_ws/install/fusion/lib/fusion/testHZ_node", line 22, in importlib_load_entry_point
for entry_point in distribution(dist_name).entry_points
File "/usr/lib/python3.10/importlib/metadata/__init__.py", line 969, in distribution
return Distribution.from_name(distribution_name)
File "/usr/lib/python3.10/importlib/metadata/__init__.py", line 548, in from_name
raise PackageNotFoundError(name)
importlib.metadata.PackageNotFoundError: No package metadata was found for fusion
[ros2run]: Process exited with failure 1
colcon build --symlink-install默认不执行soure,需要手动source一下环境。
source ./install/setup.bash
分布式测试问题
Q1、不同设备话题冲突混乱
在同一局域网下域ID可能相同,导致设备能互相接收话题,可以为每一个设备修改域ID
#进入设备用户根目录
vim .bashrc
在bash文件最后输入设置域ID命令,每个设备的ID号都要不一样
export ROS_DOMAIN_ID=XXX
最后更新用户环境变量
source .bashrc
Q2、ROS1和ROS2共存坑
- 启动终端选择ROS版本时会默认执行一次 source ~/.bashrc 。因此如果在系统全局变量.bashrc中添加了对ros1工作空间环境的source bash,如:source /home/dn/ROS1_Project/UAV_ws/devel/setup.bash,则会将部分全局变量设置为ROS1环境,导致ROS2运行出问题,反之同理。
Q3、code-server安装
ubuntu 20.04 code-server 安装
1、code-server github上下载deb文件
![架构区别
2、安装
dpkg -i code-server_4.2.0_amd64.deb
3、运行一次,生成配置文件
code-server
4、关闭程序,修改配置文件
vim ~/.config/code-server/config.yaml
bind-addr改为0.0.0.0并设置需要的端口(8080),更改password(abcd)
5、开启服务
sudo systemctl start code-server@username
6、开机自启
sudo systemctl enable --now code-server@$USER
Q4、rqt启动异常
ros/ros2同样的报错:
Traceback (most recent call last):
File "/opt/ros/noetic/bin/rqt", line 13, in <module>
sys.exit(main.main())
File "/opt/ros/noetic/lib/python3/dist-packages/rqt_gui/main.py", line 61, in main
return super(
File "/opt/ros/noetic/lib/python3/dist-packages/qt_gui/main.py", line 407, in main
from python_qt_binding import QT_BINDING
File "/opt/ros/noetic/lib/python3/dist-packages/python_qt_binding/__init__.py", line 55, in <module>
from .binding_helper import loadUi, QT_BINDING, QT_BINDING_MODULES, QT_BINDING_VERSION # @UnusedImport
File "/opt/ros/noetic/lib/python3/dist-packages/python_qt_binding/binding_helper.py", line 277, in <module>
_select_qt_binding(
File "/opt/ros/noetic/lib/python3/dist-packages/python_qt_binding/binding_helper.py", line 111, in _select_qt_binding
QT_BINDING_VERSION = binding_loader(required_modules, optional_modules)
File "/opt/ros/noetic/lib/python3/dist-packages/python_qt_binding/binding_helper.py", line 158, in _load_pyqt
_named_optional_import('PyQt5.%s' % module_name)
File "/opt/ros/noetic/lib/python3/dist-packages/python_qt_binding/binding_helper.py", line 145, in _named_optional_import
_named_import(name)
File "/opt/ros/noetic/lib/python3/dist-packages/python_qt_binding/binding_helper.py", line 136, in _named_import
module = builtins.__import__(name)
ValueError: PyCapsule_GetPointer called with incorrect name
参考:运行rqt报错PyCapsule_GetPointer called with incorrect name解决办法
1、找到文件位置
ROS :
/opt/ros/noetic/lib/python3/dist-packages/python_qt_binding.binding_helper.py
ROS2:
/opt/ros/foxy/lib/python3.8/site-packages/python_qt_binding.binding_helper.py
2、打开文件
只读文件需要sudo权限才能修改
sudo vim binding_helper.py
3、修改文件
把QtWebKitWidgets注释
#‘QtWebKitWidgets’, # Qt 5.0 - 5.5
4、结果
可以打开rqt 但是仍然会报错 不影响使用
RosPluginProvider.load(qt_gui_cpp/CppPluginProvider) exception raised in __builtin__.__import__(qt_gui_cpp.cpp_plugin_provider, [CppPluginProvider]):
Traceback (most recent call last):
File "/opt/ros/foxy/lib/python3.8/site-packages/rqt_gui/ros_plugin_provider.py", line 80, in load
module = __builtin__.__import__(
File "/opt/ros/foxy/lib/python3.8/site-packages/qt_gui_cpp/cpp_plugin_provider.py", line 33, in <module>
from .cpp_binding_helper import qt_gui_cpp
File "/opt/ros/foxy/lib/python3.8/site-packages/qt_gui_cpp/cpp_binding_helper.py", line 43, in <module>
from . import libqt_gui_cpp_sip
ValueError: PyCapsule_GetPointer called with incorrect name
RecursivePluginProvider.discover() loading plugin "qt_gui_cpp/CppPluginProvider" failed:
Traceback (most recent call last):
File "/opt/ros/foxy/lib/python3.8/site-packages/qt_gui/recursive_plugin_provider.py", line 60, in discover
instance = self._plugin_provider.load(plugin_descriptor.plugin_id(), None)
File "/opt/ros/foxy/lib/python3.8/site-packages/rqt_gui/ros_plugin_provider.py", line 91, in load
raise e
File "/opt/ros/foxy/lib/python3.8/site-packages/rqt_gui/ros_plugin_provider.py", line 80, in load
module = __builtin__.__import__(
File "/opt/ros/foxy/lib/python3.8/site-packages/qt_gui_cpp/cpp_plugin_provider.py", line 33, in <module>
from .cpp_binding_helper import qt_gui_cpp
File "/opt/ros/foxy/lib/python3.8/site-packages/qt_gui_cpp/cpp_binding_helper.py", line 43, in <module>
from . import libqt_gui_cpp_sip
ValueError: PyCapsule_GetPointer called with incorrect name
ROS2教程
文件架构 (*表示自己创建的文件/文件夹)
workspace (工作空间)
|-> ...
|-> src
|-> mypackage (python类型功能包)
|-> mypackage (代码执行区)
|-> config (*参数文件夹,需要被调用)
|->__init__.py
|-> settings.py
|-> view (*功能文件夹,需要调用cofig包)
|->__init__.py
|-> plot.py
|-> src (*主功能文件夹,需要调用cofig包,自身文件夹内部也需要互相调用)
|->__init__.py
|-> model.py
|-> train.py
|->__init__.py
|-> main.py (*功能包下的文件,需要调用cofig包)
|-> launch (*lauch文件夹,批量启动节点)
|-> my.launch.py
|-> resource
|-> ...
|-> test
|-> ...
|-> package.xml
|-> setup.cfg
|-> setup.py (配置文件 告诉ros文件怎么组织)
文件示例
1、setup.py:向编译器说明功能包的组织架构
参考: python打包分发工具:setuptools
from setuptools import setup
from glob import glob
import os
# 给出python包的路径
package_name = 'mypackage'
src = 'mypackage/src'
cofig = 'mypackage/cofig'
view = 'mypackage/view'
setup(
name=package_name,
version='0.0.0',
packages=[package_name, src, cofig, view], # 在编译时把这几个文件夹都复制到install/mypackage/..下
data_files=[
('share/ament_index/resource_index/packages',
['resource/' + package_name]),
('share/' + package_name, ['package.xml']),
(os.path.join('share', package_name, 'launch'), glob('launch/*.launch.py')), # 给出launch文件路径
],
install_requires=['setuptools'],
zip_safe=True,
maintainer='nvidia',
maintainer_email='xxx@qq.com',
description='TODO: Package description',
license='TODO: License declaration',
tests_require=['pytest'],
entry_points={
'console_scripts': [
"main_node = fusion.main:main",
"train_node = fusion.src.train:main",
"view_node = fusion.view.plot:main",
],
},
)
2、导入自定义python包裹
# main.py导入settings.py
from .config import settings
# train.py导入model.py
from . import model
# train.py导入plot.py
from ..view import plot