哨兵
与视觉通信
在Visual_Com_Init这个函数里
之前版本Aimbot_UART_Init里面传了两个函数参数,现在改成了统一的VisualCom_Receive_Flag,里面内容和之前说的通信协议基本相同
rt_err_t VisualCom_Receive_Flag(rt_uint8_t rxmsg[])
{
int fori;
char sum;
char FlagsTemp;
union Float_Char Temp;
// 校验和检查
sum = 0;
for (fori = 0; fori < 28; fori++)
sum += rxmsg[fori];
if (sum != rxmsg[fori])
{
error_time ++;
// 和校验未通过
return RT_ERROR;
}
// 数据保存
VisualMode_FB = rxmsg[1]; // 视觉当前自瞄模式
Temp.c[0] = rxmsg[2];Temp.c[1] = rxmsg[3];Temp.c[2] = rxmsg[4];Temp.c[3] = rxmsg[5];
GimbalTolerance_Pitch = Temp.f; // 云台Pitch轴当前允许控制误差 (和视觉的通信规则存疑)
Temp.c[0] = rxmsg[6];Temp.c[1] = rxmsg[7];Temp.c[2] = rxmsg[8];Temp.c[3] = rxmsg[9];
GimbalTolerance_Yaw = Temp.f; // 云台Yaw轴当前允许控制误差 (和视觉的通信规则存疑)
FlagsTemp = rxmsg[0];
VisualFlag_TargetFound = utils_read_bit(FlagsTemp, 0); // 视觉是否搜索到目标
VisualFlag_Fire = utils_read_bit(FlagsTemp, 1); // 视觉是否允许开火
VisualFlag_BurstShoot = utils_read_bit(FlagsTemp, 2); // 视觉是否允许进行爆发开火
VisualFlag_PatrolBit3 = utils_read_bit(FlagsTemp, 3); // 标志位3不使用
VisualFlag_PatrolBit4 = utils_read_bit(FlagsTemp, 4); // 标志位4不使用
VisualFlag_PatrolBit5 = utils_read_bit(FlagsTemp, 5); // 标志位5不使用
VisualFlag_WorkingCorrect = utils_read_bit(FlagsTemp, 6); // 视觉当前是否工作正常
if (VisualFlag_TargetFound == 0)
{
// 视觉丢失目标了,此时需要直接将已有设定值数据设定为 失效
GimbalSet_Receive[0].State = RT_ERROR;
GimbalSet_Receive[1].State = RT_ERROR;
}
VisualAttiSet_TickOrigin = (rxmsg[13] << 24)|(rxmsg[12] << 16)|(rxmsg[11] << 8)|(rxmsg[10]);
Temp.c[0] = rxmsg[14];Temp.c[1] = rxmsg[15];Temp.c[2] = rxmsg[16];Temp.c[3] = rxmsg[17];
Fire_Time = Temp.f;
Temp.c[0] = rxmsg[18];Temp.c[1] = rxmsg[19];Temp.c[2] = rxmsg[20];Temp.c[3] = rxmsg[21];
VisualAttiSetOri_Pitch = Temp.f;
Temp.c[0] = rxmsg[22];Temp.c[1] = rxmsg[23];Temp.c[2] = rxmsg[24];Temp.c[3] = rxmsg[25];
VisualAttiSetOri_Yaw = Temp.f;
VisualAttiSetOri_PitchSpe = (rt_int8_t)rxmsg[26];
VisualAttiSetOri_YawSpe = (rt_int8_t)rxmsg[27];
/*数据处理*/
// 先计算Tick的数值
GimbalSet_Receive[!Gimbal_Set_Cal_READ_Valid].PredictedTime = VisualAttiSet_TickOrigin;
GimbalSet_Receive[!Gimbal_Set_Cal_READ_Valid].GimbalSet_Angle.Pitch = VisualAttiSetOri_Pitch + PitchFix;
GimbalSet_Receive[!Gimbal_Set_Cal_READ_Valid].GimbalSet_Angle.Yaw = VisualAttiSetOri_Yaw + YawFix;
GimbalSet_Receive[!Gimbal_Set_Cal_READ_Valid].GimbalSet_Speed.Pitch = VisualAttiSetOri_PitchSpe;
GimbalSet_Receive[!Gimbal_Set_Cal_READ_Valid].GimbalSet_Speed.Yaw = VisualAttiSetOri_YawSpe;
if (Visual_Mode_Set == VisualMode_FB || Patrol_Mode_Set == PATROL_MODE_SELF_ARMOR_PALTE)
{
// 当前视觉工作模式正确
GimbalSet_Receive[!Gimbal_Set_Cal_READ_Valid].State = RT_EOK;
Gimbal_Set_Cal_READ_Valid = !Gimbal_Set_Cal_READ_Valid; // 切换可读取
}
else
{
// 视觉工作模式错误 则所有数据均标记为失效
GimbalSet_Receive[!Gimbal_Set_Cal_READ_Valid].State = RT_ERROR;
GimbalSet_Receive[Gimbal_Set_Cal_READ_Valid].State = RT_ERROR;
}
#ifdef AIMBOT_COM_COLLECT_PACKET_LOSS_RATE
++Package_SumCheck_Passed_Num;
#endif /* AIMBOT_COM_COLLECT_PACKET_LOSS_RATE */
return RT_EOK;
}
不同的是哨兵没有能量机关模式,所以不使用相关的位
然后是给视觉发送的线程Visual_Send_Thread
首先修改波特率,现在是460800
然后是一些串口相关配置
#define AIMBOT_RX_READ_SIZE RT_SERIAL_RB_BUFSZ // 接收缓冲区大小
#define AIMBOT_RX_READ_TIME_DIFF 30
#define AIMBOT_TX_BUFFER_SIZE 64 // 发送缓冲区大小(双段缓冲)
#define AIMBOT_RX_REAL_DATA_SIZEMAX 64 // 收到一帧数据的最大大小
uint8_t Framehead[4] = {0x00,0x00,0x80,0x7f};
注意这里面用的串口发送需要增加帧头,以后如果修改的话要注意一下
rt_size_t Aimbot_Write_UART_Data(rt_device_t *dev, rt_uint8_t ID, rt_uint8_t msg[], rt_size_t size)
{
// 用于记录当前写到缓存区的哪个位置了, 这里默认从 2 开始是因为前两字节是串口通信协议固定的内容
rt_uint8_t write_pos = 5;
// 用于指定当前该写入哪一段缓冲数据, 如果当前数据还没发送完就使用另一段缓冲区
if (!Aimbot_UART_Msg.tx_complete_flag)
Aimbot_UART_Msg.tx_data_to_write = 1 - Aimbot_UART_Msg.tx_data_to_write;
rt_uint8_t *write_msg = Aimbot_UART_Msg.tx_msg[Aimbot_UART_Msg.tx_data_to_write];
// 写入帧头
write_msg[0] = 0x00;
write_msg[1] = 0x00;
write_msg[2] = 0x80;
write_msg[3] = 0x7f;
// 遍历发送缓存区写入待发送数据
for (int i = 0; i < size; ++i)
{
write_msg[write_pos++] = msg[i];
}
// 写入数据实际长度(不包括前两字节)与数据类型
if (1 == ID)
write_msg[4] = ((write_pos - 5) & 0x7F) | (ID << 7);
else
write_msg[4] = ((write_pos - 5) & 0x7F) | (ID << 7);//????
// 发送数据
Aimbot_UART_Msg.tx_complete_flag = 0;
if (!dev)
return 0;
else
return rt_device_write(*dev, 0, write_msg, (write_msg[4] & 0x7F) + 5);
}
哨兵扫描模式
扫描模式相关的在云台控制的Gimbal_getset函数中
要求在客户端模式,最左侧拨杆在上方,比赛开始时会进入。
只有当扫描模式,且较长时间没有识别到装甲板才会进行扫描模式的云台控制刷新
相关代码
if (ComputerCTRL_EN == 1 && RC_data.Remote_Data.s0 == 1)
//if (ComputerCTRL_EN == 1 || chassisMsg.isStartGame == 1 || RC_data.Remote_Data.s0 == 1) // 处于客户端模式,比赛开始,哨兵模式
{
NowAim_Tick = rt_tick_get();
Search_Coverage();
if(VisualFlag_TargetFound == 1)
{
LastAim_Tick = rt_tick_get();
}
if (Patrol_Mode_Set == PATROL_MODE_TARGET_FINDING && VisualFlag_TargetFound == 0 && NowAim_Tick - LastAim_Tick > AIMDELTA_TICK)
Refresh_ConstSet_Gimbal(&RoboControl_GimbalSetAng.Pitch, &RoboControl_GimbalSetAng.Yaw, yaw_start, yaw_end);
}
扫描模式的设定值增加了注释
void Refresh_ConstSet_Gimbal(float *pitch_Set, float *yaw_set, float StartYaw, float EndYaw)
{
// if (StartYaw != Last_StartYaw || EndYaw != Last_EndYaw)
// Find_Start = 0;
// Last_StartYaw = StartYaw;
// Last_EndYaw = EndYaw;
// if (Yaw_Move != StartYaw && Find_Start == 0)
// {
// Yaw_Move = (StartYaw + EndYaw) / 2;
// Find_Start = 1;
// }
FindThis_Tick = rt_tick_get();
/*if(FindThis_Tick - FindLast_Tick > 1000)
{
Yaw_Move = 0;
Pitch_Move = 0;
}*/
FindLast_Tick = FindThis_Tick;
if (EndYaw > StartYaw)
EndYaw -= 360.f;
if (dir_change_num >= 10)// 摆动次数多,扩大摆动范围
{
if (dir_change_num <= 15)
StartYaw = EndYaw;
if (Yaw_Move >= 720)
{
dir_change_num = 0;
Yaw_Move -= 720;
}
}
/*
if (Yaw_Move >= 720)
{
dir_change_num = 0;
Yaw_Move -= 720;
}
if (Yaw_Move <= -720)
{
dir_change_num = 0;
Yaw_Move += 720;
}
*/
if (Yaw_Move <= EndYaw)//转动角度小于end,朝着start转动
dire_flag = 0;
else if (Yaw_Move >= StartYaw)//转动角度大于start,朝着end转动
dire_flag = 1;
if (last_dir != dire_flag)// 记录改变方向的次数
dir_change_num++;
last_dir = dire_flag;
if (StartYaw == EndYaw)
{
StartYaw += 360.f;
dire_flag = 0;
}
if (dire_flag == 0)// 朝着start转动
{
Yaw_Move += TURNSPEED_SET;
Pitch_Move = ((PITCH_MIN_ANGLE + PITCH_MAX_ANGLE) / 2) + ((PITCH_MAX_ANGLE - PITCH_MIN_ANGLE) / 3) * sinf(Yaw_Move * 3.1415926535f / 30);
}
else if (dire_flag == 1)// 朝着end转动
{
Yaw_Move -= TURNSPEED_SET;
Pitch_Move = ((PITCH_MIN_ANGLE + PITCH_MAX_ANGLE) / 2) + ((PITCH_MAX_ANGLE - PITCH_MIN_ANGLE) / 3) * sinf(Yaw_Move * 3.1415926535f / 30);
}
*pitch_Set = Pitch_Move / 2;
if (VisualMode_FB == VISUAL_MODE_AIMBUFF_ROTATING_OUTPOST)
{
*pitch_Set = 20;
dir_change_num = 0;
}
*yaw_set = Yaw_Move;
}
之前出现过两个bug,一个是哨兵识别到装甲板会自动移开,另一个是自瞄锁到之后无法回到扫描模式
第一个是因为在robocontrol里面有一个保护措施,原本是过多少秒之后才能开始索敌,但是不清楚有什么用,因为视觉是能识别敌我的
void SentryCtrl_entry(void)
{
Visual_Mode_Set = VisualMode_FB;
ui_sentry_mode = 1;
// 进入哨兵模式默认自瞄模式并记录时间
if (Game_Start_time == 0)
{
Visual_Mode_Set = VISUAL_MODE_AIMBOT_V2;
Patrol_Mode_Set = PATROL_MODE_TARGET_FINDING;
Game_Start_time = rt_tick_get();
}
// 进入哨兵模式WAIT_TICK秒后才允许锁敌,防止误识别浪费弹丸
// 后根据云台手按键决定是否发弹
if (rt_tick_get() - Game_Start_time < WAIT_TICK)
{
VisualFlag_TargetFound = 0;
}
为了安全起见把他改小了
另一个是云台控制里面,哨兵没有找到退出自瞄的标志位赋值,可能是按照之前的逻辑不需要,这里给他加上了根据targetfound更新

还有一个问题是正常情况下哨兵模式自瞄锁到以后会自动发弹,但是如果不预先开启摩擦轮一遍的话就不会发弹,暂时没找到是哪里的bug,于是增加了上电自动开启摩擦轮。

浙公网安备 33010602011771号