Merge remote-tracking branch 'origin/master'

# Conflicts:
#	.vscode/launch.json
#	application/gimbal/gimbal.c
#	application/robot.c
#	bsp/usart/bsp_usart.c
#	bsp/usart/bsp_usart.h
#	modules/master_machine/master_process.c
#	modules/master_machine/seasky_protocol.c
This commit is contained in:
chenfu
2023-03-22 16:49:56 +08:00
44 changed files with 1877 additions and 602 deletions

View File

@@ -12,12 +12,15 @@
#include "bsp_usart.h"
#include "usart.h"
#include "seasky_protocol.h"
#include "daemon.h"
#include "bsp_log.h"
static Vision_Recv_s recv_data;
// @todo:由于后续需要进行IMU-Cam的硬件触发采集控制,因此可能需要将发送设置为定时任务,或由IMU采集完成产生的中断唤醒的任务,
// 后者显然更nice,使得时间戳对齐. 因此,在send_data中设定其他的标志位数据,让ins_task填充姿态值.
// static Vision_Send_s send_data;
static USARTInstance *vision_usart_instance;
static DaemonInstance *vision_daemon_instance;
/**
* @brief 接收解包回调函数,将在bsp_usart.c中被usart rx callback调用
@@ -27,9 +30,23 @@ static USARTInstance *vision_usart_instance;
static void DecodeVision()
{
static uint16_t flag_register;
DaemonReload(vision_daemon_instance); // 喂狗
get_protocol_info(vision_usart_instance->recv_buff, &flag_register, (uint8_t *)&recv_data.pitch);
// TODO: code to resolve flag_register;
PrintLog("decode vision");
}
/**
* @brief 离线回调函数,将在daemon.c中被daemon task调用
* @attention 由于HAL库的设计问题,串口开启DMA接收之后同时发送有概率出现__HAL_LOCK()导致的死锁,使得无法
* 进入接收中断.通过daemon判断数据更新,重新调用服务启动函数以解决此问题.
*
* @param id vision_usart_instance的地址,此处没用.
*/
static void VisionOfflineCallback(void *id)
{
USARTServiceInit(vision_usart_instance);
}
/* 视觉通信初始化 */
@@ -39,8 +56,16 @@ Vision_Recv_s *VisionInit(UART_HandleTypeDef *_handle)
conf.module_callback = DecodeVision;
conf.recv_buff_size = VISION_RECV_SIZE;
conf.usart_handle = _handle;
vision_usart_instance = USARTRegister(&conf);
// 为master process注册daemon,用于判断视觉通信是否离线
Daemon_Init_Config_s daemon_conf = {
.callback = VisionOfflineCallback, // 离线时调用的回调函数,会重启串口接收
.owner_id = vision_usart_instance,
.reload_count = 10,
};
vision_daemon_instance = DaemonRegister(&daemon_conf);
return &recv_data;
}
@@ -59,13 +84,11 @@ void VisionSend(Vision_Send_s *send)
static uint8_t send_buff[VISION_SEND_SIZE];
static uint16_t tx_len;
// TODO: code to set flag_register
flag_register = 0x0001;
// 将数据转化为seasky协议的数据包
get_protocol_send_data(0x02, flag_register, &send->yaw, 3, send_buff, &tx_len);
USARTSend(vision_usart_instance, send_buff, tx_len,USART_TRANSFER_IT);
// if(vision_usart_instance->usart_handle->ReceptionType == HAL_UART_RECEPTION_TOIDLE)
// {HAL_UARTEx_ReceiveToIdle_DMA(vision_usart_instance->usart_handle, vision_usart_instance->recv_buff, vision_usart_instance->recv_buff_size);
// __HAL_DMA_DISABLE_IT(vision_usart_instance->usart_handle->hdmarx, DMA_IT_HT);
// }
USARTSend(vision_usart_instance, send_buff, tx_len, USART_TRANSFER_DMA); // 和视觉通信使用IT,防止和接收使用的DMA冲突
// 此处为HAL设计的缺陷,DMASTOP会停止发送和接收,导致再也无法进入接收中断.
// 也可在发送完成中断中重新启动DMA接收,但较为复杂.因此,此处使用IT发送.
// 若使用了daemon,则也可以使用DMA发送.
}

View File

@@ -56,7 +56,7 @@ static uint8_t protocol_heade_Check(protocol_rm_struct *pro, uint8_t *rx_buf)
pro->header.sof = rx_buf[0];
if (CRC8_Check_Sum(&rx_buf[0], 4))
{
pro->header.data_length = ((rx_buf[2] << 8) | rx_buf[1]);
pro->header.data_length = (rx_buf[2] << 8) | rx_buf[1];
pro->header.crc_check = rx_buf[3];
pro->cmd_id = (rx_buf[5] << 8) | rx_buf[4];
return 1;
@@ -125,9 +125,9 @@ uint16_t get_protocol_info(uint8_t *rx_buf, // 接收到的原始数据
if (CRC16_Check_Sum(&rx_buf[0], date_length))
{
*flags_register = (rx_buf[7] << 8) | rx_buf[6];
memcpy(rx_data, rx_buf + 8, (pro.header.data_length - 2));
memcpy(rx_data, rx_buf + 8, pro.header.data_length - 2);
return pro.cmd_id;
}
}
}
return 0;
}

View File

@@ -2,78 +2,11 @@
#include "stdlib.h"
#include "string.h"
/* 消息初始化用 */
static char pname[MAX_EVENT_COUNT][MAX_EVENT_NAME_LEN + 1];
static char sname[MAX_EVENT_COUNT][MAX_EVENT_NAME_LEN + 1];
static void *p_ptr[MAX_EVENT_COUNT] = {NULL};
static void **s_pptr[MAX_EVENT_COUNT] = {NULL}; // 因为要修改指针,所以需要二重指针
/* ----------------------------------第三方指针传递版的实现,deprecated----------------------------------- */
void MessageInit()
{
// pub必须唯一,即消息名称不能重复,不得有多个pub发布相同消息名称
// 对每一个subscriber,寻找相同消息名称的publisher,可能有多个sub从相同pub获取消息
for (size_t i = 0; i < MAX_EVENT_COUNT; ++i)
{
if (s_pptr[i] != NULL)
{
for (size_t j = 0; j < MAX_EVENT_COUNT; ++j) // 遍历publisher
{
if (p_ptr[j] != NULL) // 不为空
{
if (strcmp(sname[i], pname[j]) == 0) // 比较消息名是否一致
{
*s_pptr[i] = p_ptr[j]; // 将sub的指针指向pub的数据
break;
}
}
else // 到结尾,退出
{
while (1)
; // 如果你卡在这里,说明没有找到消息发布者!请确认消息名称是否键入错误
}
}
}
else // 说明已经遍历完所有的subs
{
break;
}
}
}
/* 传入数据地址 */
void PublisherRegister(char *name, void *data)
{
static uint8_t idx;
for (size_t i = 0; i < idx; ++i)
{
if (strcmp(pname[i], name) == 0)
while (1)
; // 运行至此说明pub的消息发布名称冲突
}
strcpy(pname[idx], name);
p_ptr[idx++] = data;
}
/* 注意传入的是指针的地址,传参时使用&对数据指针取地址 */
void SubscribeEvent(char *name, void **data_ptr)
{
static uint8_t idx;
strcpy(sname[idx], name);
s_pptr[idx++] = data_ptr;
}
/* ----------------------------------链表-队列版的实现----------------------------------- */
/* message_center是fake head node,是方便链表编写的技巧,这样就不需要处理链表头的特殊情况 */
static Publisher_t message_center = {
.event_name = "Message_Manager",
.first_subs = NULL,
.next_event_node = NULL
};
.next_event_node = NULL};
static void CheckName(char *name)
{
@@ -112,18 +45,18 @@ Subscriber_t *SubRegister(char *name, uint8_t data_len)
{ // 给消息队列的每一个元素分配空间,queue里保存的实际上是数据执指针,这样可以兼容不同的数据长度
ret->queue[i] = malloc(sizeof(data_len));
}
//如果是第一个订阅者,特殊处理一下
if(node->first_subs==NULL)
// 如果是第一个订阅者,特殊处理一下
if (node->first_subs == NULL)
{
node->first_subs=ret;
node->first_subs = ret;
return ret;
}
// 遍历订阅者链表,直到到达尾部
Subscriber_t *sub = node->first_subs; // 作为iterator
while (sub->next_subs_queue) // 遍历订阅了该事件的订阅者链表
while (sub->next_subs_queue) // 遍历订阅了该事件的订阅者链表
{
sub = sub->next_subs_queue; // 移动到下一个订阅者,遇到空指针停下,说明到了链表尾部
}
}
sub->next_subs_queue = ret; // 把刚刚创建的订阅者接上
return ret;
}
@@ -157,6 +90,7 @@ Publisher_t *PubRegister(char *name, uint8_t data_len)
if (strcmp(node->event_name, name) == 0) // 如果已经注册了相同的事件,直接返回结点指针
{
CheckLen(data_len, node->data_len);
node->pub_registered_flag = 1;
return node;
}
} // 遍历完发现尚未创建name对应的事件
@@ -165,6 +99,7 @@ Publisher_t *PubRegister(char *name, uint8_t data_len)
memset(node->next_event_node, 0, sizeof(Publisher_t));
node->next_event_node->data_len = data_len;
strcpy(node->next_event_node->event_name, name);
node->pub_registered_flag = 1;
return node->next_event_node;
}
@@ -189,7 +124,7 @@ uint8_t PubPushMessage(Publisher_t *pub, void *data_ptr)
while (iter)
{
if (iter->temp_size == QUEUE_SIZE) // 如果队列已满,则需要删除最老的数据(头部),再填入
{
{
// 队列头索引前移动,相当于抛弃前一个位置的数据,被抛弃的位置稍后会被写入新的数据
iter->front_idx = (iter->front_idx + 1) % QUEUE_SIZE;
iter->temp_size--; // 相当于出队,size-1

View File

@@ -19,30 +19,6 @@
#define MAX_EVENT_COUNT 12 // 最多支持的事件数量
#define QUEUE_SIZE 1
/**
* @brief 在所有应用初始化结束之后调用,当作app的"回调函数"
*
*/
void MessageInit();
/**
* @brief 注册成为消息发布者
*
* @param name 消息标识名,注意不要超过MAX_EVENT_NAME_LEN
* @param data 发布者的数据地址
*/
void PublisherRegister(char *name, void *data);
/**
* @brief 订阅消息,成为消息订阅者
*
* @param name 消息标识名
* @param data 保存数据的指针的地址,注意这是一个二级指针,传入的时候对数据指针取地址(&)
*/
void SubscribeEvent(char *name, void **data);
#endif // !PUBSUB_H
typedef struct mqt
{
/* 用数组模拟FIFO队列 */
@@ -69,6 +45,7 @@ typedef struct ent
Subscriber_t *first_subs;
/* 指向下一个Publisher的指针 */
struct ent *next_event_node;
uint8_t pub_registered_flag; // 用于标记该发布者是否已经注册
} Publisher_t;
/**
@@ -105,3 +82,5 @@ uint8_t SubGetMessage(Subscriber_t *sub, void *data_ptr);
* @return uint8_t 新消息成功推送给几个订阅者
*/
uint8_t PubPushMessage(Publisher_t *pub, void *data_ptr);
#endif // !PUBSUB_H

View File

@@ -1,5 +1,6 @@
#include "dji_motor.h"
#include "general_def.h"
#include "bsp_log.h"
static uint8_t idx = 0; // register idx,是该文件的全局电机索引,在注册时使用
@@ -32,16 +33,6 @@ static CANInstance sender_assignment[6] = {
*/
static uint8_t sender_enable_flag[6] = {0};
/**
* @brief 当注册的电机id冲突时,会进入这个函数并提示冲突的ID
* @todo 通过segger jlink 发送日志
*/
static void IDcrash_Handler(uint8_t conflict_motor_idx, uint8_t temp_motor_idx)
{
while (1)
;
}
/**
* @brief 根据电调/拨码开关上的ID,根据说明书的默认id分配方式计算发送ID和接收ID,
* 并对电机进行分组以便处理多电机控制命令
@@ -79,7 +70,10 @@ static void MotorSenderGrouping(DJIMotorInstance *motor, CAN_Init_Config_s *conf
for (size_t i = 0; i < idx; ++i)
{
if (dji_motor_instance[i]->motor_can_instance->can_handle == config->can_handle && dji_motor_instance[i]->motor_can_instance->rx_id == config->rx_id)
IDcrash_Handler(i, idx);
{
LOGERROR("[dji_motor] ID crash. Check in debug mode, add dji_motor_instance to watch to get more information."); // 后续可以把id和CAN打印出来
while (1); // 6020的id 1-4和2006/3508的id 5-8会发生冲突(若有注册,即1!5,2!6,3!7,4!8) (1!5!,LTC! (((不是)
}
}
break;
@@ -103,7 +97,10 @@ static void MotorSenderGrouping(DJIMotorInstance *motor, CAN_Init_Config_s *conf
for (size_t i = 0; i < idx; ++i)
{
if (dji_motor_instance[i]->motor_can_instance->can_handle == config->can_handle && dji_motor_instance[i]->motor_can_instance->rx_id == config->rx_id)
IDcrash_Handler(i, idx);
{
LOGERROR("[dji_motor] ID crash. Check in debug mode, add dji_motor_instance to watch to get more information.");
while (1); // 6020的id 1-4和2006/3508的id 5-8会发生冲突(若有注册,即1!5,2!6,3!7,4!8)
}
}
break;
@@ -126,6 +123,7 @@ static void DecodeDJIMotor(CANInstance *_instance)
static DJI_Motor_Measure_s *measure;
rxbuff = _instance->rx_buff;
// 这里对can instance的id进行了强制转换,从而获得电机的instance实例地址
// _instance指针指向的id是对应电机instance的地址,通过强制转换为电机instance的指针,再通过->运算符访问电机的成员motor_measure,最后取地址获得指针
measure = &(((DJIMotorInstance *)_instance->id)->motor_measure); // measure要多次使用,保存指针减小访存开销
// 解析数据并对电流和速度进行滤波,电机的反馈报文具体格式见电机说明手册
@@ -138,7 +136,7 @@ static void DecodeDJIMotor(CANInstance *_instance)
CURRENT_SMOOTH_COEF * (float)((int16_t)(rxbuff[4] << 8 | rxbuff[5]));
measure->temperate = rxbuff[6];
// 多圈角度计算,前提是两次采样间电机转过的角度小于180°,高速转动时可能会出现问题,自己画个图就清楚计算过程了
// 多圈角度计算,前提是假设两次采样间电机转过的角度小于180°,自己画个图就清楚计算过程了
if (measure->ecd - measure->last_ecd > 4096)
measure->total_round--;
else if (measure->ecd - measure->last_ecd < -4096)
@@ -190,8 +188,7 @@ void DJIMotorChangeFeed(DJIMotorInstance *motor, Closeloop_Type_e loop, Feedback
}
else
{
while (1)
; // LOOP TYPE ERROR!!!检查是否传入了正确的LOOP类型,或发生了指针越界
LOGERROR("[dji_motor] loop type error, check memory access and func param");// 检查是否传入了正确的LOOP类型,或发生了指针越界
}
}

View File

@@ -7,6 +7,10 @@
> 1. 给不同的电机设置不同的低通滤波器惯性系数而不是统一使用宏
> 2. 为M2006和M3508增加开环的零位校准函数
---
> 建议将电机的反馈频率通过RoboMaster Assistant统一设置为500Hz。当前默认的`MotorTask()`执行频率为500Hz若不修改电机反馈频率可能导致单条总线挂载的电机数量有限且容易出现帧错误和仲裁失败的情况。
## 总览和封装说明
> 如果你不需要理解该模块的工作原理,你只需要查看这一小节。
@@ -19,7 +23,7 @@ dji_motor模块对DJI智能电机包括M2006M3508以及GM6020进行了详
2. ==速度环为角速度,单位为**度/每秒**deg/sec==
3. ==电流环为mA==
3. ==电流环为A==
4. ==GM6020的输入设定为**力矩**,待测量(-30000~30000==

View File

@@ -16,7 +16,7 @@ static void LKMotorDecode(CANInstance *_instance)
static LKMotor_Measure_t *measure;
static uint8_t *rx_buff;
rx_buff = _instance->rx_buff;
measure = &((LKMotorInstance *)_instance)->measure; // 通过caninstance保存的id获取对应的motorinstance
measure = &(((LKMotorInstance *)_instance->id)->measure); // 通过caninstance保存的id获取对应的motorinstance
measure->last_ecd = measure->ecd;
measure->ecd = (uint16_t)((rx_buff[7] << 8) | rx_buff[6]);
@@ -59,7 +59,10 @@ LKMotorInstance *LKMotorInit(Motor_Init_Config_s *config)
motor->motor_can_ins = CANRegister(&config->can_init_config);
if (idx == 0) // 用第一个电机的can instance发送数据
{
sender_instance = motor->motor_can_ins;
sender_instance->tx_id = 0x280; // 修改tx_id为0x280,用于多电机发送,不用管其他LKMotorInstance的tx_id,它们仅作初始化用
}
LKMotorEnable(motor);
lkmotor_instance[idx++] = motor;

View File

@@ -2,4 +2,6 @@
这是瓴控电机的模块封装说明文档。关于LK电机的控制报文和反馈报文值详见LK电机的说明文档由于电机实例已经自带三环PID计算一般来说**我们能用到的只有单电机的力矩指令和多电机指令。**
注意LK电机在使用多电机发送的时候只支持一条总线上至多4个电机多电机模式下LK仅支持发送id 0x280为接收ID为0x140+id.
注意LK电机在使用多电机发送的时候只支持一条总线上至多4个电机多电机模式下LK仅支持发送id 0x280为接收ID为0x140+id.
要设置为多电机模式请通过串口连接电机并使用该文件夹下的LK motor tool.exe进行配置。

View File

@@ -136,20 +136,18 @@ void Append_CRC8_Check_Sum( uint8_t *pchMessage, uint16_t dwLength)
*/
uint16_t Get_CRC16_Check_Sum(uint8_t *pchMessage,uint32_t dwLength,uint16_t wCRC)
{
uint8_t chData;
if (pchMessage == NULL)
{
return 0xFFFF;
}
while(dwLength--)
{
chData = *pchMessage++;
(wCRC) = ((uint16_t)(wCRC) >> 8) ^
wCRC_Table[((uint16_t)(wCRC) ^ (uint16_t)(chData)) & 0x00ff];
}
return wCRC;
uint8_t chData;
if (pchMessage == NULL)
{
return 0xFFFF;
}
while(dwLength--)
{
chData = *pchMessage++;
(wCRC) = ((uint16_t)(wCRC) >> 8) ^
wCRC_Table[((uint16_t)(wCRC) ^ (uint16_t)(chData)) & 0x00ff];
}
return wCRC;
}

View File

@@ -1,357 +0,0 @@
/**
* @file referee.h
* @author kidneygood (you@domain.com)
* @brief
* @version 0.1
* @date 2022-11-18
*
* @copyright Copyright (c) 2022
*
*/
#ifndef REFEREE_H
#define REFEREE_H
#include "bsp_usart.h"
#include "usart.h"
#define FALSE 0
#define TRUE 1
#define JUDGE_DATA_ERROR 0
#define JUDGE_DATA_CORRECT 1
#define LEN_HEADER 5 // 帧头长
#define LEN_CMDID 2 // 命令码长度
#define LEN_TAIL 2 // 帧尾CRC16
// 起始字节,协议固定为0xA5
#define JUDGE_FRAME_HEADER (0xA5)
#pragma pack(1)
/***************裁判系统数据接收********************/
typedef enum
{
FRAME_HEADER = 0,
CMD_ID = 5,
DATA = 7,
} JudgeFrameOffset;
// 5字节帧头,偏移位置
typedef enum
{
SOF = 0, // 起始位
DATA_LENGTH = 1, // 帧内数据长度,根据这个来获取数据长度
SEQ = 3, // 包序号
CRC8 = 4 // CRC8
} FrameHeaderOffset;
// 命令码ID,用来判断接收的是什么数据
typedef enum
{
ID_game_state = 0x0001, // 比赛状态数据
ID_game_result = 0x0002, // 比赛结果数据
ID_game_robot_survivors = 0x0003, // 比赛机器人血量数据
ID_event_data = 0x0101, // 场地事件数据
ID_supply_projectile_action = 0x0102, // 场地补给站动作标识数据
ID_supply_projectile_booking = 0x0103, // 场地补给站预约子弹数据
ID_game_robot_state = 0x0201, // 机器人状态数据
ID_power_heat_data = 0x0202, // 实时功率热量数据
ID_game_robot_pos = 0x0203, // 机器人位置数据
ID_buff_musk = 0x0204, // 机器人增益数据
ID_aerial_robot_energy = 0x0205, // 空中机器人能量状态数据
ID_robot_hurt = 0x0206, // 伤害状态数据
ID_shoot_data = 0x0207, // 实时射击数据
} CmdID;
// 命令码数据段长,根据官方协议来定义长度
typedef enum
{
LEN_game_state = 3, // 0x0001
LEN_game_result = 1, // 0x0002
LEN_game_robot_HP = 2, // 0x0003
LEN_event_data = 4, // 0x0101
LEN_supply_projectile_action = 4, // 0x0102
// LEN_game_robot_state = 15, // 0x0201
LEN_game_robot_state = 27, // 0x0201
LEN_power_heat_data = 14, // 0x0202
LEN_game_robot_pos = 16, // 0x0203
LEN_buff_musk = 1, // 0x0204
LEN_aerial_robot_energy = 1, // 0x0205
LEN_robot_hurt = 1, // 0x0206
LEN_shoot_data = 7, // 0x0207
} JudgeDataLength;
/* 自定义帧头 */
typedef struct
{
uint8_t SOF;
uint16_t DataLength;
uint8_t Seq;
uint8_t CRC8;
} xFrameHeader;
/* ID: 0x0001 Byte: 3 比赛状态数据 */
typedef struct
{
uint8_t game_type : 4;
uint8_t game_progress : 4;
uint16_t stage_remain_time;
} ext_game_state_t;
/* ID: 0x0002 Byte: 1 比赛结果数据 */
typedef struct
{
uint8_t winner;
} ext_game_result_t;
/* ID: 0x0003 Byte: 32 比赛机器人血量数据 */
typedef struct
{
uint16_t red_1_robot_HP;
uint16_t red_2_robot_HP;
uint16_t red_3_robot_HP;
uint16_t red_4_robot_HP;
uint16_t red_5_robot_HP;
uint16_t red_7_robot_HP;
uint16_t red_outpost_HP;
uint16_t red_base_HP;
uint16_t blue_1_robot_HP;
uint16_t blue_2_robot_HP;
uint16_t blue_3_robot_HP;
uint16_t blue_4_robot_HP;
uint16_t blue_5_robot_HP;
uint16_t blue_7_robot_HP;
uint16_t blue_outpost_HP;
uint16_t blue_base_HP;
} ext_game_robot_HP_t;
/* ID: 0x0101 Byte: 4 场地事件数据 */
typedef struct
{
uint32_t event_type;
} ext_event_data_t;
/* ID: 0x0102 Byte: 3 场地补给站动作标识数据 */
typedef struct
{
uint8_t supply_projectile_id;
uint8_t supply_robot_id;
uint8_t supply_projectile_step;
uint8_t supply_projectile_num;
} ext_supply_projectile_action_t;
/* ID: 0X0201 Byte: 27 机器人状态数据 */
typedef struct
{
uint8_t robot_id;
uint8_t robot_level;
uint16_t remain_HP;
uint16_t max_HP;
uint16_t shooter_id1_17mm_cooling_rate;
uint16_t shooter_id1_17mm_cooling_limit;
uint16_t shooter_id1_17mm_speed_limit;
uint16_t shooter_id2_17mm_cooling_rate;
uint16_t shooter_id2_17mm_cooling_limit;
uint16_t shooter_id2_17mm_speed_limit;
uint16_t shooter_id1_42mm_cooling_rate;
uint16_t shooter_id1_42mm_cooling_limit;
uint16_t shooter_id1_42mm_speed_limit;
uint16_t chassis_power_limit;
uint8_t mains_power_gimbal_output : 1;
uint8_t mains_power_chassis_output : 1;
uint8_t mains_power_shooter_output : 1;
} ext_game_robot_state_t;
/* ID: 0X0202 Byte: 14 实时功率热量数据 */
typedef struct
{
uint16_t chassis_volt;
uint16_t chassis_current;
float chassis_power; // 瞬时功率
uint16_t chassis_power_buffer; // 60焦耳缓冲能量
uint16_t shooter_heat0; // 17mm
uint16_t shooter_heat1;
} ext_power_heat_data_t;
/* ID: 0x0203 Byte: 16 机器人位置数据 */
typedef struct
{
float x;
float y;
float z;
float yaw;
} ext_game_robot_pos_t;
/* ID: 0x0204 Byte: 1 机器人增益数据 */
typedef struct
{
uint8_t power_rune_buff;
} ext_buff_musk_t;
/* ID: 0x0205 Byte: 1 空中机器人能量状态数据 */
typedef struct
{
uint8_t attack_time;
} aerial_robot_energy_t;
/* ID: 0x0206 Byte: 1 伤害状态数据 */
typedef struct
{
uint8_t armor_id : 4;
uint8_t hurt_type : 4;
} ext_robot_hurt_t;
/* ID: 0x0207 Byte: 7 实时射击数据 */
typedef struct
{
uint8_t bullet_type;
uint8_t shooter_id;
uint8_t bullet_freq;
float bullet_speed;
} ext_shoot_data_t;
/***************裁判系统数据********************/
/*
交互数据,包括一个统一的数据段头结构,
包含了内容 ID发送者以及接受者的 ID 和内容数据段,
整个交互数据的包总共长最大为 128 个字节,
减去 frame_header,cmd_id,frame_tail 以及数据段头结构的 6 个字节,
故而发送的内容数据段最大为 113。
整个交互数据 0x0301 的包上行频率为 10Hz。
机器人 ID
1英雄(红)
2工程(红)
3/4/5步兵(红)
6空中(红)
7哨兵(红)
11英雄(蓝)
12工程(蓝)
13/14/15步兵(蓝)
16空中(蓝)
17哨兵(蓝)。
客户端 ID
0x0101 为英雄操作手客户端( 红)
0x0102 ,工程操作手客户端 ((红 )
0x0103/0x0104/0x0105步兵操作手客户端(红)
0x0106空中操作手客户端((红)
0x0111英雄操作手客户端(蓝)
0x0112工程操作手客户端(蓝)
0x0113/0x0114/0x0115操作手客户端步兵(蓝)
0x0116空中操作手客户端(蓝)。
*/
/* 交互数据接收信息0x0301 */
typedef struct
{
uint16_t data_cmd_id;
uint16_t send_ID;
uint16_t receiver_ID;
} ext_student_interactive_header_data_t;
/*
客户端 客户端自定义数据cmd_id:0x0301。内容 ID:0xD180
发送频率:上限 10Hz
1. 客户端 客户端自定义数据cmd_id:0x0301。内容 ID:0xD180。发送频率上限 10Hz
字节偏移量 大小 说明 备注
0 2 数据的内容 ID 0xD180
2 2 送者的 ID 需要校验发送者机器人的 ID 正确性
4 2 客户端的 ID 只能为发送者机器人对应的客户端
6 4 自定义浮点数据 1
10 4 自定义浮点数据 2
14 4 自定义浮点数据 3
18 1 自定义 8 位数据 4
*/
typedef struct
{
float data1;
float data2;
float data3;
uint8_t masks;
} client_custom_data_t;
/*
学生机器人间通信 cmd_id 0x0301内容 ID:0x0200~0x02FF
交互数据 机器人间通信0x0301。
发送频率:上限 10Hz
字节偏移量 大小 说明 备注
0 2 数据的内容 ID 0x0200~0x02FF
可以在以上 ID 段选取,具体 ID 含义由参赛队自定义
2 2 发送者的 ID 需要校验发送者的 ID 正确性,
4 2 接收者的 ID 需要校验接收者的 ID 正确性,
例如不能发送到敌对机器人的ID
6 n 数据段 n 需要小于 113
*/
typedef struct
{
uint8_t data[10]; // 数据段,n需要小于113
} robot_interactive_data_t;
// 发送给客户端的信息
// 帧头 命令码 数据段头结构 数据段 帧尾
typedef struct
{
xFrameHeader txFrameHeader; // 帧头
uint16_t CmdID; // 命令码
ext_student_interactive_header_data_t dataFrameHeader; // 数据段头结构
client_custom_data_t clientData; // 数据段
uint16_t FrameTail; // 帧尾
} ext_SendClientData_t;
// 机器人交互信息
typedef struct
{
xFrameHeader txFrameHeader; // 帧头
uint16_t CmdID; // 命令码
ext_student_interactive_header_data_t dataFrameHeader; // 数据段头结构
robot_interactive_data_t interactData; // 数据段
uint16_t FrameTail; // 帧尾
} ext_CommunatianData_t;
// 裁判系统接收数据整合进一个结构体
typedef struct
{
xFrameHeader FrameHeader; // 接收到的帧头信息
uint16_t CmdID;
ext_game_state_t GameState; // 0x0001
ext_game_result_t GameResult; // 0x0002
ext_game_robot_HP_t GameRobotHP; // 0x0003
ext_event_data_t EventData; // 0x0101
ext_supply_projectile_action_t SupplyProjectileAction; // 0x0102
ext_game_robot_state_t GameRobotStat; // 0x0201
ext_power_heat_data_t PowerHeatData; // 0x0202
ext_game_robot_pos_t GameRobotPos; // 0x0203
ext_buff_musk_t BuffMusk; // 0x0204
aerial_robot_energy_t AerialRobotEnergy; // 0x0205
ext_robot_hurt_t RobotHurt; // 0x0206
ext_shoot_data_t ShootData; // 0x0207
ext_SendClientData_t ShowData; // 客户端信息
ext_CommunatianData_t CommuData; // 队友通信信息
} referee_info_t;
#pragma pack()
/**
* @brief 初始化裁判系统,返回接收数据指针
*
* @param referee_usart_handle
* @return referee_info_t*
*/
referee_info_t* RefereeInit(UART_HandleTypeDef *referee_usart_handle);
#endif // !REFEREE_H

View File

@@ -0,0 +1,3 @@
# referee
当前模块组织较为混乱,后续统一为多机通信+裁判系统信息接收+UI绘制。UI绘制和多机通信的发送部分在referee任务中以一定的频率运行信息的接收通过中断完成。

View File

@@ -0,0 +1,433 @@
/**
* @file referee_UI.C
* @author kidneygood (you@domain.com)
* @brief
* @version 0.1
* @date 2023-1-18
*
* @copyright Copyright (c) 2022
*
*/
#include "referee_UI.h"
#include "string.h"
#include "crc.h"
#include "stdio.h"
#include "rm_referee.h"
// 包序号
/********************************************删除操作*************************************
**参数_id 对应的id结构体
Del_Operate 对应头文件删除操作
Del_Layer 要删除的层 取值0-9
*****************************************************************************************/
void UI_Delete(referee_id_t *_id, uint8_t Del_Operate, uint8_t Del_Layer)
{
UI_delete_t UI_delete_data;
uint8_t temp_datalength = Interactive_Data_LEN_Head + UI_Operate_LEN_Del; // 计算交互数据长度
UI_delete_data.FrameHeader.SOF = REFEREE_SOF;
UI_delete_data.FrameHeader.DataLength = temp_datalength;
UI_delete_data.FrameHeader.Seq = UI_Seq;
UI_delete_data.FrameHeader.CRC8 = Get_CRC8_Check_Sum((uint8_t *)&UI_delete_data, LEN_CRC8, 0xFF);
UI_delete_data.CmdID = ID_student_interactive;
UI_delete_data.datahead.data_cmd_id = UI_Data_ID_Del;
UI_delete_data.datahead.receiver_ID = _id->Cilent_ID;
UI_delete_data.datahead.sender_ID = _id->Robot_ID;
UI_delete_data.Delete_Operate = Del_Operate; // 删除操作
UI_delete_data.Layer = Del_Layer;
UI_delete_data.frametail = Get_CRC16_Check_Sum((uint8_t *)&UI_delete_data, LEN_HEADER + LEN_CMDID + temp_datalength, 0xFFFF);
/* 填入0xFFFF,关于crc校验 */
RefereeSend((uint8_t *)&UI_delete_data, LEN_HEADER + LEN_CMDID + temp_datalength + LEN_TAIL); // 发送
UI_Seq++; // 包序号+1
}
/************************************************绘制直线*************************************************
**参数:*graph Graph_Data类型变量指针用于存放图形数据
graphname[3] 图片名称,用于标识更改
Graph_Operate 图片操作,见头文件
Graph_Layer 图层0-9
Graph_Color 图形颜色
Graph_Width 图形线宽
Start_x、Start_y 起点xy坐标
End_x、End_y 终点xy坐标
**********************************************************************************************************/
void Line_Draw(Graph_Data_t *graph, char graphname[3], uint32_t Graph_Operate, uint32_t Graph_Layer, uint32_t Graph_Color,
uint32_t Graph_Width, uint32_t Start_x, uint32_t Start_y, uint32_t End_x, uint32_t End_y)
{
int i;
for (i = 0; i < 3 && graphname[i] != '\0'; i++) // 填充至0为止
{
graph->graphic_name[2 - i] = graphname[i]; // 按内存地址增大方向填充所以会有i与2-i
}
graph->operate_tpye = Graph_Operate;
graph->graphic_tpye = UI_Graph_Line;
graph->layer = Graph_Layer;
graph->color = Graph_Color;
graph->start_angle = 0;
graph->end_angle = 0;
graph->width = Graph_Width;
graph->start_x = Start_x;
graph->start_y = Start_y;
graph->radius = 0;
graph->end_x = End_x;
graph->end_y = End_y;
}
/************************************************绘制矩形*************************************************
**参数:*graph Graph_Data类型变量指针用于存放图形数据
graphname[3] 图片名称,用于标识更改
Graph_Operate 图片操作,见头文件
Graph_Layer 图层0-9
Graph_Color 图形颜色
Graph_Width 图形线宽
Start_x、Start_y 起点xy坐标
End_x、End_y 对角顶点xy坐标
**********************************************************************************************************/
void Rectangle_Draw(Graph_Data_t *graph, char graphname[3], uint32_t Graph_Operate, uint32_t Graph_Layer, uint32_t Graph_Color,
uint32_t Graph_Width, uint32_t Start_x, uint32_t Start_y, uint32_t End_x, uint32_t End_y)
{
int i;
for (i = 0; i < 3 && graphname[i] != '\0'; i++)
{
graph->graphic_name[2 - i] = graphname[i];
}
graph->graphic_tpye = UI_Graph_Rectangle;
graph->operate_tpye = Graph_Operate;
graph->layer = Graph_Layer;
graph->color = Graph_Color;
graph->start_angle = 0;
graph->end_angle = 0;
graph->width = Graph_Width;
graph->start_x = Start_x;
graph->start_y = Start_y;
graph->radius = 0;
graph->end_x = End_x;
graph->end_y = End_y;
}
/************************************************绘制整圆*************************************************
**参数:*graph Graph_Data类型变量指针用于存放图形数据
graphname[3] 图片名称,用于标识更改
Graph_Operate 图片操作,见头文件
Graph_Layer 图层0-9
Graph_Color 图形颜色
Graph_Width 图形线宽
Start_x、Start_y 圆心xy坐标
Graph_Radius 圆形半径
**********************************************************************************************************/
void Circle_Draw(Graph_Data_t *graph, char graphname[3], uint32_t Graph_Operate, uint32_t Graph_Layer, uint32_t Graph_Color,
uint32_t Graph_Width, uint32_t Start_x, uint32_t Start_y, uint32_t Graph_Radius)
{
int i;
for (i = 0; i < 3 && graphname[i] != '\0'; i++)
{
graph->graphic_name[2 - i] = graphname[i];
}
graph->graphic_tpye = UI_Graph_Circle;
graph->operate_tpye = Graph_Operate;
graph->layer = Graph_Layer;
graph->color = Graph_Color;
graph->start_angle = 0;
graph->end_angle = 0;
graph->width = Graph_Width;
graph->start_x = Start_x;
graph->start_y = Start_y;
graph->radius = Graph_Radius;
graph->end_x = 0;
graph->end_y = 0;
}
/************************************************绘制椭圆*************************************************
**参数:*graph Graph_Data类型变量指针用于存放图形数据
graphname[3] 图片名称,用于标识更改
Graph_Operate 图片操作,见头文件
Graph_Layer 图层0-9
Graph_Color 图形颜色
Graph_Width 图形线宽
Start_x、Start_y 圆心xy坐标
End_x、End_y xy半轴长度
**********************************************************************************************************/
void Elliptical_Draw(Graph_Data_t *graph, char graphname[3], uint32_t Graph_Operate, uint32_t Graph_Layer, uint32_t Graph_Color,
uint32_t Graph_Width, uint32_t Start_x, uint32_t Start_y, uint32_t end_x, uint32_t end_y)
{
int i;
for (i = 0; i < 3 && graphname[i] != '\0'; i++)
{
graph->graphic_name[2 - i] = graphname[i];
}
graph->graphic_tpye = UI_Graph_Ellipse;
graph->operate_tpye = Graph_Operate;
graph->layer = Graph_Layer;
graph->color = Graph_Color;
graph->width = Graph_Width;
graph->start_angle = 0;
graph->end_angle = 0;
graph->width = Graph_Width;
graph->start_x = Start_x;
graph->start_y = Start_y;
graph->radius = 0;
graph->end_x = end_x;
graph->end_y = end_y;
}
/************************************************绘制圆弧*************************************************
**参数:*graph Graph_Data类型变量指针用于存放图形数据
graphname[3] 图片名称,用于标识更改
Graph_Operate 图片操作,见头文件
Graph_Layer 图层0-9
Graph_Color 图形颜色
Graph_StartAngle,Graph_EndAngle 起始终止角度
Graph_Width 图形线宽
Start_y,Start_y 圆心xy坐标
x_Length,y_Length xy半轴长度
**********************************************************************************************************/
void Arc_Draw(Graph_Data_t *graph, char graphname[3], uint32_t Graph_Operate, uint32_t Graph_Layer, uint32_t Graph_Color,
uint32_t Graph_StartAngle, uint32_t Graph_EndAngle, uint32_t Graph_Width, uint32_t Start_x, uint32_t Start_y,
uint32_t end_x, uint32_t end_y)
{
int i;
for (i = 0; i < 3 && graphname[i] != '\0'; i++)
{
graph->graphic_name[2 - i] = graphname[i];
}
graph->graphic_tpye = UI_Graph_Arc;
graph->operate_tpye = Graph_Operate;
graph->layer = Graph_Layer;
graph->color = Graph_Color;
graph->start_angle = Graph_StartAngle;
graph->end_angle = Graph_EndAngle;
graph->width = Graph_Width;
graph->start_x = Start_x;
graph->start_y = Start_y;
graph->radius = 0;
graph->end_x = end_x;
graph->end_y = end_y;
}
/************************************************绘制浮点型数据*************************************************
**参数:*graph Graph_Data类型变量指针用于存放图形数据
graphname[3] 图片名称,用于标识更改
Graph_Operate 图片操作,见头文件
Graph_Layer 图层0-9
Graph_Color 图形颜色
Graph_Size 字号
Graph_Digit 小数位数
Graph_Width 图形线宽
Start_x、Start_y 开始坐标
radius=a&0x3FF; a为浮点数乘以1000后的32位整型数
end_x=(a>>10)&0x7FF;
end_y=(a>>21)&0x7FF;
**********************************************************************************************************/
void Float_Draw(Graph_Data_t *graph, char graphname[3], uint32_t Graph_Operate, uint32_t Graph_Layer, uint32_t Graph_Color,
uint32_t Graph_Size, uint32_t Graph_Digit, uint32_t Graph_Width, uint32_t Start_x, uint32_t Start_y, int32_t Graph_Float)
{
int i;
for (i = 0; i < 3 && graphname[i] != '\0'; i++)
{
graph->graphic_name[2 - i] = graphname[i];
}
graph->graphic_tpye = UI_Graph_Float;
graph->operate_tpye = Graph_Operate;
graph->layer = Graph_Layer;
graph->color = Graph_Color;
graph->width = Graph_Width;
graph->start_x = Start_x;
graph->start_y = Start_y;
graph->start_angle = Graph_Size;
graph->end_angle = Graph_Digit;
graph->radius = Graph_Float & 0x3FF;
graph->end_x = (Graph_Float >> 10) & 0x7FF;
graph->end_y = (Graph_Float >> 21) & 0x7FF;
}
/************************************************绘制整型数据*************************************************
**参数:*graph Graph_Data类型变量指针用于存放图形数据
graphname[3] 图片名称,用于标识更改
Graph_Operate 图片操作,见头文件
Graph_Layer 图层0-9
Graph_Color 图形颜色
Graph_Size 字号
Graph_Width 图形线宽
Start_x、Start_y 开始坐标
radius=a&0x3FF; a为32位整型数
end_x=(a>>10)&0x7FF;
end_y=(a>>21)&0x7FF;
**********************************************************************************************************/
void Integer_Draw(Graph_Data_t *graph, char graphname[3], uint32_t Graph_Operate, uint32_t Graph_Layer, uint32_t Graph_Color,
uint32_t Graph_Size, uint32_t Graph_Width, uint32_t Start_x, uint32_t Start_y, int32_t Graph_Integer)
{
int i;
for (i = 0; i < 3 && graphname[i] != '\0'; i++)
{
graph->graphic_name[2 - i] = graphname[i];
}
graph->graphic_tpye = UI_Graph_Int;
graph->operate_tpye = Graph_Operate;
graph->layer = Graph_Layer;
graph->color = Graph_Color;
graph->start_angle = Graph_Size;
graph->end_angle = 0;
graph->width = Graph_Width;
graph->start_x = Start_x;
graph->start_y = Start_y;
graph->radius = Graph_Integer & 0x3FF;
graph->end_x = (Graph_Integer >> 10) & 0x7FF;
graph->end_y = (Graph_Integer >> 21) & 0x7FF;
}
/************************************************绘制字符型数据*************************************************
**参数:*graph Graph_Data类型变量指针用于存放图形数据
graphname[3] 图片名称,用于标识更改
Graph_Operate 图片操作,见头文件
Graph_Layer 图层0-9
Graph_Color 图形颜色
Graph_Size 字号
Graph_Width 图形线宽
Start_x、Start_y 开始坐标
**********************************************************************************************************/
void Char_Draw(String_Data_t *graph, char graphname[3], uint32_t Graph_Operate, uint32_t Graph_Layer, uint32_t Graph_Color,
uint32_t Graph_Size, uint32_t Graph_Width, uint32_t Start_x, uint32_t Start_y)
{
int i;
for (i = 0; i < 3 && graphname[i] != '\0'; i++)
{
graph->Graph_Control.graphic_name[2 - i] = graphname[i];
}
graph->Graph_Control.graphic_tpye = UI_Graph_Char;
graph->Graph_Control.operate_tpye = Graph_Operate;
graph->Graph_Control.layer = Graph_Layer;
graph->Graph_Control.color = Graph_Color;
graph->Graph_Control.width = Graph_Width;
graph->Graph_Control.start_x = Start_x;
graph->Graph_Control.start_y = Start_y;
graph->Graph_Control.start_angle = Graph_Size;
graph->Graph_Control.radius = 0;
graph->Graph_Control.end_x = 0;
graph->Graph_Control.end_y = 0;
}
/************************************************绘制字符型数据*************************************************
**参数:*graph Graph_Data类型变量指针用于存放图形数据
fmt需要显示的字符串
此函数的实现和具体使用类似于printf函数
**********************************************************************************************************/
void Char_Write(String_Data_t *graph, char *fmt, ...)
{
uint16_t i = 0;
va_list ap;
va_start(ap, fmt);
vsprintf((char *)graph->show_Data, fmt, ap); // 使用参数列表进行格式化并输出到字符串
va_end(ap);
i = strlen((const char *)graph->show_Data);
graph->Graph_Control.end_angle = i;
}
/* UI推送函数使更改生效
参数: cnt 图形个数
... 图形变量参数
Tips该函数只能推送1257个图形其他数目协议未涉及
*/
void UI_ReFresh(referee_id_t *_id, int cnt, ...)
{
int i;
UI_GraphReFresh_t UI_GraphReFresh_data;
Graph_Data_t graphData;
va_list ap; // 创建一个 va_list 类型变量
va_start(ap, cnt); // 初始化 va_list 变量为一个参数列表
UI_GraphReFresh_data.FrameHeader.SOF = REFEREE_SOF;
UI_GraphReFresh_data.FrameHeader.DataLength = Interactive_Data_LEN_Head + cnt * UI_Operate_LEN_PerDraw;
UI_GraphReFresh_data.FrameHeader.Seq = UI_Seq;
UI_GraphReFresh_data.FrameHeader.CRC8 = Get_CRC8_Check_Sum((uint8_t *)&UI_GraphReFresh_data, LEN_CRC8, 0xFF);
UI_GraphReFresh_data.CmdID = ID_student_interactive;
switch (cnt)
{
case 1:
UI_GraphReFresh_data.datahead.data_cmd_id = UI_Data_ID_Draw1;
break;
case 2:
UI_GraphReFresh_data.datahead.data_cmd_id = UI_Data_ID_Draw2;
break;
case 5:
UI_GraphReFresh_data.datahead.data_cmd_id = UI_Data_ID_Draw5;
break;
case 7:
UI_GraphReFresh_data.datahead.data_cmd_id = UI_Data_ID_Draw7;
break;
}
UI_GraphReFresh_data.datahead.receiver_ID = _id->Cilent_ID;
UI_GraphReFresh_data.datahead.sender_ID = _id->Robot_ID;
// 先发送帧头、命令码、交互数据帧头三部分并计算CRC16校验值
UI_GraphReFresh_data.frametail = Get_CRC16_Check_Sum((uint8_t *)&UI_GraphReFresh_data, LEN_HEADER + LEN_CMDID + Interactive_Data_LEN_Head, 0xFFFF);
RefereeSend((uint8_t *)&UI_GraphReFresh_data, LEN_HEADER + LEN_CMDID + Interactive_Data_LEN_Head);
for (i = 0; i < cnt; i++) // 发送交互数据的数据帧并计算CRC16校验值
{
graphData = va_arg(ap, Graph_Data_t); // 访问参数列表中的每个项,第二个参数是你要返回的参数的类型,在取值时需要将其强制转化为指定类型的变量
// 发送并计算CRC16
RefereeSend((uint8_t *)&graphData, UI_Operate_LEN_PerDraw);
UI_GraphReFresh_data.frametail = Get_CRC16_Check_Sum((uint8_t *)&graphData, UI_Operate_LEN_PerDraw, UI_GraphReFresh_data.frametail);
}
RefereeSend((uint8_t *)&UI_GraphReFresh_data.frametail, LEN_TAIL); // 发送CRC16校验值
va_end(ap); // 结束可变参数的获取
UI_Seq++; // 包序号+1
}
/************************************************UI推送字符使更改生效*********************************/
void Char_ReFresh(referee_id_t *_id, String_Data_t string_Data)
{
UI_CharReFresh_t UI_CharReFresh_data;
uint8_t temp_datalength = Interactive_Data_LEN_Head + UI_Operate_LEN_DrawChar; // 计算交互数据长度
UI_CharReFresh_data.FrameHeader.SOF = REFEREE_SOF;
UI_CharReFresh_data.FrameHeader.DataLength = temp_datalength;
UI_CharReFresh_data.FrameHeader.Seq = UI_Seq;
UI_CharReFresh_data.FrameHeader.CRC8 = Get_CRC8_Check_Sum((uint8_t *)&UI_CharReFresh_data, LEN_CRC8, 0xFF);
UI_CharReFresh_data.CmdID = ID_student_interactive;
UI_CharReFresh_data.datahead.data_cmd_id = UI_Data_ID_DrawChar;
UI_CharReFresh_data.datahead.receiver_ID = _id->Cilent_ID;
UI_CharReFresh_data.datahead.sender_ID = _id->Robot_ID;
UI_CharReFresh_data.String_Data = string_Data;
UI_CharReFresh_data.frametail = Get_CRC16_Check_Sum((uint8_t *)&UI_CharReFresh_data, LEN_HEADER + LEN_CMDID + temp_datalength, 0xFFFF);
RefereeSend((uint8_t *)&UI_CharReFresh_data, LEN_HEADER + LEN_CMDID + temp_datalength + LEN_TAIL); // 发送
UI_Seq++; // 包序号+1
}

View File

@@ -0,0 +1,77 @@
#ifndef REFEREE_UI_H
#define REFEREE_UI_H
#include "stdarg.h"
#include "stdint.h"
#include "referee_def.h"
#include "rm_referee.h"
#pragma pack(1) //按1字节对齐
/* 此处的定义只与UI绘制有关 */
typedef struct
{
xFrameHeader FrameHeader;
uint16_t CmdID;
ext_student_interactive_header_data_t datahead;
uint8_t Delete_Operate; //删除操作
uint8_t Layer;
uint16_t frametail;
} UI_delete_t;
typedef struct
{
xFrameHeader FrameHeader;
uint16_t CmdID;
ext_student_interactive_header_data_t datahead;
uint16_t frametail;
} UI_GraphReFresh_t;
typedef struct
{
xFrameHeader FrameHeader;
uint16_t CmdID;
ext_student_interactive_header_data_t datahead;
String_Data_t String_Data;
uint16_t frametail;
} UI_CharReFresh_t; //打印字符串数据
#pragma pack()
void UI_Delete(referee_id_t *_id,uint8_t Del_Operate,uint8_t Del_Layer);
void Line_Draw(Graph_Data_t *graph,char graphname[3],uint32_t Graph_Operate,uint32_t Graph_Layer,uint32_t Graph_Color,
uint32_t Graph_Width,uint32_t Start_x,uint32_t Start_y,uint32_t End_x,uint32_t End_y);
void Rectangle_Draw(Graph_Data_t *graph,char graphname[3],uint32_t Graph_Operate,uint32_t Graph_Layer,uint32_t Graph_Color,
uint32_t Graph_Width,uint32_t Start_x,uint32_t Start_y,uint32_t End_x,uint32_t End_y);
void Circle_Draw(Graph_Data_t *graph,char graphname[3],uint32_t Graph_Operate,uint32_t Graph_Layer,uint32_t Graph_Color,
uint32_t Graph_Width,uint32_t Start_x,uint32_t Start_y,uint32_t Graph_Radius);
void Elliptical_Draw(Graph_Data_t *graph,char graphname[3],uint32_t Graph_Operate,uint32_t Graph_Layer,uint32_t Graph_Color,
uint32_t Graph_Width,uint32_t Start_x,uint32_t Start_y,uint32_t end_x,uint32_t end_y);
void Arc_Draw(Graph_Data_t *graph,char graphname[3],uint32_t Graph_Operate,uint32_t Graph_Layer,uint32_t Graph_Color,
uint32_t Graph_StartAngle,uint32_t Graph_EndAngle,uint32_t Graph_Width,uint32_t Start_x,uint32_t Start_y,
uint32_t end_x,uint32_t end_y);
void Float_Draw(Graph_Data_t *graph,char graphname[3],uint32_t Graph_Operate,uint32_t Graph_Layer,uint32_t Graph_Color,
uint32_t Graph_Size,uint32_t Graph_Digit,uint32_t Graph_Width,uint32_t Start_x,uint32_t Start_y,int32_t Graph_Float);
void Integer_Draw(Graph_Data_t *graph,char graphname[3],uint32_t Graph_Operate,uint32_t Graph_Layer,uint32_t Graph_Color,
uint32_t Graph_Size,uint32_t Graph_Width,uint32_t Start_x,uint32_t Start_y,int32_t Graph_Integer);
void Char_Draw(String_Data_t *graph,char graphname[3],uint32_t Graph_Operate,uint32_t Graph_Layer,uint32_t Graph_Color,
uint32_t Graph_Size,uint32_t Graph_Width,uint32_t Start_x,uint32_t Start_y);
void Char_Write(String_Data_t *graph,char* fmt, ...);
void UI_ReFresh(referee_id_t *_id,int cnt,...);
void Char_ReFresh(referee_id_t *_id,String_Data_t string_Data);
#endif

View File

@@ -0,0 +1,45 @@
/**
* @file referee_communication.h
* @author kidneygood (you@domain.com)
* @version 0.1
* @date 2022-12-02
*
* @copyright Copyright (c) HNU YueLu EC 2022 all rights reserved
*
*/
#include "referee_communication.h"
#include "crc.h"
#include "stdio.h"
#include "rm_referee.h"
/**
* @brief 发送机器人间的交互数据
* @param referee_id_t *_id sender为本机器人receiver为接收方机器人发送前设置Receiver_Robot_ID再调用该函数
* robot_interactive_data_t *data 数据段
* @retval none
* @attention
*/
void Communicate_SendData(referee_id_t *_id,robot_interactive_data_t *_data)
{
Communicate_SendData_t SendData;
uint8_t temp_datalength = Interactive_Data_LEN_Head + Communicate_Data_LEN; // 计算交互数据长度 6+n,n为交互数据长度
SendData.FrameHeader.SOF = REFEREE_SOF;
SendData.FrameHeader.DataLength = temp_datalength;
SendData.FrameHeader.Seq = UI_Seq;
SendData.FrameHeader.CRC8 = Get_CRC8_Check_Sum((uint8_t *)&SendData, LEN_CRC8, 0xFF);
SendData.CmdID = ID_student_interactive;
SendData.datahead.data_cmd_id = Communicate_Data_ID;
SendData.datahead.sender_ID = _id->Robot_ID;
SendData.datahead.receiver_ID = _id->Receiver_Robot_ID;
SendData.Data = *_data;
SendData.frametail = Get_CRC16_Check_Sum((uint8_t *)&SendData,LEN_HEADER+LEN_CMDID+temp_datalength,0xFFFF);
RefereeSend((uint8_t *)&SendData,LEN_HEADER+LEN_CMDID+temp_datalength+LEN_TAIL); //发送
UI_Seq++; // 包序号+1
}

View File

@@ -0,0 +1,10 @@
#ifndef REFEREE_COMMUNICATION_H
#define REFEREE_COMMUNICATION_H
#include "stdint.h"
#include "referee_def.h"
#include "rm_referee.h"
void Communicate_SendData(referee_id_t *_id,robot_interactive_data_t *_data);
#endif

View File

@@ -0,0 +1,397 @@
/**
* @file referee_def.h
* @author kidneygood (you@domain.com)
* @version 0.1
* @date 2022-12-02
*
* @copyright Copyright (c) HNU YueLu EC 2022 all rights reserved
*
*/
#ifndef REFEREE_DEF_H
#define REFEREE_DEF_H
#include "stdint.h"
/****************************宏定义部分****************************/
/****************************宏定义部分****************************/
#define REFEREE_SOF 0xA5 // 起始字节,协议固定为0xA5
#define Robot_Red 0
#define Robot_Blue 1
#define Communicate_Data_LEN 5 //自定义交互数据长度,该长度决定了我方发送和他方接收,自定义交互数据协议更改时只需要更改此宏定义即可
#pragma pack(1)
/****************************通信协议格式****************************/
/****************************通信协议格式****************************/
/* 通信协议格式偏移,枚举类型,代替#define声明 */
typedef enum
{
FRAME_HEADER_Offset = 0,
CMD_ID_Offset = 5,
DATA_Offset = 7,
} JudgeFrameOffset_e;
/* 通信协议长度 */
typedef enum
{
LEN_HEADER = 5, // 帧头长
LEN_CMDID = 2, // 命令码长度
LEN_TAIL = 2, // 帧尾CRC16
LEN_CRC8 = 4, // 帧头CRC8校验长度=帧头+数据长+包序号
} JudgeFrameLength_e;
/****************************帧头****************************/
/****************************帧头****************************/
/* 帧头偏移 */
typedef enum
{
SOF = 0, // 起始位
DATA_LENGTH = 1, // 帧内数据长度,根据这个来获取数据长度
SEQ = 3, // 包序号
CRC8 = 4 // CRC8
} FrameHeaderOffset_e;
/* 帧头定义 */
typedef struct
{
uint8_t SOF;
uint16_t DataLength;
uint8_t Seq;
uint8_t CRC8;
} xFrameHeader;
/****************************cmd_id命令码说明****************************/
/****************************cmd_id命令码说明****************************/
/* 命令码ID,用来判断接收的是什么数据 */
typedef enum
{
ID_game_state = 0x0001, // 比赛状态数据
ID_game_result = 0x0002, // 比赛结果数据
ID_game_robot_survivors = 0x0003, // 比赛机器人血量数据
ID_event_data = 0x0101, // 场地事件数据
ID_supply_projectile_action = 0x0102, // 场地补给站动作标识数据
ID_supply_projectile_booking = 0x0103, // 场地补给站预约子弹数据
ID_game_robot_state = 0x0201, // 机器人状态数据
ID_power_heat_data = 0x0202, // 实时功率热量数据
ID_game_robot_pos = 0x0203, // 机器人位置数据
ID_buff_musk = 0x0204, // 机器人增益数据
ID_aerial_robot_energy = 0x0205, // 空中机器人能量状态数据
ID_robot_hurt = 0x0206, // 伤害状态数据
ID_shoot_data = 0x0207, // 实时射击数据
ID_student_interactive = 0x0301, // 机器人间交互数据
} CmdID_e;
/* 命令码数据段长,根据官方协议来定义长度,还有自定义数据长度 */
typedef enum
{
LEN_game_state = 3, // 0x0001
LEN_game_result = 1, // 0x0002
LEN_game_robot_HP = 2, // 0x0003
LEN_event_data = 4, // 0x0101
LEN_supply_projectile_action = 4, // 0x0102
LEN_game_robot_state = 27, // 0x0201
LEN_power_heat_data = 14, // 0x0202
LEN_game_robot_pos = 16, // 0x0203
LEN_buff_musk = 1, // 0x0204
LEN_aerial_robot_energy = 1, // 0x0205
LEN_robot_hurt = 1, // 0x0206
LEN_shoot_data = 7, // 0x0207
LEN_receive_data = 6+Communicate_Data_LEN, //0x0301
} JudgeDataLength_e;
/****************************接收数据的详细说明****************************/
/****************************接收数据的详细说明****************************/
/* ID: 0x0001 Byte: 3 比赛状态数据 */
typedef struct
{
uint8_t game_type : 4;
uint8_t game_progress : 4;
uint16_t stage_remain_time;
} ext_game_state_t;
/* ID: 0x0002 Byte: 1 比赛结果数据 */
typedef struct
{
uint8_t winner;
} ext_game_result_t;
/* ID: 0x0003 Byte: 32 比赛机器人血量数据 */
typedef struct
{
uint16_t red_1_robot_HP;
uint16_t red_2_robot_HP;
uint16_t red_3_robot_HP;
uint16_t red_4_robot_HP;
uint16_t red_5_robot_HP;
uint16_t red_7_robot_HP;
uint16_t red_outpost_HP;
uint16_t red_base_HP;
uint16_t blue_1_robot_HP;
uint16_t blue_2_robot_HP;
uint16_t blue_3_robot_HP;
uint16_t blue_4_robot_HP;
uint16_t blue_5_robot_HP;
uint16_t blue_7_robot_HP;
uint16_t blue_outpost_HP;
uint16_t blue_base_HP;
} ext_game_robot_HP_t;
/* ID: 0x0101 Byte: 4 场地事件数据 */
typedef struct
{
uint32_t event_type;
} ext_event_data_t;
/* ID: 0x0102 Byte: 3 场地补给站动作标识数据 */
typedef struct
{
uint8_t supply_projectile_id;
uint8_t supply_robot_id;
uint8_t supply_projectile_step;
uint8_t supply_projectile_num;
} ext_supply_projectile_action_t;
/* ID: 0X0201 Byte: 27 机器人状态数据 */
typedef struct
{
uint8_t robot_id;
uint8_t robot_level;
uint16_t remain_HP;
uint16_t max_HP;
uint16_t shooter_id1_17mm_cooling_rate;
uint16_t shooter_id1_17mm_cooling_limit;
uint16_t shooter_id1_17mm_speed_limit;
uint16_t shooter_id2_17mm_cooling_rate;
uint16_t shooter_id2_17mm_cooling_limit;
uint16_t shooter_id2_17mm_speed_limit;
uint16_t shooter_id1_42mm_cooling_rate;
uint16_t shooter_id1_42mm_cooling_limit;
uint16_t shooter_id1_42mm_speed_limit;
uint16_t chassis_power_limit;
uint8_t mains_power_gimbal_output : 1;
uint8_t mains_power_chassis_output : 1;
uint8_t mains_power_shooter_output : 1;
} ext_game_robot_state_t;
/* ID: 0X0202 Byte: 14 实时功率热量数据 */
typedef struct
{
uint16_t chassis_volt;
uint16_t chassis_current;
float chassis_power; // 瞬时功率
uint16_t chassis_power_buffer; // 60焦耳缓冲能量
uint16_t shooter_heat0; // 17mm
uint16_t shooter_heat1;
} ext_power_heat_data_t;
/* ID: 0x0203 Byte: 16 机器人位置数据 */
typedef struct
{
float x;
float y;
float z;
float yaw;
} ext_game_robot_pos_t;
/* ID: 0x0204 Byte: 1 机器人增益数据 */
typedef struct
{
uint8_t power_rune_buff;
} ext_buff_musk_t;
/* ID: 0x0205 Byte: 1 空中机器人能量状态数据 */
typedef struct
{
uint8_t attack_time;
} aerial_robot_energy_t;
/* ID: 0x0206 Byte: 1 伤害状态数据 */
typedef struct
{
uint8_t armor_id : 4;
uint8_t hurt_type : 4;
} ext_robot_hurt_t;
/* ID: 0x0207 Byte: 7 实时射击数据 */
typedef struct
{
uint8_t bullet_type;
uint8_t shooter_id;
uint8_t bullet_freq;
float bullet_speed;
} ext_shoot_data_t;
/****************************机器人交互数据****************************/
/****************************机器人交互数据****************************/
/* 发送的内容数据段最大为 113 检测是否超出大小限制?实际上图形段不会超数据段最多30个也不会超*/
/* 交互数据头结构 */
typedef struct
{
uint16_t data_cmd_id; //由于存在多个内容 ID但整个cmd_id 上行频率最大为 10Hz请合理安排带宽。注意交互部分的上行频率
uint16_t sender_ID;
uint16_t receiver_ID;
} ext_student_interactive_header_data_t;
/* 机器人id */
typedef enum
{
// 红方机器人ID
RobotID_RHero = 1,
RobotID_REngineer = 2,
RobotID_RStandard1 = 3,
RobotID_RStandard2 = 4,
RobotID_RStandard3 = 5,
RobotID_RAerial = 6,
RobotID_RSentry = 7,
RobotID_RRadar = 9,
// 蓝方机器人ID
RobotID_BHero = 101,
RobotID_BEngineer = 102,
RobotID_BStandard1 = 103,
RobotID_BStandard2 = 104,
RobotID_BStandard3 = 105,
RobotID_BAerial = 106,
RobotID_BSentry = 107,
RobotID_BRadar = 109,
} Robot_ID_e;
/* 交互数据ID */
typedef enum
{
UI_Data_ID_Del = 0x100,
UI_Data_ID_Draw1 = 0x101,
UI_Data_ID_Draw2 = 0x102,
UI_Data_ID_Draw5 = 0x103,
UI_Data_ID_Draw7 = 0x104,
UI_Data_ID_DrawChar = 0x110,
/* 自定义交互数据部分 */
Communicate_Data_ID = 0x0200,
} Interactive_Data_ID_e;
/* 交互数据长度 */
typedef enum
{
Interactive_Data_LEN_Head = 6,
UI_Operate_LEN_Del = 2,
UI_Operate_LEN_PerDraw = 15,
UI_Operate_LEN_DrawChar = 15 + 30,
/* 自定义交互数据部分 */
// Communicate_Data_LEN = 5,
} Interactive_Data_Length_e;
/****************************自定义交互数据****************************/
/****************************自定义交互数据****************************/
/*
学生机器人间通信 cmd_id 0x0301内容 ID:0x0200~0x02FF
自定义交互数据 机器人间通信0x0301。
发送频率:上限 10Hz
*/
//自定义交互数据协议,可更改,更改后需要修改最上方宏定义数据长度的值
typedef struct
{
uint8_t data[Communicate_Data_LEN]; // 数据段,n需要小于113
} robot_interactive_data_t;
// 机器人交互信息_发送
typedef struct
{
xFrameHeader FrameHeader;
uint16_t CmdID;
ext_student_interactive_header_data_t datahead;
robot_interactive_data_t Data; // 数据段
uint16_t frametail;
} Communicate_SendData_t;
// 机器人交互信息_接收
typedef struct
{
ext_student_interactive_header_data_t datahead;
robot_interactive_data_t Data; // 数据段
} Communicate_ReceiveData_t;
/****************************UI交互数据****************************/
/****************************UI交互数据****************************/
/* 图形数据 */
typedef struct
{
uint8_t graphic_name[3];
uint32_t operate_tpye : 3;
uint32_t graphic_tpye : 3;
uint32_t layer : 4;
uint32_t color : 4;
uint32_t start_angle : 9;
uint32_t end_angle : 9;
uint32_t width : 10;
uint32_t start_x : 11;
uint32_t start_y : 11;
uint32_t radius : 10;
uint32_t end_x : 11;
uint32_t end_y : 11;
} Graph_Data_t;
typedef struct
{
Graph_Data_t Graph_Control;
uint8_t show_Data[30];
} String_Data_t; // 打印字符串数据
/* 删除操作 */
typedef enum
{
UI_Data_Del_NoOperate = 0,
UI_Data_Del_Layer = 1,
UI_Data_Del_ALL = 2, // 删除全部图层,后面的参数已经不重要了。
} UI_Delete_Operate_e;
/* 图形配置参数__图形操作 */
typedef enum
{
UI_Graph_ADD = 1,
UI_Graph_Change = 2,
UI_Graph_Del = 3,
} UI_Graph_Operate_e;
/* 图形配置参数__图形类型 */
typedef enum
{
UI_Graph_Line = 0, // 直线
UI_Graph_Rectangle = 1, // 矩形
UI_Graph_Circle = 2, // 整圆
UI_Graph_Ellipse = 3, // 椭圆
UI_Graph_Arc = 4, // 圆弧
UI_Graph_Float = 5, // 浮点型
UI_Graph_Int = 6, // 整形
UI_Graph_Char = 7, // 字符型
} UI_Graph_Type_e;
/* 图形配置参数__图形颜色 */
typedef enum
{
UI_Color_Main = 0, // 红蓝主色
UI_Color_Yellow = 1,
UI_Color_Green = 2,
UI_Color_Orange = 3,
UI_Color_Purplish_red = 4, // 紫红色
UI_Color_Pink = 5,
UI_Color_Cyan = 6, // 青色
UI_Color_Black = 7,
UI_Color_White = 8,
} UI_Graph_Color_e;
#pragma pack()
#endif

View File

@@ -1,18 +1,56 @@
#include "referee.h"
/**
* @file rm_referee.C
* @author kidneygood (you@domain.com)
* @brief
* @version 0.1
* @date 2022-11-18
*
* @copyright Copyright (c) 2022
*
*/
#include "rm_referee.h"
#include "string.h"
#include "crc_ref.h"
#include "bsp_usart.h"
#include "dma.h"
// 参考深圳大学 Infantry_X-master
#define RE_RX_BUFFER_SIZE 200
static USARTInstance *referee_usart_instance;
static USARTInstance *referee_usart_instance; // 暂时改为非静态变量
/**************裁判系统数据******************/
static referee_info_t referee_info;
static uint8_t Judge_Self_ID; // 当前机器人的ID
static uint16_t Judge_SelfClient_ID; // 发送者机器人对应的客户端ID
static void JudgeReadData(uint8_t *ReadFromUsart);
static void RefereeRxCallback();
uint8_t UI_Seq = 0; // 包序号供整个referee文件使用
/* 裁判系统通信初始化 */
referee_info_t *RefereeInit(UART_HandleTypeDef *referee_usart_handle)
{
USART_Init_Config_s conf;
conf.module_callback = RefereeRxCallback;
conf.usart_handle = referee_usart_handle;
conf.recv_buff_size = RE_RX_BUFFER_SIZE;
referee_usart_instance = USARTRegister(&conf);
return &referee_info;
}
/**
* @brief
* @param send
*/
void RefereeSend(uint8_t *send, uint16_t tx_len)
{
USARTSend(referee_usart_instance, send, tx_len,USART_TRANSFER_IT);
/* syhtodo DMA请求过快会导致数据发送丢失考虑数据尽可能打成一个整包以及队列发送并且发送函数添加缓冲区 */
HAL_Delay(5);
}
/*裁判系统串口接收回调函数,解析数据 */
static void RefereeRxCallback()
{
JudgeReadData(referee_usart_instance->recv_buff);
}
/**
* @brief ,
@@ -22,17 +60,15 @@ static uint16_t Judge_SelfClient_ID; // 发送者机器人对应的客户端ID
*/
static void JudgeReadData(uint8_t *ReadFromUsart)
{
uint16_t judge_length; // 统计一帧数据长度
// referee_info.CmdID = 0; //数据命令码解析
// 空数据包,则不作任何处理
if (ReadFromUsart == NULL)
uint16_t judge_length; // 统计一帧数据长度
if (ReadFromUsart == NULL) // 空数据包,则不作任何处理
return;
// 写入帧头数据(5-byte),用于判断是否开始存储裁判数据
memcpy(&referee_info.FrameHeader, ReadFromUsart, LEN_HEADER);
// 判断帧头数据(0)是否为0xA5
if (ReadFromUsart[SOF] == JUDGE_FRAME_HEADER)
if (ReadFromUsart[SOF] == REFEREE_SOF)
{
// 帧头CRC8校验
if (Verify_CRC8_Check_Sum(ReadFromUsart, LEN_HEADER) == TRUE)
@@ -49,51 +85,43 @@ static void JudgeReadData(uint8_t *ReadFromUsart)
switch (referee_info.CmdID)
{
case ID_game_state: // 0x0001
memcpy(&referee_info.GameState, (ReadFromUsart + DATA), LEN_game_state);
memcpy(&referee_info.GameState, (ReadFromUsart + DATA_Offset), LEN_game_state);
break;
case ID_game_result: // 0x0002
memcpy(&referee_info.GameResult, (ReadFromUsart + DATA), LEN_game_result);
memcpy(&referee_info.GameResult, (ReadFromUsart + DATA_Offset), LEN_game_result);
break;
case ID_game_robot_survivors: // 0x0003
memcpy(&referee_info.GameRobotHP, (ReadFromUsart + DATA), LEN_game_robot_HP);
memcpy(&referee_info.GameRobotHP, (ReadFromUsart + DATA_Offset), LEN_game_robot_HP);
break;
case ID_event_data: // 0x0101
memcpy(&referee_info.EventData, (ReadFromUsart + DATA), LEN_event_data);
memcpy(&referee_info.EventData, (ReadFromUsart + DATA_Offset), LEN_event_data);
break;
case ID_supply_projectile_action: // 0x0102
memcpy(&referee_info.SupplyProjectileAction, (ReadFromUsart + DATA), LEN_supply_projectile_action);
memcpy(&referee_info.SupplyProjectileAction, (ReadFromUsart + DATA_Offset), LEN_supply_projectile_action);
break;
case ID_game_robot_state: // 0x0201
memcpy(&referee_info.GameRobotStat, (ReadFromUsart + DATA), LEN_game_robot_state);
memcpy(&referee_info.GameRobotState, (ReadFromUsart + DATA_Offset), LEN_game_robot_state);
break;
case ID_power_heat_data: // 0x0202
memcpy(&referee_info.PowerHeatData, (ReadFromUsart + DATA), LEN_power_heat_data);
memcpy(&referee_info.PowerHeatData, (ReadFromUsart + DATA_Offset), LEN_power_heat_data);
break;
case ID_game_robot_pos: // 0x0203
memcpy(&referee_info.GameRobotPos, (ReadFromUsart + DATA), LEN_game_robot_pos);
memcpy(&referee_info.GameRobotPos, (ReadFromUsart + DATA_Offset), LEN_game_robot_pos);
break;
case ID_buff_musk: // 0x0204
memcpy(&referee_info.BuffMusk, (ReadFromUsart + DATA), LEN_buff_musk);
memcpy(&referee_info.BuffMusk, (ReadFromUsart + DATA_Offset), LEN_buff_musk);
break;
case ID_aerial_robot_energy: // 0x0205
memcpy(&referee_info.AerialRobotEnergy, (ReadFromUsart + DATA), LEN_aerial_robot_energy);
memcpy(&referee_info.AerialRobotEnergy, (ReadFromUsart + DATA_Offset), LEN_aerial_robot_energy);
break;
case ID_robot_hurt: // 0x0206
memcpy(&referee_info.RobotHurt, (ReadFromUsart + DATA), LEN_robot_hurt);
memcpy(&referee_info.RobotHurt, (ReadFromUsart + DATA_Offset), LEN_robot_hurt);
break;
case ID_shoot_data: // 0x0207
memcpy(&referee_info.ShootData, (ReadFromUsart + DATA), LEN_shoot_data);
// JUDGE_ShootNumCount();//发弹量统计
memcpy(&referee_info.ShootData, (ReadFromUsart + DATA_Offset), LEN_shoot_data);
break;
case ID_student_interactive: // 0x0301 syhtodo接收代码未测试
memcpy(&referee_info.ReceiveData, (ReadFromUsart + DATA_Offset), LEN_receive_data);
break;
}
}
@@ -106,22 +134,3 @@ static void JudgeReadData(uint8_t *ReadFromUsart)
}
}
}
/**
* @brief ,
*
*/
static void RefereeRxCallback()
{
JudgeReadData(referee_usart_instance->recv_buff);
}
referee_info_t *RefereeInit(UART_HandleTypeDef *referee_usart_handle)
{
USART_Init_Config_s conf;
conf.module_callback = RefereeRxCallback;
conf.usart_handle = referee_usart_handle;
conf.recv_buff_size = RE_RX_BUFFER_SIZE;
referee_usart_instance = USARTRegister(&conf);
return &referee_info;
}

View File

@@ -0,0 +1,60 @@
#ifndef RM_REFEREE_H
#define RM_REFEREE_H
#include "usart.h"
#include "referee_def.h"
#include "bsp_usart.h"
extern uint8_t UI_Seq;
#pragma pack(1)
typedef struct
{
uint8_t Robot_Color; //机器人颜色
uint16_t Robot_ID; //本机器人ID
uint16_t Cilent_ID; //本机器人对应的客户端ID
uint16_t Receiver_Robot_ID; //机器人车间通信时接收者的ID必须和本机器人同颜色
} referee_id_t;
// 此结构体包含裁判系统接收数据以及UI绘制与机器人车间通信的相关信息
typedef struct
{
referee_id_t referee_id;
xFrameHeader FrameHeader; // 接收到的帧头信息
uint16_t CmdID;
ext_game_state_t GameState; // 0x0001
ext_game_result_t GameResult; // 0x0002
ext_game_robot_HP_t GameRobotHP; // 0x0003
ext_event_data_t EventData; // 0x0101
ext_supply_projectile_action_t SupplyProjectileAction; // 0x0102
ext_game_robot_state_t GameRobotState; // 0x0201
ext_power_heat_data_t PowerHeatData; // 0x0202
ext_game_robot_pos_t GameRobotPos; // 0x0203
ext_buff_musk_t BuffMusk; // 0x0204
aerial_robot_energy_t AerialRobotEnergy; // 0x0205
ext_robot_hurt_t RobotHurt; // 0x0206
ext_shoot_data_t ShootData; // 0x0207
//自定义交互数据的接收
Communicate_ReceiveData_t ReceiveData;
} referee_info_t;
#pragma pack()
/**
* @brief 初始化裁判系统,返回接收数据指针
*
* @param referee_usart_handle
* @return referee_info_t*
*/
referee_info_t *RefereeInit(UART_HandleTypeDef *referee_usart_handle);
/**
* @brief 发送函数
* @todo
* @param send 待发送数据
*/
void RefereeSend(uint8_t *send, uint16_t tx_len);
#endif // !REFEREE_H