simple_navigation
Simple_navigation
本项目基于:
- RTK
- IMU
- 单线激光雷达
- 闭环控制akm底盘
实现基于多传感器数据融合的导航算法。
1. akm底盘控制
akm小车采用坐标系:
1.1 上位机串口控制
ROS主控发布控制话题:/cmd_vel
,消息类型:geometry_msgs::Twist
,采用串口通讯进行控制,串口数据:
short transition; //中间变量 |
值得注意的是:
小车采用的西北天坐标系。
akm小车只需要进行X轴速度以及Z轴转角控制。
1.2 下位机指令解算
对ROS发出的指令,下位机主控需要解算到对应电机及转向舵机上。
后轮驱动电机解算:
void Drive_Motor(float Vx, float Vz) |
转向角度:
Angle_Servo = -0.2137*pow(AngleR, 2) + 1.439*AngleR + 0.009599; |
由舵盘转角与转向角度的关系,进行二次曲线拟合得到关系式,再采用PWM控制方式。
2. 坐标系
2.1 地理坐标系
2.1.1 ECEF坐标系
ECEF是一个三维直角坐标系,用于描述地球表面上任何一点的三维坐标:
- 坐标系原点: 地球的质心
- X轴:指向赤道平面与本初子午线的交点,即经度为0°,纬度为0°的点
- Y轴::位于赤道平面内,指向经度为90°的点
- Z轴:指向地理北极
ECEF坐标系使用三维直角坐标(X, Y, Z)
来表示地球表面上的任意点位置。
2.1.2 wgs84坐标系
wgs84是导航常用坐标系,其定义了地球的形状、大小、重力场以及其在空间中的位置:
- 椭球模型::wgs84定义了地球的形状为一个椭球,具有特定的长半轴和扁率
- 坐标系::wgs84使用地理坐标(纬度、经度和椭球高度)来表示地球表面上的点
- 纬度: 相对于地球赤道平面的角度,表示南北方向的位置
- 经度: 相对于本初子午线的角度,表示东西方向的位置
- 高度: 高度是相对于wgs84参考椭球面的垂直距离
我们经常说的LLA就是指的:经度、维度、海拔
2.1.3 ENU坐标系
这是两种常用的导航局部坐标系:东北天(ENU)、东北地(END)
ENU:
- X轴:E,朝向地理东
- Y轴:N,朝向地理北
- Z轴:U,朝向天
- 欧拉角顺序:Z-X-Y
往往ENU和END坐标系是wgs84坐标给定原点位置。
2.2 欧拉角与四元数
欧拉角:用三个角描述物体姿态,一般取自绕三个固定轴的旋转角,假如在END坐标系下:
- Yaw(偏航角)
- Pitch(俯仰角)
- Roll(滚转角)
欧拉角的正负遵循右手定则:伸出右手,大拇指指向旋转轴的正方向,四指弯曲的方向就是旋转的正方向。
欧拉角的旋转顺序很重要,上述坐标系的旋转顺序:Z-Y-X
,即先绕Z轴旋转Yaw,再绕Y轴旋转Pitch,最后绕X轴旋转Roll
具有不连续、万向锁的问题。
四元数:一种基于超复数的数学结构,用于表示旋转
q=w+xi+yj+zkq = w + xi + yj + zkq=w+xi+yj+zk
通常表示为一个四元组(w, x, y, z)
,其中w
是实部,x
、y
、z
是虚部。四元数也可以表示为一个旋转轴和一个旋转角度。
之间的转换:
|
3. RTK的使用
3.1 固定设备号
由于串口设备拔插后端口号会改变,故需要对RTK设备(一般是转USB)进行起别名。
查看串口信息:lsusb
,得到设备识别码:
新建shell脚本:touch rtk_udev.sh
,内容如下:
设置变量 |
添加可执行属性:sudo chmod +x rtk_udev.sh
,
重新拔插设备,执行:sudo ./rtk_udev.sh
:
3.2 RTK驱动
RTK设备一般都支持nmea0184数据格式,需要以下报文信息:
- GPGGA:包含位置信息,
AT+GPGGA=5\r\n
- GPVTG:包含速度信息,
AT+GPVTG= 1\r\n
- GPHDT:包含定向的朝向信息,
AT+GPHDT= 1\r\n
安装:sudo apt install ros-noetic-nmea-navsat-driver
编辑启动文件:sudo nano /opt/ros/noetic/share/nmea_navsat_driver/launch/nmea_serial_driver.launch
<launch> |
执行:roslaunch nmea_navsat_driver nmea_serial_driver.launch
此时发布的
/fix
话题为sensor_msgs/NavSatFix类型,其中gps信号为wgs84坐标系。
3.3 gps_common
将sensor_msgs/NavSatFix 转为 sensor_msgs/Odometry
安装:
git clone -b foxy-eol --single-branch https://github.com/swri-robotics/gps_umd.git |
4. IMU的使用
4.1 固定设备号
首先,如果IMU与RTK使用的同一通讯芯片,如:CP2102,需要更改设备序列号。
新建shell文件:imu_udev.sh
,内容如下:
设置变量 |
重新拔插:
4.2 imu驱动
驱动采用官方驱动包:fdilink_ahrs
,启动文件:roslaunch fdilink_ahrs ahrs_data.launch
:
<launch> |
编译后,执行:
如果想要实现imu输出ENU下数据,魔改代码:
// NED->ENU : x=y y=x z=z |
也可以用tf静态发布:
<node pkg="tf" type="static_transform_publisher" name="tf_imu_ned_enu" args="0 0 0 1.5708 0 3.1416 imu_link_ned imu_link 10" output="screen"/> |
使用转换后的数据:
tf2_.reset(new tf2_ros::Buffer()); // 创建tf2_ros::Buffer对象,储存在tf2_中 |
注意:
- 该imu自带九轴滤波融合
- 注意绝对航向和相对航向问题
- 数据漂移,请校准
4.3 imu_transformer
作用:
- 创建imu数据从一坐标系到另一坐标系的静态发布
- 计算转换后的坐标信息
下载:
git clone -b master --single-branch https://github.com/ros-perception/imu_pipeline.git |
假设imu固定坐标系为NED,转为ENU,则父坐标为NED,子坐标为ENU,创建和计算如下:
<node pkg="tf" type="static_transform_publisher" name="tf_imu_ned_enu" args="0 0 0 1.5708 0 3.1416 imu_link_ned imu_link 10" output="screen"/> |
注意mag(磁力计)消息类型要求。
4.4 imu_tools
其提供三个节点:
- imu_filter_madgwick:融合imu角速度、线加速度、磁力计(可选)生成带
orientation
的imu数据 - imu_complementary_filter:采用补偿融合的方式生成带
orientation
的imu数据 - rviz_imu_plugin:imu Rviz可视化
下载:
git clone -b noetic --single-branch https://github.com/CCNYRoboticsLab/imu_tools.git |
上述imu自带多轴数据融合,不再进行融合。
5. multi-sensor fusion
5.1 robot_localization
下载:
git clone -b noetic-devel --single-branch https://github.com/cra-ros-pkg/robot_localization.git |
依赖:
sudo apt-get install ros-noetic-roslint |
robot_localization支持连续状态估计、任意数量传感器数据融合、自定义传感器输入数据剔除等功能,其提供的状态估计节点有:
- ekf_localization_node
- ukf_localization_node
- navsat_transform_node
观察其逻辑框图:
用于融合:轮式里程计、imu、gps
编辑启动文件,robot_localization.launch
:
<launch> |
编辑配置参数,dual_ekf_navsat_example.yaml
:
# imu、轮式里程计融合 |
5.2 imu_gnss_eskf
该项目旨在实现一个误差状态卡尔曼滤波器(ESKF)算法,用于融合 IMU 和 GNSS 数据。
安装依赖项:
sudo apt-get install libeigen3-dev |
查询路径下cmake版本号,然后替换下面的**:
sudo ln -s /usr/share/cmake/geographiclib/FindGeographicLib.cmake /usr/share/cmake-3**/Modules/ |
sudo ln -s:创建符号链接,sudo ln -s [目标文件或目录] [链接名称]
修改imu_gnss_eskf_node.cpp
文件,新增参数,更改父坐标系与子坐标系,并添加动态广播。
... |
编译通过,修改启动文件:roslaunch imu_gnss_eskf imu_gnss_eskf.launch
:
<launch> |
其产生的话题:
/fix ## 接收RTK话题,sensor_msgs/NavSatFix |
实际融合:
5.3 robot_pose_ekf
这也是一个多传感器融合包:
- 轮式里程计
- imu
- gps
下载:
git clone https://github.com/udacity/robot_pose_ekf.git |
其订阅的话题:
对于轮式里程计不作介绍,一般由机器人底盘上的电机编码器得到,对于imu可以直接使用上述imu。
而对于gps传感器而言,上述RTK提供的gps为sensor_msgs/NavSatFix
类型,需要将其转换。
5.4 imu_gps_localization
该包维护位置、速度、方向、加速度和陀螺的bias,实现:将wgs84坐标系下的gps转为ENU坐标系下与imu进行融合。
下载:
git clone https://github.com/ydsf16/imu_gps_localization.git |
依赖:
sudo apt-get install libgoogle-glog-dev |
查看话题:
这个包显然只是将gps与imu融合得到轨迹跟踪数据。
5.5 rtk_odom
基于带航向信息的RTK里程计设计:
开启nmea数据流:
- GPGGA
- GPVTG
nmea驱动包:nmea_navsat_driver
- 话题:/fix,消息类型:sensor_msgs/NavSatFix
- 话题:/heading,消息类型:geometry_msgs/QuaternionStamped
新建rtk_odom
包,代码如下:
|
编辑launch文件:
<launch> |
查看效果:
不推荐这种,RTK航向信息太不稳定了。
6. rviz查看卫星地图
下面介绍两种卫星地图的查看方式。
6.1 rviz_satellite
安装:
git clone -b ros1 --single-branch https://github.com/nobleo/rviz_satellite.git |
打开launch目录下的demo.gps
文件,修改经纬度,填入起始经纬度信息。
运行:roslaunch rviz_satellite demo.launch
修改AerialMapDisplay:
选项 | 含义 |
---|---|
Topic | 接受gps话题,消息类型:sensor_msgs/NavSatFix |
Robot frame | 机器人坐标系 |
Dynamically reload | 当机器人移出中心块时,将导致图像重新加载,这仅在 TF 正确指定机器人框架时才有效 |
Alpha | 透明度 |
Draw Under | 将地图显示在所有其他几何体下方 |
Zoom | 地图缩放级别,推荐16-19,最大22 |
Blocks | 加载的相邻块数,将加载中心块,以及中心周围的许多块,最大值8 |
Frame Convention | X/Y 轴的约定,默认XYZ 映射到 ENU |
Object URI | 地图API接口 |
简单URL:
https://maps.wikimedia.org/osm-intl/{z}/{x}/{y}.png # 最简陋 已经停用了 |
付费:
TomTom: https://api.tomtom.com/map/1/tile/basic/main/{z}/{x}/{y}.png?tileSize=512&key=[TOKEN] |
查看效果:
6.2 mapviz
快速安装:
sudo apt-get install ros-noetic-mapviz ros-noetic-mapviz-plugins ros-noetic-tile-map ros-noetic-multires-image |
下载:
git clone -b melodic-eol --single-branch https://github.com/swri-robotics/mapviz.git |
没发现noetic版本的,但melodic版本在noetic下编译通过。
安装依赖:
rosdep install --from-paths src --ignore-src |
修改mapviz.launch
中的经纬度,地图将以该中心加载地图。
<launch> |
启动:
roslaunch mapviz mapviz.launch |
天地网申请URL:
http://t0.tianditu.gov.cn/img_w/wmts?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=img&STYLE=default&TILEMATRIXSET=w&FORMAT=tiles&TILEMATRIX={level}&TILEROW={y}&TILECOL={x}&tk=f6c42d6c77ed827abe977452a23c2732 |
查看效果:
7. 导航
整个导航是基于ROS Navigation Stack的,安装:
git clone https://github.com/ros-planning/navigation.git |
默认版本:noetic,melodic:
git clone -b melodic-devel --single-branch https://github.com/ros-planning/navigation.git
。
安装依赖项:
sudo apt-get install ros-noetic-navigation* |
最好不要用rosdep,rosdep安装与其它包存在冲突。
编译:catkin_make
。
基于ROS Navigation Stack进行导航,大致思路:
- map_server加载全局地图,以map为全局坐标系
- 将odom原点与map重合,odom子坐标系为base_link,base_link与laser_link坐标系为静态坐标系
- 启动雷达,得到点云信息
- 启动move_base
- 局部规划由move_base完成
- 发送导航路径
- ok
7.1 创建地图
新建一个ros包:pgm_generator
,代码如下:
|
这个文件依赖 roslib包,但不能targetlink。
编写launch文件:
<launch> |
该地图还可以使用ps进行修改,后续进阶可以使用雷达、视觉建图生成。
7.2 map_server
map_server作用:
- 加载地图文件,转为地图话题信息发布。
- 保存地图。
这里只用前者,使用map_server加载地图文件,需要配置地图描述文件,新建_map_config.yaml
文件:
image: /home/.../blank_map.pgm ## 地图文件 |
一般map_server的使用结合整个launch文件设计:
<arg name="map_file" default="$(find simple_navigation)/map/_map_config.yaml" /> |
map_server:
- 发布话题:/map
- 消息类型:nav_msgs/OccupancyGrid
- 发布话题:/map_metadata
- 消息类型:nav_msgs/MapMetaData
查看效果:
7.3 雷达的使用
7.3.1 单线雷达
lidar:M10 Navigation & Obstacle Avoidance LiDAR | Leishen 2D LiDAR Supplier (lslidar.com)
雷达固定ip:192.168.1.102,端口:2368
安装依赖:
sudo apt-get install ros-$ROS_DISTRO-pcl-ros ros-$ROS_DISTRO-pluginlib ros-$ROS_DISTRO-pcl-conversions ros-$ROS_DISTRO-diagnostic-updater |
移植驱动,编译:
catkin_make -DCATKIN_WHITELIST_PACKAGES="lslidar_msgs" |
运行:roslaunch lslidar_driver lslidar_net.launch
<launch> |
查看话题:
- /scan:雷达数据
- /lslidar_order:雷达控制
对于雷达控制:
#M10 M10_GPS M10_PLUS N10 N10_PLUS 雷达 |
7.3.2 多线雷达
雷达:32/16-Line Mechanical LiDAR | Leishen Intelligent System (lslidar.com)
雷达固定ip:192.168.1.102,端口:2368
安装依赖:
sudo apt-get install ros-$ROS_DISTRO-pcl-ros ros-$ROS_DISTRO-pluginlib ros-$ROS_DISTRO-pcl-conversions |
移植驱动,编译:
catkin_make -DCATKIN_WHITELIST_PACKAGES="lslidar_msgs" |
运行:roslaunch lslidar_cx_driver lslidar_c16.launch
<launch> |
查看话题:
- /lslidar_point_cloud:点云话题
- /laserscan:指定线束的数据,默认10
雷达控制:
source devel/setup.bash |
虽然该雷达提供了可选laserscan话题,但:
- pointcloud_to_laserscan提取3d点云信息中与地面平行的那一层,用作下位机导航和避障。
pcl点云转scan:
下载:
git clone -b foxy --single-branc https://github.com/ros-perception/pointcloud_to_laserscan.git |
调整对应启动文件:pointcloud_scan.launch
<?xml version="1.0"?> |
7.3.3 laser_filters
用来滤除sensor_msgs/LaserScan
类型的雷达数据,可支持:
- Range Filter:范围滤波
- Angular Filter:角度滤波
- Intensity Filter:强度滤波
- Median Filter:中值滤波
- Shadow Filter:阴影滤波
- Bounding Box Filter:界限滤波
- Jump Distance Filter:跳点滤波
- Scan to Scan Filter Chain:复合滤波
下载:
git clone -b noetic-devel --single-branch https://github.com/ros-perception/laser_filters.git |
本处使用:Bounding Box Filter
scan_filter_chain: |
7.3.4 gampping
这是一种建图算法。
下载:
git clone https://github.com/ros-perception/openslam_gmapping |
7.4 odom
7.4.1 坐标系转换
ROS中坐标系的转换:
<!-- 静态TF1 --> |
参数含义:x偏移量 y偏移量 z偏移量 z偏航角度 y俯仰角度 x翻滚角度 父级坐标系 子级坐标系 发布频率
7.4.2 urdf
在rviz中显示车体外型:
<!-- URDF 标准化机器人描述格式 --> |
其中 akm_robot.urdf :
<?xml version="1.0" ?> |
7.4.3 nav里程计
7.5 move_base
订阅的话题:
话题名称 | 消息类型 | 作用 |
---|---|---|
/move_base_simple/goal | geometry_msgs/PoseStamped | 提供目标点 |
/odom | nav_msgs/Odometry | 参考位移 |
/scan | sensor_msgs/LaserScan or sensor_msgs/PointCloud | 检测障碍物,进行避障 |
/map | nav_msgs/OccupancyGrid | map_server加载地图,并发布话题 |
/tf | tf2_msgs/TFMessage | 跟踪和广播不同坐标系变换关系 |
/initialpose | geometry_msgs/PoseWithCovarianceStamped | 提供机器人在地图中的初始位置,用于初始化定位模块 |
发布话题:
- 话题名称:/cmd_vel
- 消息类型:geometry_msgs/Twist
- 作用:导航栈输出的速度指令,用于控制机器人的运动
7.5.1 launch
选择使用动态避障效果更好的teb局部规划器。
安装:
sudo apt update |
move_base核心,参数文件加载:
<!-- move_base核心 --> |
下面进行move_base的参数文件加载,参数文件有:
- move_base_params.yaml
- local_costmap_params.yaml
- global_costmap_params.yaml
- local_planner_param.yaml
- global_planner_param.yaml
- costmap_common_params.yaml
7.5.2 move_base_params
move_base_params.yaml:负责move_base基本设置
#设置全局路径规划器 |
7.5.3 local_costmap_params
local_costmap_params.yaml:特定局部代价地图参数设置
#局部代价地图参数命名空间 |
7.5.4 global_costmap_params
global_costmap_params.yaml:特定全局代价地图参数设置
#全局代价地图参数命名空间 |
7.5.5 local_planner_param
local_planner_param.yaml:局部规划器参数设置
#局部路径规划器TebLocalPlannerROS命名空间 |
7.5.6 global_planner_param
global_planner_param.yaml:全局规划器参数设置
#全局路径规划器GlobalPlanner命名空间 |
7.5.7 costmap_common_params
costmap_common_params.yaml:代价地图通用参数设置
# 圆形机器人的外形设置,直接设置其外形半径 |
7.6 多点导航
move_base提供了MoveBaseAction消息接口可实现多点导航。
7.6.1 巡线打点
导航点可以来自多个方面,下面给出巡线自动记录点位和姿态的代码,并保存在nav_data/map/nav_goals.csv
中。
7.6.2 多点导航
新建pub_goals
包:
|
7.7 导航
新建nav.launch
文件:
<launch> |