# APP层应用编写指引

## 通信机制

**应用之间不应该有任何包含关系，它们必须是平行工作的。**而这通过pub-sub的机制实现。module层提供了`message_center`模块，支持发布订阅者的消息订阅机制。以传统的框架为例，负责整车控制的应用和其他应用（或任务）是从属的树状结构，或不同的任务和应用之间通过全局变量传递消息（**请不要使用全局变量！**），而此框架下的不同应用是并行的关系。

如果一个应用希望获取另一个应用的数据，那么他应该**订阅**由此此应用发布的话题。一个应用要把自己希望共享的数据，注册到消息中心，即**发布**。为了区别不同的消息来源（你希望订阅谁的消息？哪一个消息？），可以通过**话题名**进行订阅。也就是说，消息中心作为第三方，管理所有的消息发布者和订阅者，它像报刊亭一样对消息进行中转，使得不同的应用之间不需要包含彼此，更不用全局变量也能共享消息。

> 更多关于发布-订阅的实现，请参考`modules/message_center`下的文档。


## robot_def.h

这是机器人的参数配置文件，必须要针对每个机器人进行修改。包括机器人的尺寸参数和性能参数等。你还需要在这里设定软硬件配置：云台板/底盘板/单板等。这里定义的宏会作为条件编译的决断。

app层共用的状态变量和结构体等也应该定义在这里（例如用于应用之间通信的数据）。记得用于通信的变量要用:
```c
#pragma pack(1) 
typedef struct
{
    // your struct 

} your_struct;
#pragma pack()
```
包裹起来，取消字节对齐以防止出现访问8-bit地址而出现错误。

如果你需要其他的通信数据类型或修改模块间通信数据的格式，直接在此处更改即可。

## robot_cmd

机器人命令模块是对整个机器人的抽象，对于单板控制整车的情况，该应用应该包含接收控制指令的模块，例如遥控器、视觉通信模块。该模块会处理接收到的控制数据，并将其转化为**具体的、定量的**控制信息，发送给其他模块。同时，cmd应用会处理模块和应用离线的情况，出现紧急状况时停止所有执行机构的运行。

如从遥控器获知当前右侧摇杆拨向上方，则将遥控器发来的数值转化为底盘前进的速度值，然后发送给其他应用。同时，robot_cmd还要从其他应用获取反馈信息，做出其他决策。可以将其视为整个机器人的**大脑**。

robot_cmd工作起来就像一个遥控数据的兼容层，不论数据的来源是视觉上位机/遥控器/键鼠/图传通信链路/ps手柄，最后都会被转化成真实参考输入提供给其他的app。它的任务是将其他来源的数据映射到控制输入上。



## gimbal

以步兵为例，云台应用应当包含两个电机，分别用于驱动yaw和pitch轴（除非你是一个三轴的云台），还有一个imu（开发板一般放在云台上）。gimbal模块会接收robot_cmd发来的控制信息（云台的角度、转速等），并通过电机提供的接口完成电机的参考值设定。gimbal还要把imu的数据反馈给cmd，用于和视觉的通信以及云台状态的判断。



## shoot

还是以步兵为例，发射应用应当包括摩擦轮电机、拨盘电机和弹舱盖。根据cmd应用发来的控制信息，决定当前的发射模式（单发、双发、连发），弹舱盖的开合，以及射速（15？18？30？）等。



##  chassis

以步兵为例，底盘应该包括4个电机。根据cmd应用发来的控制信息，进行麦克纳姆轮的运动学解算，从而获知四个电机需要的设定值，然后调用电机提供的接口进行设定。chassis还要根据电机的反馈数据以及imu信息（如果有imu的话，即双板的情况，云台一个底盘一个），计算底盘的实际运动状态，反馈给robot_cmd应用。



## lift

以工程机器人为例，抬升机构应该包含用于抬升的执行单元（可能是气缸、电磁阀、电机、点推杆等），根据cmd发来的数据控制执行单元运行到特定的高度，并进行必要的反馈。



## 双板兼容

此框架对单开发板/双开发板/多开发板的情况都提供了支持（多板一般只在工程机器人上出现，需要自己在robot_cmd和robot_def增加相应的条件编译选项，robot.c中也不要忘记增加初始化和任务运行函数），目前通过条件编译实现了对单双板的切换。使用双板时，主控板在云台上，连接遥控器和上位机；副板在底盘上，负责底盘的运动控制和与裁判系统的通信。
