rmoss_core icon indicating copy to clipboard operation
rmoss_core copied to clipboard

Refactor rmoss project

Open gezp opened this issue 1 year ago • 21 comments

rmoss项目已经很久没有更新了,代码框架已经过时,是时候重新回头考虑rmoss软件系统应该如何设计这个问题了。目前可以参考的开源项目有很多,比如:

rmoss项目将只做rmoss_corermoss_gazebo仿真器项目,而任务级功能软件包rmoss_contrib将不再维护,其中的rmoss_auto_aim建立独立仓库进行维护。而像能量机关等任务级功能是需要参赛队伍去自行开发,而且每年可能都会有变化,甚至会有新任务的出现,如有开发者愿意开发任务级功能以作为demo演示,则建立独立仓库进行维护。

其中有几个部分需要讨论:

  • rmoss机器人软件架构:一个RM机器人软件应该怎样解耦设计?需要哪些功能包?每个包消息链路以及层级关系如何设计?
  • rmoss_core目录结构:rmoss_core应该包含哪些通用公共的功能?
  • rmoss_interfaces消息类型:机器人控制消息,机器人状态消息,裁判系统提供的状态消息,优先使用ros现在已有的消息类型。

欢迎大家讨论,并提出建议。

gezp avatar Jul 22 '24 15:07 gezp

cc @Ericsii @WUyinwei-hah

gezp avatar Jul 22 '24 15:07 gezp

目前想到的rmoss_core应该包含以下package:

  • rmoss_transporter:即rmoss_base中transporter功能,仅作为库进行依赖
  • rmoss_cam: 相机功能
  • rmoss_projectile_motion: 弹道运动计算功能,仅作为库进行依赖
  • rmoss_util:通用工具类,仅作为库进行依赖

rmoss_base没有存在的必要性,其中的simple_robot_base_node.cpp仅仅作为example样例存在,不同机器人的base模块必然不同,因此可以删除rmoss_base包。

gezp avatar Jul 22 '24 15:07 gezp

参考navigation2,可以采用LifecycleNode进行节点管理,删除rmoss_util/task_manager功能类

gezp avatar Jul 22 '24 15:07 gezp

参考navigation2,可以采用LifecycleNode进行节点管理,删除rmoss_util/task_manager功能类

支持使用LifecycleNode来进行管理。rmoss_interface中对于云台的底盘控制的消息应该重新修改一下,我倾向于类似ros2_control的方式来控制云台

Ericsii avatar Jul 22 '24 16:07 Ericsii

  • 裁判系统可以单独作为一个功能提供
  • rmoss_util可以进一步拆分,避免越做越大(防止为了一个小工具而安装一堆库,等一坨东西编译半天)
    • 除了ros2以外没有其他依赖的通用工具类
    • 图像处理的工具类或者是对OpenCV某个功能的封装
    • 一些常用的数学算法工具,比如均值滤波、卡尔曼滤波,曲线拟合,不同旋转表示之间的转换

baiyeweiguang avatar Jul 22 '24 17:07 baiyeweiguang

  • 裁判系统可以单独作为一个功能提供

你说的是裁判系统给机器人提供的信息?还是仿真器的裁判系统实现?

  • rmoss_util可以进一步拆分,避免越做越大(防止为了一个小工具而安装一堆库,等一坨东西编译半天)

    • 除了ros2以外没有其他依赖的通用工具类
    • 图像处理的工具类或者是对OpenCV某个功能的封装
    • 一些常用的数学算法工具,比如均值滤波、卡尔曼滤波,曲线拟合,不同旋转表示之间的转换

这个我也赞同,rmoss_util应该只放一些简单的工具类,复杂的工具类应该单独做package,第二点图像处理工具类我倾向于独立出去,放在rmoss_perception_common之类的包中?

gezp avatar Jul 23 '24 01:07 gezp

支持使用LifecycleNode来进行管理。rmoss_interface中对于云台的底盘控制的消息应该重新修改一下,我倾向于类似ros2_control的方式来控制云台

可以简单讲一下这种方式下云台和底盘消息怎么定义吗?比如应该包含哪些字段,我对ros2_control不太熟 @Ericsii

gezp avatar Jul 23 '24 01:07 gezp

支持使用LifecycleNode来进行管理。rmoss_interface中对于云台的底盘控制的消息应该重新修改一下,我倾向于类似ros2_control的方式来控制云台

可以简单讲一下这种方式下云台和底盘消息怎么定义吗?比如应该包含哪些字段,我对ros2_control不太熟 @Ericsii

可以参考一下 ros2_control 的 architecture 这部分介绍,应该算是使用 ros 来控制机器人的标准推荐做法 https://control.ros.org/rolling/doc/getting_started/getting_started.html#controller-manager

Ericsii avatar Jul 23 '24 05:07 Ericsii

  • 裁判系统可以单独作为一个功能提供

可以把裁判系统通讯尽量直接兼容裁判系统协议,如果之后有队伍愿意做无下位机的方案也可以直接使用

Ericsii avatar Jul 23 '24 05:07 Ericsii

系统架构设计想法: arch 其中

  • Task Layer: 功能任务层,包含感知,规划,定位,导航等任务的实现,可以被不同的机器人复用,不需要考虑机器人硬件结构。
  • Interfece Layer: 机器人与功能任务的接口层,包含传感器与执行器驱动,由于不同机器人硬件结构差异性较大,而控制功能与机器人硬件结构相关性比较高,因此也放入该层,该部分可以采用ros2-control方式实现适配,也可以自行开发控制程序,不做限制。
  • Hardware Layer:机器人本体,使用usb,以太网,串口与Interfece Layer进行数据通信。

Task Layer与Interfece Layer使用ros msg应该与机器人的具体硬件结构实现无关。

  • state ros msg:sensor_msgs/JointState
  • command ros msg:geometry_msgs/Twist, trajectory_msgs/JointTrajectory

Task Layer的功能包可以参考navigation2moveit2

  • navigation2的输入消息是目标点,输出消息是geometry_msgs/Twist,与机器人底盘具体实现无关
  • moveit2的输入消息是末端执行器目标点,输出消息是trajectory_msgs/JointTrajectory,适用于通用机械臂,而不是特定机械臂

gezp avatar Jul 23 '24 14:07 gezp

  • 裁判系统可以单独作为一个功能提供

你说的是裁判系统给机器人提供的信息?还是仿真器的裁判系统实现?

与真实的裁判系统实现通信,数据发布到指定话题上(在雷达站上算刚需)。目前好像没找到特别好的,在上位机与裁判系统通信的开源,只在广工的rm_controls开源上看到一个ROS1版的,但实现的有点复杂,不太好用

baiyeweiguang avatar Jul 25 '24 09:07 baiyeweiguang

与真实的裁判系统实现通信,数据发布到指定话题上(在雷达站上算刚需)。目前好像没找到特别好的,在上位机与裁判系统通信的开源,只在广工的rm_controls开源上看到一个ROS1版的,但实现的有点复杂,不太好用

看起来没问题,创建一个新包,例如rmoss_referee_bridge , 把裁判系统的数据封装为ros msg发布出去,裁判系统的消息与比赛规则相关性高,可以单独创建仓库进行维护,后面可以加入开发计划。

gezp avatar Jul 25 '24 15:07 gezp

rmoss_auto_aim模块重构的想法: autoaim

其中rmoss_auto_aim应该只包含armor detector和armor tracker模块,作为一个perception功能包。

模块功能:

  • armor detector: 检测装甲板目标与位姿估计,输出一组装甲板消息。
  • armor tracker: 装甲板跟踪与预测,输出预测的最佳射击目标点等消息。
  • gimbal controller: 云台控制,包含弹道补偿功能,输入目标点,输出关节角度目标JointState或者JointTrajectory给MCU,与机器人的机械结构强相关,不同的机器人不一样,甚至有可能是双云台机器人。

参考了rm_auto_aim,其pipeline设计比较合理,这里只是解耦了perception和control模块,这样解耦的好处是perception模块无需关心硬件结构,只需要输出目标位置即可,gimbal controller也可以被能量机关这种需要射击的任务复用。同时perception和control模块之间也非常容易插入决策模块判断目标pose是否应该射击。

gezp avatar Jul 25 '24 16:07 gezp

通讯部分的设想:

参考:

为了兼容不同队伍机器人会有不同的总线设计,需要一套能够兼容不同总线通讯协议的基础工具类,有一套统一的数据读取机制。我设想是直接基于 boost::asio 来设计一个通讯基类的接口。

RMOSS-Transporter drawio

  • 基础的数据类型为 DataFrame ,需要包含 DataFrame 签名(数据帧)的类型以及数据帧内字节数据
  • Transporter 作为通讯基类,仅提供 ros_control 中对于 hardware_interface 需要提供的 read 和 write 接口
  • SocketTransporter 为 Socket 通讯基类,使用 boost::asio 实现异步的数据读写操作
  • 实现一个新的可实例化的通讯类型可以从 SocketTransporter 派生来使用 asio 提供的异步读写接口,也可以直接从 Transporter 派生更为自由的实现操作
  • TransporterFactory 来便于直接从配置文件中读取配置字符数组来自动构造通讯类型。(此部分可以参考我之前实现的通讯协议解析工厂模式 buffer_processor_factory register_macro

这部分作为一个基础工具类同时为 ros_control 做无下位机控制和裁判系统通讯等功能提供支持

具体工厂模式如何读取配置文件的实现,应该可以参考一下 navigation2 中 plugin 的配置读取方式

Ericsii avatar Aug 15 '24 12:08 Ericsii

为了兼容不同队伍机器人会有不同的总线设计,需要一套能够兼容不同总线通讯协议的基础工具类,有一套统一的数据读取机制

兼容不同通信方式可行,统一通信接口就行,比如现在rmoss_base中的Transporter就做的这件事,但是要统一通信数据格式比较困难,不同队伍有着不同数据格式的需求,这个感觉比较难统一,比如比如rm-vision中的rm_serial_driver直接使用结构体作为数据传输格式,简单有效。这也是我为什么想把rmoss_base更改为rmoss_transporter的原因,即仅提供通信接口,通信的数据处理不同队伍会有各自不同的实现。

Transporter 作为通讯基类,仅提供 ros_control 中对于 hardware_interface 需要提供的 read 和 write 接口

这里我感觉是不是要和 ros_control 的hardware_interface 解偶开来,Transporter 应该作为通用的消息传输接口(字节传输),Transporter 有Can, Serial Socket等方式,ros2_control 中 hardware_interface 通过使用Transporter 获得硬件交互能力,比如rm_controls/rm_hw 中也是使用CanBus(属于Transporter ),另外GPIO感觉比较特殊,感觉不应该继承Transporter基类,单独实现一个接口即可 ,rm_controls/rm_hw设计感觉就行。

gezp avatar Aug 15 '24 15:08 gezp

Transporter 作为通讯基类,仅提供 ros_control 中对于 hardware_interface 需要提供的 read 和 write 接口

这里我感觉是不是要和 ros_control 的 hardware_interface 解偶开来,Transporter 应该作为通用的消息传输接口(字节传输),Transporter 有Can, Serial Socket等方式,ros2_control 中 hardware_interface 通过使用Transporter 获得硬件交互能力,比如rm_controls/rm_hw 中也是使用CanBus(属于Transporter ),另外GPIO感觉比较特殊,感觉不应该继承Transporter基类,单独实现一个接口即可 ,rm_controls/rm_hw设计感觉就行。

这里应该是我的表述有误,其实想法是 Transporter 使用类似 hardware_interface 的接口定义,这样如果后续想要做无下位机的方案可以比较方便的放到 ros_control 里面

Ericsii avatar Aug 15 '24 15:08 Ericsii

这里应该是我的表述有误,其实想法是 Transporter 使用类似 hardware_interface 的接口定义,这样如果后续想要做无下位机的方案可以比较方便的放到 ros_control 里面

那感觉就是ros_control的内容了,有点像之前rmoss_base的设计目标了,硬件和ros接口之间的桥梁,需要设计数据格式,以及数据处理逻辑,设计上较难考虑周全。另外,我觉得Transporter定义还是得回归通信本身,最好解耦开来,至于是否需要统一接口,这个也有待讨论。

gezp avatar Aug 15 '24 16:08 gezp

这里应该是我的表述有误,其实想法是 Transporter 使用类似 hardware_interface 的接口定义,这样如果后续想要做无下位机的方案可以比较方便的放到 ros_control 里面

那感觉就是ros_control的内容了,有点像之前rmoss_base的设计目标了,硬件和ros接口之间的桥梁,需要设计数据格式,以及数据处理逻辑,设计上较难考虑周全。另外,我觉得Transporter定义还是得回归通信本身,最好解耦开来,至于是否需要统一接口,这个也有待讨论。

这里并没有规定数据格式,按照UML图例 DataFrame 仅包含数据的元信息 encoding (或者别的名字)和原始的字节数据,具体如何拼接和解析二进制数据的协议并没有包含在这个 Transporter 设计中应该作为使用者来进行实现。是满足这里说的硬件通信和协议解耦的

Ericsii avatar Aug 15 '24 16:08 Ericsii

这里并没有规定数据格式,按照UML图例 DataFrame 仅包含数据的元信息 encoding (或者别的名字)和原始的字节数据,具体如何拼接和解析二进制数据的协议并没有包含在这个 Transporter 设计中应该作为使用者来进行实现。是满足这里说的硬件通信和协议解耦的

从UML中,read和write函数并没有看到data参数,那么怎么利用Transporter去发送和读取DataFrame?我好像并没有看到,这里能不能解释一下?我理解read和write是处理read_buffer和write_buffer,但是好像没有加进去和读出来的接口,没太看明白这里是怎么工作的。

gezp avatar Aug 16 '24 01:08 gezp

从UML中,read和write函数并没有看到data参数,那么怎么利用Transporter去发送和读取DataFrame?我好像并没有看到,这里能不能解释一下?我理解read和write是处理read_buffer和write_buffer,但是好像没有加进去和读出来的接口,没太看明白这里是怎么工作的。

这里是参照常见的一些通讯库的做法,在 Transporter 的构造时传入 read 和 write 的 buffer 的指针,调用这两个方法时就不用再传 data 了

Ericsii avatar Aug 16 '24 02:08 Ericsii

rmoss_cam重构想法:

  • cam_server/cam_client框架略显繁琐,消息链路为raw data->cv::Mat->ros msg->cv::Mat,可以去掉cam_server/cam_client封装,简化为raw data->ros msg->cv::Mat方式。
  • 重点规范ros msg/srv接口,而不是统一程序API,提供一些通用相机工具类/函数,例如https://github.com/robomaster-oss/rmoss_core/issues/17 中功能。
  • 提供usb相机和虚拟相机功能(维持原有功能)。
  • 实现参数配置GUI,可以参考ros2_mindvision_camera

目前 rmoss_gz_cam已经去掉cam_server/cam_client包装,极大简化了程序,避免为了适配代码封装而产生大量繁琐且冗余的代码。

gezp avatar Aug 28 '24 15:08 gezp