哨兵

与视觉通信

在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,于是增加了上电自动开启摩擦轮。

posted @ 2025-04-07 09:40  小蒟蒻皮皮鱼  阅读(48)  评论(0)    收藏  举报