diff --git a/application/application.md b/application/application.md index d314406..a68e948 100644 --- a/application/application.md +++ b/application/application.md @@ -1,3 +1,59 @@ # application -这是application层的说明 \ No newline at end of file +
neozng1@hnu.edu.cn
+ +这是application层的说明。 + + + +## 使用说明 + +在main函数中包含`robot.h`头文件,这是对整车的抽象。将`INStask`,`motortask`,`ledtask`,`monitortask`这四个task加入`freertos.c`中,创建对应的任务,设置合适的任务运行间隔;然后将`robottask`放入freertos.c中,同样以一定的频率运行。 在初始化实时系统之前,在`main()`中调用`RobotInit()`进行整车的初始化。 + +INStask的运行频率为1kHz,motortask推荐的运行频率为200Hz\~500Hz,对于高实时性要求的电机可以提升到1kHz,不过要注意CAN总线的负载。ledtask的运行频率推荐为1kHz,monitortask的运行频率推荐为50\~100Hz;robottask的运行频率推荐为150Hz以上,应当高于视觉发送的频率,若后续使用插帧,应该保证不低过motortask太多。 + +若使用双板,则在`robot_def.h`中给对应的开发板设定宏定义,如底盘板使用`#define CHASSIS_BOARD`,云台板使用`#define GIMBAL_BOARD`;单个开发板控制整车,则定义`#define ONE_BOARD`。在每个应用中,都已经使用编译预处理指令完成条件编译,会自动根据设定的宏切换功能。使用双板的时候,目前板间通信通过CAN完成,因此两个开发板会挂载在一条总线上,在两个开发板对这条总线的其他使用CAN的设备进行配置时注意**不要发生ID冲突**,还要注意**防止负载过大**。 + +**同样,在该文件中你需要修改一些关于机器人的参数**。比如底盘和云台对齐时yaw电机编码器的值,拨盘的单圈载弹量、底盘的轴距等等。 + + + +## 封装总览 + +Robot.c是整个机器人的抽象,其下有4个应用:robot_cmd,gimbal,chassis,shoot。此框架当前是针对步兵/英雄/哨兵设计的,其他机器人只需要根据各自的特殊机构进行修改即可。robot_cmd是整个机器人的核心应用,其负责接受遥控器/上位机发来的指令,并将指令转化为实际的运动控制目标,发送给其他三个应用。后者会根据robot_cmd发来的命令,设定电机和其他执行单元的参考值等。 + +为了进一步解耦应用之间的关系,这里并没有采用层级结构(或设计模式中所谓的**工厂模式**,即robot_cmd包含其他三个模块),而采用了应用并列的**发布-订阅**机制,四个应用之间没有任何相互包含关系,他们之间的通信通过module层提供的`message_center`实现。每个应用会通过该模块向一些话题(事件)发布一些消息,同时从一些话题订阅消息。如robot_cmd应用会发布其他三个模块的控制信息,同时订阅其他三个模块的反馈信息。其他三个模块会订阅robot_cmd发布的控制信息,同时发布反馈给robot_cmd的信息,他们不需要知道彼此的存在,只是从`message_center`处获取其他应用发布的消息或向自己发布的话题推送消息。 + + + +## 整车程序流程 + +```mermaid +graph TD +main调用RobotInit进行初始化 --> RobotInit调用基础bsp初始化以及各个app的初始化 --> 各个app进行消息订阅初始化和自有模块的初始化 --> 启动实时系统 --> 各任务开始运行 + +``` + +任务开始之后,每个app之间的交互关系如下: + +```mermaid +graph TD +robot_cmd获取遥控器/上位机指令以及各个应用发布的回传信息 --> 将指令转化为具体的控制信息 --> 发布指令到对应话题 +``` + +gimbal/chassis/shoot则根据订阅的robot_cmd发布的消息,将具体的控制信息根据当前模式转化为执行单元的目标值,通过自己拥有的模块完成这些指令,然后把回传的信息发布到对应话题。 + +每个应用的具体流程和实现,参见它们各自的说明文档。 + + + +## 开发要点 + +各个应用之间务必通过`message_center`以发布-订阅的方式进行消息交换,不要出现包含关系,这可以大大减小耦合度并提高合作开发的效率。 + + + + + + + diff --git a/application/cmd/robot_cmd.c b/application/cmd/robot_cmd.c index a50da6a..7949f62 100644 --- a/application/cmd/robot_cmd.c +++ b/application/cmd/robot_cmd.c @@ -176,11 +176,11 @@ static void EmergencyHandler() } } -void GimbalCMDTask() +void RobotCMDTask() { // 从其他应用获取回传数据 #ifdef ONE_BOARD - SubGetMessage(chassis_feed_sub, (void*)&chassis_fetch_data); + SubGetMessage(chassis_feed_sub, (void *)&chassis_fetch_data); #endif // ONE_BOARD #ifdef GIMBAL_BOARD chassis_fetch_data = *(Chassis_Upload_Data_s *)CANCommGet(cmd_can_comm); diff --git a/application/cmd/robot_cmd.h b/application/cmd/robot_cmd.h index 8f0931d..faa8d80 100644 --- a/application/cmd/robot_cmd.h +++ b/application/cmd/robot_cmd.h @@ -3,6 +3,6 @@ void GimbalCMDInit(); -void GimbalCMDTask(); +void RobotCMDTask(); #endif // !GIMBAL_CMD_H \ No newline at end of file diff --git a/application/cmd/robot_cmd.md b/application/cmd/robot_cmd.md index e69de29..1a9075d 100644 --- a/application/cmd/robot_cmd.md +++ b/application/cmd/robot_cmd.md @@ -0,0 +1,28 @@ +# robot_cmd + +neozng1@hnu.edu.cn
+ +## 运行流程 + +运行流程可以很直观的从`RobotCMDTask()`中看出。首先通过消息订阅机制,获取其他应用的反馈信息,然后使用`CalcOffsetAngle()`计算底盘和云台的offset angle(使得底盘始终获知当前的正方向),接着根据当前是通过键鼠or遥控器控制,调用对应的函数,将控制指令量化为具体的控制信息;得到控制信息之后,先不急着发布,而是检测重要的模块和应用是否掉线或出现异常,以及遥控器是否进入紧急停止模式,如果以上情况发生,那么将所有的控制信息都置零,即让电机和其他执行单元保持静止。最后还是通过pubsub机制,把具体的控制信息发布到对应话题,让其他应用获取。 + + + +## 外部接口 + + + + + + + + + +## 私有函数和变量 + + + + + + + diff --git a/application/robot.c b/application/robot.c index 3fbbc92..7610866 100644 --- a/application/robot.c +++ b/application/robot.c @@ -29,7 +29,7 @@ void RobotInit() void RobotTask() { #if defined(ONE_BOARD) || defined(GIMBAL_BOARD) - GimbalCMDTask(); + RobotCMDTask(); GimbalTask(); ShootTask(); #endif diff --git a/modules/message_center/message_center.md b/modules/message_center/message_center.md index 183a02d..9db777f 100644 --- a/modules/message_center/message_center.md +++ b/modules/message_center/message_center.md @@ -24,7 +24,7 @@ - 订阅者:获取消息的对象。订阅者在订阅了某个事件之后,可以通过接口获得该事件的消息。 - 事件(event / topic):用于区分消息来源的对象。可以将一个事件看作一刊杂志,不同的发布者会将文章汇集到杂志上,而订阅者选择订阅一种杂志,然后就可以获取所有写在杂志上的文章。 -Message Center不同应用间进行消息传递的中介,它的存在可以在相当大的程度上解耦不同的app,使得不同的应用之间**不存在包含关系**,让代码的自由度更大,将不同模块之间的关系降为**松耦合**。在以往,如果一个.c文件中的数据需要被其他任务/源文件共享,那么其他模块应该要包含前者的头文件,或头文件中应当存在获取该模块数据的接口(即函数,一般是返回数据指针或直接返回数据);但现在,不同的应用之间完全隔离,他们不需要了解彼此的存在,而是只能看见一个**消息中心**。 +Message Center不同应用间进行消息传递的中介,它的存在可以在相当大的程度上解耦不同的app,使得不同的应用之间**不存在包含关系**,让代码的自由度更大,将不同模块之间的关系降为**松耦合**。在以往,如果一个.c文件中的数据需要被其他任务/源文件共享,那么其他模块应该要包含前者的头文件,且头文件中应当存在获取该模块数据的接口(即函数,一般是返回数据指针或直接返回数据,**强烈建议不要使用全局变量**);但现在,不同的应用之间完全隔离,他们不需要了解彼此的存在,而是只能看见一个**消息中心**以及一些事件(有些地方也称**话题**)。 需要被共享的消息,将会被**发布者**(publisher)发送到消息中心;要获取消息,则由**订阅者**(subscriber)从消息中心根据订阅的消息名(事件)获取。在这之前,发布者要在消息中心完成**注册**,将自己要发布的消息类型和消息名称提交到消息中心;订阅者同样要先在消息中心完成订阅,将自己要接收的消息类型和消息名称提交到订阅中心。消息中心会根据**消息名称**,把订阅者绑定到发布相同名称的发布者上。 diff --git a/openocd_dap.cfg b/openocd_dap.cfg index 8710b89..2ff8684 100644 --- a/openocd_dap.cfg +++ b/openocd_dap.cfg @@ -1,7 +1,7 @@ # 选择调试器为jlink source [find interface/cmsis-dap.cfg] -# source [find interface/jlink.cfg] #使用jlink硬件进行调试,注意其他地方也要更改 +# source [find interface/jlink.cfg] #使用cmsis-dap硬件进行调试,注意其他地方也要更改 # OpenOCD作为GDB和硬件调试器的桥梁(为硬件提供抽象,把接口给GDB),支持多种硬件调试器. # OpenOCD会自动在其根目录的share/openocd/scripts/interface里面寻找对应的配置文件