组件 | 版本 | 组件 | 版本 |
---|---|---|---|
ubuntu | 18.04.5 | gazebo | 9.0.0 |
kernel | 5.4.0 | python2 | 2.7.17 |
nvidia driver | 460.73.01 | python3 | 3.6.9 |
opencv | 3.2.0 | g++ | 7.5.0 |
ROS | melodic |
使用如下命令安装所需依赖
rosdep install --from-paths src --ignore-src -r -y
如果遇到gazebo黑屏, 参考: gazebo打不开world的通用解决方法
1. topic 发送订阅
ROS
话题发布与订阅机示例
ROS
服务请求与应答示例
my_client_node
向 my_server_node
发送服务请求, my_server_node
视数据有效性决定是否拒绝服务
运行命令
roslaunch service_req_rep service_req_rep.launch
3. param 服务器
ROS
参数服务器示例, 与服务订阅联合示例
dynamic_configure_node
收到参数变化请求后调用 myParamDynamicSetCallServer
提供的服务
运行命令
roslaunch param_dynamic_set param_dynamic_set.launch
4. 小乌龟TF
TF
订阅、发布示例
通过键盘控制乌龟1位置, 乌龟2订阅TF树上乌龟1上参考点
相对于乌龟2
的变换, 乌龟2跟踪该变换并设法使变换归零. 跟踪目标可以通过start_demo.launch
修改
运行命令
roslaunch learning_tf start_demo.launch
5. 动作服务器
简单动作服务器示例
randNumGen
生成随机数发布到 randomNumber
话题, avgActionClient
设定目标并接受 avgActionServer 提供的反馈
运行命令
roslaunch action_server_client server_and_client_avg.launch
6. pluginlib
ROS
插件编写、注册机制示例与教程
pluginlib 利用面向对象编程的继承概念, 在基类
中定义方法, 在继承类
中实现
推荐使用公有继承
运行命令
roslaunch my_pluginlib_learning plugin_param_demo.launch
ROS中插件注册插件流程
-
编写
基类
和继承类
的头文件, 并使继承类
继承基类
的接口 -
新建
源文件
并分别添加基类
和继承类
的头文件、pluginlib/class_list_macros.h
头文件 -
在
源文件
中使用PLUGINLIB_EXPORT_CLASS(
继承类,
基类)
指定基类
和继承类
的关系 -
在 CMakeLists.txt 中添加如下代码以生成名为
lib插件名称.so
的动态链接库add_library(插件名称 源文件) target_link_libraries(插件名称 ${catkin_LIBRARIES})
-
新建
插件描述.xml
对插件继承关系进行描述<library path = "lib/lib插件名称"> <class name = "任意起一个名字" type = "继承类" base_class_type = "基类"> <description>继承类用途描述</description> </class> </library>
-
在
package.xml
中<export>
标签下添加如下代码, 将该插件注册到某一插件库中<插件库名称 plugin = "${prefix}/插件描述.xml"/>
-
编译后在终端中输入如下代码检查插件时否正确注册
rospack plugins --attrib=plugin 插件库名称
-
在源文件中使用
基类
生成继承类
实例, 查看plugin_caller.cpp查看具体使用方式, 生成继承类
既可以使用插件描述.xml
中定义的名字, 也可以使用继承类
名称
7. nodelet
pluginlib
的一种使用方式: nodelet
string_publisher
节点发布消息到 input
话题
nodelet_manager_1
下注册 subPubInstance1
、subPubInstance2
和 myNodeLetxx
节点管理器下挂节点通过管理器对外订阅或发布话题
运行命令
roslaunch my_nodelet_learning my_nodelet_launch.launch
nodelet 与 pluginlib 具有相似性
- 都需要继承于一个
基类
- 都需要在一个源文件中使用
PLUGINLIB_EXPORT_CLASS
宏 - 都需要在在
CMakeLists.txt
中声明add_library
- 都会生成动态链接库
- 都需要
插件描述.xml
- 都需要在
package.xml
中进行注册
不同点在于
-
nodelet 只能继承
nodelet::Nodelet
类 -
nodelet 运行时必须依托一个管理节点, 将不同 nodelet 注册到一个管理节点实现数据的指针传递
-
插件必须注册到
nodelet
库中 -
在 launch 文件中使用如下命令指定 nodelet 类型
load nodelet名 管理节点名称
注意
- nodelet 中使用
getPrivateNodeHandle()
获取私有节点控制权, 使用ros::NodeHandle
获取的是 nodelet 管理节点的控制权, 详情查看my_nodelet_register.cpp - 管理节点是一个抽象的节点, 不同类型的 nodelet 可以注册到一个管理节点上
- 管理器下挂所有节点均通过节点管理器与外界交流
- nodelet 可能支持服务, 但并未进行尝试
轨迹规划算法开发仿真包, 提供全剧规划与局部规划两种接口.
与 my_global_planner_plugin
与 my_local_planner_plugin
配合使用
使用经过北京邮电大学修改过的MIT模型
需要安装如下依赖(如果已经使用过本文件开头的命令, 可忽略)
sudo apt-get install ros-melodic-controller-manager
sudo apt-get install ros-melodic-gazebo-ros-control
sudo apt-get install ros-melodic-effort-controllers
sudo apt-get install ros-melodic-joint-state-controller
sudo apt-get install ros-melodic-driver-base
sudo apt-get install ros-melodic-rtabmap-ros
sudo apt-get install ros-melodic-teb-local-planner
sudo apt-get install ros-melodic-vesc*
sudo apt-get install ros-melodic-ackermann-*
sudo apt-get install ros-melodic-joystick-drivers
启动命令1:带键盘控制的最小化系统(无amcl
和move_base
)
roslaunch lasis_launch spawn_racecar.launch
启动命令2:在启动命令1
的基础上使用gmapping
算法建图
如需保存地图, 需在命令行中添加
save_map_option:=true
参数
roslaunch lasis_launch gmapping.launch
启动命令3:在启动命令1
的基础上使用move_base
节点进行规划, 使用amcl
定位, odom
由gazebo获取
如果要直接使用gazebo发布变换, 需在命令行中添加
use_amcl:=false
参数
暂时使用cmd_vel_to_ackermann_drive
节点作为ackermann_msgs
发布器
正在编写从nav_msgs::path
到ackermann_msgs
的节点
roslaunch lasis_launch navigation.launch
racecar中
ackermann_cmd_mux
模块负责处理不同优先级的阿克曼底盘速度指令
通过命名空间和nodelet划分为上下两个层级, 描述文件位于mux.launch
上层控处理不同优先级的导航控制命令并发送给下层
下层按照遥控
、安全
、导航
顺序处理底盘控制指令
上层输出到下层的导航控制指令通过relay
进行连接
ackermann_cmd_mux
模块允许自定义不同优先级的同数据类型话题
上层优先级定义文件为high_level_mux.yaml
下层优先级定义文件为low_level_mux.yaml
odom
指里程计, 可以理解为由编码器、惯导、GNSS、视觉里程计等传感器发布的消息信息, 经过航位推测法(Dead Reckoning)推算出的车辆相对于出发点位置, 通常使用robot_pose_ekf
节点对以上数据进行融合, 然后发布以/odom
为根节点, 以/base_link
为叶子节点的TF
变换.
由于
odom
不可避免的存在漂移(Odometry Drift), 需要使用车辆所在位置的局部信息如雷达点云/scan
等对该误差进行估计(校正).amcl
节点提供该算法,amcl
指自适应蒙特卡洛定位, 使用粒子滤波算法, 估计出车辆在地图中最可能的位置, 然后发布以/map
为根节点, 以/odom
为叶子节点的TF
变换, 对误差进行校正.
图片来源:answers.ros.org
启动命令3提供两种定位方法, gazebo定位与amcl定位, 其TF
树差异如下
待续
全局轨迹规划算法开发工具包, 提供测试工具、 rviz
接口、几种规划算法对比
需要与 move_base
, TF
配合使用, lasis_vehicle
已包含当前包功能
提供下列节点供测试
click_point_make_plan
使用 rviz 中发布点功能, 调用make_plan()
函数并发布路径kernelTest
直接调用myRosDijkstra
内核进行规划
提供下列全局路径规划器
myCarrot planner
起点指向终点的路径, 遇到障碍结束myAStar planner
基于像素的AStar
算法myDijkstra planner
基于像素的Dijkstra
算法myRosDijkstra planner
基于势能场的Dijkstra
算法, 并使用wrapper
包装, 方便调试
测试命令
roslaunch my_global_planner_plugin kernelDebug.launch
结果
myCarrot
myAStar
myDijkstra
myRosDijkstra
局部轨迹规划算法开发工具包, 提供测试工具、 rviz
接口、几种规划算法对比
提供下列局部轨迹规划器
TrajectoryPlannerROS
用于差分底盘, 控制空间采样仿真TebLocalPlannerROS
用于阿克曼底盘, 优化方法
启动命令1:base_local_planner
作为局部轨迹规划器
roslaunch lasis_launch navigation.launch local_planner:=base_local_planner/myBaseLocalPlannerROS
启动命令2: TebLocalPlannerROS
作为局部轨迹规划器
roslaunch lasis_launch navigation.launch local_planner:=teb_local_planner/TebLocalPlannerROS
ROS
中局部规划算法的基类为 nav_core::BaseLocalPlanner
, 提供如下四个接口供 move_base
调用
// 计算底盘控制指令
virtual bool computeVelocityCommands(geometry_msgs::Twist& cmd_vel) = 0;
// 是否完成对全局路径规划的跟踪
virtual bool isGoalReached() = 0;
// 设定全局全局路径规划位姿
virtual bool setPlan(const std::vector<geometry_msgs::PoseStamped>& plan) = 0;
// 初始化局部轨迹规划器
virtual void initialize(std::string name, tf2_ros::Buffer* tf, costmap_2d::Costmap2DROS* costmap_ros) = 0;
ROS
中差分机器人底盘默认局部路径规划器为 base_local_planner/TrajectoryPlannerROS
, 主要算法为 state lattice
: 在控制空间中采样控制量并对机器人在这组控制量下的轨迹进行仿真并评分, 找到代价最小的轨迹作为最优轨迹. 由算法核心与 ROS 包装层组成, 其工作流程图由 CSDN用户 BRAND-NEO 整理, 可归纳为:
move_base
节点使用pluginlib
方式创建TrajectoryPlannerROS
对象作为包装层, 在其构造函数中创建算法对象TrajectoryPlanner
, 调用接口为TrajectoryPlannerROS::initialize
- 当全局路径规划结果发生变化时,
move_base
调用TrajectoryPlannerROS::setPlan
对追踪目标进行更新,TrajectoryPlannerROS
储存全局路径规划并将当前状态设置为未到达终点 move_base
节点周期调用TrajectoryPlannerROS::computeVelocityCommands
和TrajectoryPlannerROS::isGoalReached
计算底盘控制指令并检查是否完成追踪- 在
TrajectoryPlannerROS::computeVelocityCommands
中,TrajectoryPlannerROS
将全局路径规划变换到局部代价图上并对规划进行裁减, 然后根据底盘是否在运动、距离终点距离、决定轨迹生成方式并生成底盘控制指令, 轨迹生成算法核心函数为TrajectoryPlanner::generateTrajectory
, 详细参考Base Local Planner 源码解读-1 TrajectoryPlanner::createTrajectories
在控制空间中采样并调用轨迹生成函数,TrajectoryPlanner::generateTrajectory
对机器人在采样控制量下运动轨迹进行仿真并评分, 详细参考Base Local Planner 源码解读-2
图片来源:CSDN用户 BRAND-NEO
move_base 节点并不是针对阿克曼底盘设计, 底盘控制指令为控制差分底盘的 geometry_msgs/Twist
, 而不是阿克曼底盘控制指令 ackermann_msgs/AckermannDriveStamped
. 但因前者具有六自由度而后者仅具有二自由度, 因此 geometry_msgs/Twist
仍可用于阿克曼底盘. TebLocalPlannerROS
通过添加 最小转弯半径约束解决该两种底盘运动方式不同的问题:
注意: 使用 TebLocalPlannerROS
时推荐关闭 move_base
节点的 escape
功能!
TebLocalPlannerROS
的主要方法是使用 g2o
优化 TimedElasticBand
对象
图片来源:腾讯云 小白学视觉
图片来源:g2o学习笔记
base_local_planner/TrajectoryPlannerROS
效果欠佳
teb_local_planner/TebLocalPlannerROS
使用底盘运动学限制,效果良好
- 20210416
TF
变换学习 - 20210420
actionlib
动作服务器学习 - 20210421 动态参数调节学习, 使用类进行参数服务器与服务段封装
- 20210424
pluginlib
插件类加载方法学习 - 20210426
nodelet
学习 - 20210513 添加
my_global_planner_plugin
局部路径规划插件 - 20210519 仿照
navfn
优化dijkstra
算法, 并使用wrapper
包装新增调试节点 - 20210524 在
lasis_car
中使用racecar
模型 - 20210527
amcl
上线 - 20210528 新增
move_base
节点,navigation
基础功能完成 - 20210601 迁移到
ROS melodic
发行版 - 20210615 添加
my_local_planner_plugin
局部路径规划插件 - 20210616 修复使用
TebLocalPlannerROS
时小车陷入局部最优解问题
- 抄来的
base_local_planner
原地打方向, 已解决 - 使用差速规划器控制阿克曼底盘效果不理想,代解决
pluginlib_tutorials
如何配置VSCode来调试ROS节点
北邮-智能车
carrot planner
aStar planner& dijkstra planner
NavFnROS中势能计算
AMZ-driverless
MIT-RACECAR
MIT racecar 2016 team 5 project blog
MIT ICRA'19 tutorial
Publishing Odometry Information over ROS
amcl详解-csdn
Base Local Planner 源码解读-1
Base Local Planner 源码解读-2
Base Local Planner 源码解读-3
ros-planning/navigation/base_local_planner
rst-tu-dortmund/teb_local_planner
Trajectory modification considering dynamic constraints of autonomous robots
Kinodynamic Trajectory Optimization and Control for Car-Like Robots
g2o学习笔记
graph slam tutorial : 从推导到应用1
graph slam tutorial : 从推导到应用2
graph slam tutorial : 从推导到应用3