| 组件 | 版本 | 组件 | 版本 |
|---|---|---|---|
| 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