diff --git a/assets/CANcomm.png b/assets/CANcomm.png new file mode 100644 index 0000000..b4a0a76 Binary files /dev/null and b/assets/CANcomm.png differ diff --git a/modules/can_comm/can_comm.md b/modules/can_comm/can_comm.md index ee1d359..607ac98 100644 --- a/modules/can_comm/can_comm.md +++ b/modules/can_comm/can_comm.md @@ -5,35 +5,91 @@ > TODO: > > 1. 增加数据长度可变的协议支持 -> 2. 简化接收流程 +> 1. 对`CANCommGet()`进行修改,使得其可以返回数据是否更新的相关信息。 + + ## 总览和封装说明 - - - - - +CAN comm是用于CAN多机通信的模块。你不需要关心实现的协议,**只需要传入你想发送/接收的结构体的长度**(通过`sizeof()`获取)即可。单帧发送长度目前限制为60字节,如果需要加长可以在`can_comm.h`中修改`CAN_COMM_MAX_BUFFSIZE`的定义值。注意CAN的负载以及使用此模块的发送频率,否则可能造成堵塞。 ## 代码结构 - - - +.h中放置的是数据定义和外部接口,以及协议的定义和宏,.c中包含一些私有函数。 ## 外部接口 +```c +CANCommInstance *CANCommInit(CANComm_Init_Config_s* comm_config); +void CANCommSend(CANCommInstance *instance, uint8_t *data); +void *CANCommGet(CANCommInstance *instance); +``` +第一个函数将会初始化一个CANComm实例,返回其指针。使用CANComm进行通信的应用应该保存返回的指针。初始化需要传入一个初始化结构体。请在应用初始化的时候调用该函数。推荐的结构体配置方式如下: +```c +/* 初始化结构体的定义 */ +typedef struct +{ + can_instance_config_s can_config; + uint8_t send_data_len; //发送数据长度 + uint8_t recv_data_len; //接收数据长度,两者请用sizeof获取 +} CANComm_Init_Config_s; +CANComm_Init_Config_s cconfig = { + .can_config = { + .can_handle=&hcan1, + .tx_id=0x02, + .rx_id=0x03}, + .send_data_len = sizeof(your_data_structure), + .recv_data_len = sizeof(recv_data_structure) +}; +``` + +第二个函数将会通过CAN发送一帧数据。这里的“帧”不是CAN的一帧报文,而是你使用的数据。在CANComm初始化的时候,使用sizeof获得你要发送的数据的长度。调用此函数时,将你的数据结构或数据cast成`u8`类型的指针传入即可。==**特别注意,你的结构体需要使用预编译指令`#pragma pack(1)`以及`#pragma pack()`包裹**==,从而进行字节压缩而不进行字节对齐,如: + +```c +#pragma pack(1) +typedef struct +{ + uint8_t aa; + float bb; + double cc; + uint16_t dd; +} some_struct; +#pragma pack() +``` + +只有这样,这个结构体才不会进行padding扩充字节实现字节对齐。你可以尝试一下,如果不使用pack处理,上面的结构体将会占据18个字节以上的空间;开启pack后,会降低至15。更多关于字节对齐的内容,自行查询。 + +> 后期可能更新字节对齐和内存访问相关的教程。 + +`CANCommGet()`是获取来自CANComm接收到的数据的接口,返回值为一个void类型指针,你需要通过**强制类型转换**将其变为你设定的接收类型指针,然后就可以访问其数据了。 ## 私有函数和变量 +```c +static CANCommInstance *can_comm_instance[MX_CAN_COMM_COUNT] = {NULL}; +static uint8_t idx; +static void CANCommResetRx(CANCommInstance *ins); +static void CANCommRxCallback(can_instance *_instance); +``` +第一个指针数组保存所有的can comm实例,从而在callback中区分不同实例。idx是初始化使用的索引,用于确定每个can comm实例指针存放的位置。 +`CANCommResetRx()`在`CANCommRxCallback()`中多次被调用,用于清空接收缓冲区。 - - +`CANCommRxCallback()`是CAN comm初始化can实例时的回调函数,用于can接收中断,进行协议解析。 ## 接收解析流程 +CAN comm的通信协议如下: + +| 帧头 | 数据长度 | 数据 | crc8校验 | 帧尾 | +| ----------- | -------- | ---------------- | -------- | ----------- | +| 's'(0x73) | 0~255 | 最大60(可修改) | 校验码 | 'e'(0x65) | +| 1-byte | 1-byte | n-byte | 1-byte | 1-byte | + +接收的流程见代码注释。 + +流程图如下:![未命名文件](../../assets/CANcomm.png) diff --git a/modules/master_machine/master_process.c b/modules/master_machine/master_process.c index 57548e3..1c24908 100644 --- a/modules/master_machine/master_process.c +++ b/modules/master_machine/master_process.c @@ -14,7 +14,7 @@ #include "seasky_protocol.h" /* use usart1 as vision communication*/ -Vision_Recv_s recv_data; +static Vision_Recv_s recv_data; // @todo:由于后续需要进行IMU-Cam的硬件触发采集控制,因此可能需要将发送设置为定时任务,或由IMU采集完成产生的中断唤醒的任务, // 使得时间戳对齐. 因此,在send_data中设定其他的标志位数据,让ins_task填充姿态值. // static Vision_Send_s send_data; @@ -61,9 +61,4 @@ void VisionSend(Vision_Send_s *send) get_protocol_send_data(0x02, flag_register, &send->yaw, 3, send_buff, &tx_len); USARTSend(vision_usart_instance, send_buff, tx_len); -} - -Vision_Recv_s *VisionGetcmd() -{ - return &recv_data; } \ No newline at end of file diff --git a/modules/master_machine/master_process.h b/modules/master_machine/master_process.h index 180aac6..4bc5c03 100644 --- a/modules/master_machine/master_process.h +++ b/modules/master_machine/master_process.h @@ -7,6 +7,78 @@ #define VISION_RECV_SIZE 36u #define VISION_SEND_SIZE 36u +typedef enum +{ + NO_FIRE = 0, + AUTO_FIRE = 1, + AUTO_AIM = 2 +} Fire_Mode_e; + +typedef enum +{ + NO_TARGET = 0, + TARGET_CONVERGING = 1, + READY_TO_FIRE = 2 +} Target_State_e; + +typedef enum +{ + NO_TARGET_NUM = 0, + HERO1 = 1, + ENGINEER2 = 2, + INFANTRY3 = 3, + INFANTRY4 = 4, + INFANTRY5 = 5, + OUTPOST = 6, + SENTRY = 7, + BASE = 8 +} Target_Type_e; + +typedef struct +{ + Fire_Mode_e fire_mode; + Target_State_e target_state; + Target_Type_e target_type; + + float pitch; + float yaw; +} Vision_Recv_s; + +typedef enum +{ + BLUE = 0, + RED = 1 +} Enemy_Color_e; + +typedef enum +{ + MODE_AIM = 0, + MODE_SMALL_BUFF = 1, + MODE_BIG_BUFF = 2 +} Work_Mode_e; + +typedef enum +{ + BIG_AMU_10 = 10, + SMALL_AMU_15 = 15, + BIG_AMU_16 = 16, + SMALL_AMU_18 = 18, + SMALL_AMU_30 = 30, +} Bullet_Speed_e; + +typedef struct +{ + Enemy_Color_e enemy_color; + Work_Mode_e work_mode; + Bullet_Speed_e bullet_speed; + + float yaw; + float pitch; + float roll; + + // uint32_t time_stamp; // @todo 用于和相机的时间戳对齐 +} Vision_Send_s; + /** * @brief 调用此函数初始化和视觉的串口通信 * diff --git a/modules/master_machine/master_process.md b/modules/master_machine/master_process.md index 94ab049..055c332 100644 --- a/modules/master_machine/master_process.md +++ b/modules/master_machine/master_process.md @@ -1 +1,134 @@ -# master_process \ No newline at end of file +# master_process + + + +

neozng1@hnu.edu.cn

+ +> TODO: +> +> 1. 补全标志位解析和发送设置的代码 +> 2. 增加发送给视觉数据的时间戳用于数据对齐 + + + +## 总览和封装说明 + +模块包含了和视觉通信的初始化、向上位机发送信息的接口和模块的串口的回调处理。接口的定义统一,可以方便的替换成其他通信方式,如CAN。 + +## 代码结构 + +.h文件内包括了外部接口和与**视觉上位机通信的数据结构定义**,以及模块对应的宏。c文件内为私有函数和外部接口的定义。 + +本模块主要是对协议解析的处理和协议发送的封装,实际内容不多。协议相关内容都在`seasky_protocol.h`中。 + +## 类型定义 + +和视觉通信所必须的标志位和数据。包括开火模式,目标状态,目标类型,接收/发送数据结构体。 + +```c +typedef enum +{ + NO_FIRE = 0, + AUTO_FIRE = 1, + AUTO_AIM = 2 +} Fire_Mode_e; + +typedef enum +{ + NO_TARGET = 0, + TARGET_CONVERGING = 1, + READY_TO_FIRE = 2 +} Target_State_e; + +typedef enum +{ + NO_TARGET_NUM = 0, + HERO1 = 1, + ENGINEER2 = 2, + INFANTRY3 = 3, + INFANTRY4 = 4, + INFANTRY5 = 5, + OUTPOST = 6, + SENTRY = 7, + BASE = 8 +} Target_Type_e; + +typedef struct +{ + Fire_Mode_e fire_mode; + Target_State_e target_state; + Target_Type_e target_type; + + float pitch; + float yaw; +} Vision_Recv_s; + +typedef enum +{ + BLUE = 0, + RED = 1 +} Enemy_Color_e; + +typedef enum +{ + MODE_AIM = 0, + MODE_SMALL_BUFF = 1, + MODE_BIG_BUFF = 2 +} Work_Mode_e; + +typedef enum +{ + BIG_AMU_10 = 10, + SMALL_AMU_15 = 15, + BIG_AMU_16 = 16, + SMALL_AMU_18 = 18, + SMALL_AMU_30 = 30, +} Bullet_Speed_e; + +typedef struct +{ + Enemy_Color_e enemy_color; + Work_Mode_e work_mode; + Bullet_Speed_e bullet_speed; + + float yaw; + float pitch; + float roll; + // uint32_t time_stamp; // @todo 用于和相机的时间戳对齐 +} Vision_Send_s; +``` + +## 外部接口 + +```c +Vision_Recv_s *VisionInit(UART_HandleTypeDef *_handle); + +void VisionSend(Vision_Send_s *send); +``` + +给`VisionInit()`传入串口handle,将初始化一个视觉通信模块,返回值是接收数据的结构体指针。拥有视觉模块的应用应该在初始化中调用此函数,并保存返回值的指针。 + +调用`VisionSend`并传入填好发送数据的结构体,会通过底层的通信模块向视觉发送一帧报文。 + +## 私有函数和变量 + +```c +static Vision_Recv_s recv_data; + +static usart_instance *vision_usart_instance; + +static void DecodeVision() +{ + static uint16_t flag_register; + get_protocol_info(vision_usart_instance->recv_buff, &flag_register, (uint8_t*)&recv_data.pitch); + // TODO: code to resolve flag_register; +} +``` + +第一个是保存接收数据的结构体,其指针将会在初始化的时候返回给拥有者。目前最多只能配置一个视觉模块。 + +第二个是该模块拥有的串口实例指针,用于调度其底层的发送和接收。如果要换成CAN/SPI等,替换成对应实例,并修改初始化和发送的实现即可。 + +`DecodeVision()`是解析视觉接收数据的回调函数,会在串口接收回调中被调用。如果修改通信协议,只需要更改 + +`get_protocol_info()`。 \ No newline at end of file diff --git a/modules/master_machine/seasky_protocol.c b/modules/master_machine/seasky_protocol.c index 17af114..105a6b8 100644 --- a/modules/master_machine/seasky_protocol.c +++ b/modules/master_machine/seasky_protocol.c @@ -104,10 +104,10 @@ uint16_t get_protocol_info(uint8_t *rx_buf, // 接收到的原始数据 uint16_t *flags_register, // 接收数据的16位寄存器地址 uint8_t *rx_data) // 接收的float数据存储地址 { + // 放在静态区,避免反复申请栈上空间 static protocol_rm_struct pro; static uint16_t date_length; - volatile size_t s = sizeof(pro); - volatile size_t aa = sizeof(Vision_Recv_s); + if (protocol_heade_Check(&pro, rx_buf)) { date_length = OFFSET_BYTE + pro.header.data_length; diff --git a/modules/master_machine/seasky_protocol.h b/modules/master_machine/seasky_protocol.h index c769a92..7035007 100644 --- a/modules/master_machine/seasky_protocol.h +++ b/modules/master_machine/seasky_protocol.h @@ -5,81 +5,8 @@ #include #define PROTOCOL_CMD_ID 0XA5 - #define OFFSET_BYTE 8 // 出数据段外,其他部分所占字节数 -typedef enum -{ - NO_FIRE = 0, - AUTO_FIRE = 1, - AUTO_AIM = 2 -} Fire_Mode_e; - -typedef enum -{ - NO_TARGET = 0, - TARGET_CONVERGING = 1, - READY_TO_FIRE = 2 -} Target_State_e; - -typedef enum -{ - NO_TARGET_NUM = 0, - HERO1 = 1, - ENGINEER2 = 2, - INFANTRY3 = 3, - INFANTRY4 = 4, - INFANTRY5 = 5, - OUTPOST = 6, - SENTRY = 7, - BASE = 8 -} Target_Type_e; - -typedef struct -{ - Fire_Mode_e fire_mode; - Target_State_e target_state; - Target_Type_e target_type; - - float pitch; - float yaw; -} Vision_Recv_s; - -typedef enum -{ - BLUE = 0, - RED = 1 -} Enemy_Color_e; - -typedef enum -{ - MODE_AIM = 0, - MODE_SMALL_BUFF = 1, - MODE_BIG_BUFF = 2 -} Work_Mode_e; - -typedef enum -{ - BIG_AMU_10 = 10, - SMALL_AMU_15 = 15, - BIG_AMU_16 = 16, - SMALL_AMU_18 = 18, - SMALL_AMU_30 = 30, -} Bullet_Speed_e; - -typedef struct -{ - Enemy_Color_e enemy_color; - Work_Mode_e work_mode; - Bullet_Speed_e bullet_speed; - - float yaw; - float pitch; - float roll; - - // uint32_t time_stamp; // @todo 用于和相机的时间戳对齐 -} Vision_Send_s; - typedef struct { struct