stm32蓝牙遥控循迹避障多功能车

发布时间:2026/10/29 1:53:16
stm32蓝牙遥控循迹避障多功能车

一个基于3功能小车 通过按钮选择模式

uint8_t key=Key_GetNum();
if (key==1)mode=1;(蓝牙)
if (key==2)mode=2;(循迹)
if (key==3)mode=3;(避障)

关于蓝牙模式 是根据上一篇的蓝牙控制小车修改,详细可看上一篇

​ if (Serial_RxFlag == 1) { lost_cnt = 0; OLED_ShowString(4, 1," "); OLED_ShowString(4, 1,Serial_RxPacket); char *Tag = strtok(Serial_RxPacket,","); if (Tag != NULL && strcmp(Tag,"joystick")==0) { char *pLH = strtok(NULL, ","); char *pLV = strtok(NULL, ","); if (pLH != NULL && pLV != NULL) { int LH = atoi(pLH); int LV = atoi(pLV); if (abs(LV)>=abs(LH)&&abs(LV)>20) { int spd=abs(LV); if (LV>0) Motor_SetSpeed(spd,spd); else Motor_SetSpeed(-spd,-spd); } else if (abs(LH)>20) { int spd = abs(LH); if (LH>0) Motor_SetSpeed(spd,-spd); else Motor_SetSpeed(-spd,spd); } else { Motor_SetSpeed(0, 0); } } } Serial_RxFlag = 0; ​

循迹模式 使用8路灰度传感器 检测到黑线返回数据

uint16_t CounSensor_Get(void) { uint16_t state=0; if(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_12)==1) state|= 0x80;//10000000 if(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_13)==1) state|= 0x40;//01000000 if(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_14)==1) state|=0x20;//00100000 if(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_15)==1) state|=0x10;//00010000 if(GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_8)==1) state|=0x08;//00001000 if(GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_11)==1) state|=0x04;//00000100 if(GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_12)==1) state|=0x02;//00000010 if(GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_15)==1) state|=0x01;//00000001 return state; }

用穷举把每种情况标明(1为检测到黑线0为白色)并转为十六进制,方便接下来使用switch函数判断情况

switch (state) { case 0x00: turn = PID_Compute(&PID_Dirct, 0.0); break; case 0x18: turn = PID_Compute(&PID_Dirct, 0.0); break; case 0x30: turn = PID_Compute(&PID_Dirct, -2.0); break; case 0x60: turn = PID_Compute(&PID_Dirct, -3.0); break; case 0xC0: turn = PID_Compute(&PID_Dirct, -6.0); break; case 0xE0: turn = PID_Compute(&PID_Dirct, -6.0); break; case 0x70: turn = PID_Compute(&PID_Dirct, -2.0); break; case 0x0C: turn = PID_Compute(&PID_Dirct, 2.0); break; case 0x06: turn = PID_Compute(&PID_Dirct, 3.0); break; case 0x03: turn = PID_Compute(&PID_Dirct, 6.0); break; case 0x07: turn = PID_Compute(&PID_Dirct, 6.0); break; case 0x0E: turn = PID_Compute(&PID_Dirct, 2.0); break; default: turn = 0.0; break; } int left_pwm = base_speed - (int)turn; int right_pwm = base_speed + (int)turn; Motor_SetSpeed(left_pwm, right_pwm);

pid就不用过多简绍 PID_Compute(PID_TypeDef *pid, float actual)通过根据黑线位置修改actual值来跟踪,实际下机测试在根据情况自己修改kp ki kd

避障 是根据超声波模块和舵机云台联动完成

if (distance > 15.0f) { Motor_SetSpeed(50, 50); } else { Motor_SetSpeed(0, 0); Delay_ms(200); Servo_SetAngle(0); Delay_ms(300); float dist_left = UltrasonicGetLength(); Servo_SetAngle(180); Delay_ms(300); float dist_right = UltrasonicGetLength(); Servo_SetAngle(90); Delay_ms(100); if (dist_left > 15.0f) { MPU6050(90.0f, 50); } else if (dist_right > 15.0f) { MPU6050(-90.0f, 50); } else { Motor_SetSpeed(-50, -50); Delay_ms(500); MPU6050(-90.0f, 50); } Motor_SetSpeed(0, 0); Delay_ms(100); } } else { mode = 0; Motor_SetSpeed(0, 0); } Delay_ms(10); } }

这是判断部分 》15直行 当《15时就左右自动超声波,哪里没有障碍就往哪里转向 都有障碍就直接倒

​ void MPU6050(float target_angle, uint8_t speed) { float accumulated = 0.0f; float dt; uint32_t t_last, t_now; if (target_angle > 0) Motor_SetSpeed(-speed, speed); else { Motor_SetSpeed(speed, -speed); target_angle = -target_angle; } t_last = DWT_CYCCNT_REG; while (accumulated < target_angle) { MPU6050_GetData(&AX, &AY, &AZ, &GX, &GY, &GZ); t_now = DWT_CYCCNT_REG; dt = (float)(t_now - t_last) / 72000000.0f; t_last = t_now; float gz_rate = (float)GZ / 16.4f - Z; accumulated += gz_rate * dt; if (accumulated < 0.0f) accumulated = 0.0f; Delay_ms(5); } Motor_SetSpeed(0, 0); } ​

这个函数是设定转向角度速度 根据MPU6050积分当达到设定角度就停 z是解决mpu6050误差漂的