圆梦杯V2记录
参考文章
注:因为原理图跟V1还是差不多的,所以此处就不详细记录基本的东西了,只记一下F1跟F4之间的移植遇到的问题等等,工程文件会上传到Github
框图
焊接
一开始焊完DCDC那上电后电解电容和DCDC芯片严重发热,后面我换了板子一个个元器件焊,最后焊完也是正常的,输出4.95V,可能是因为加热台不知道哪里虚焊或者短路了吧
焊完下载程序半天没效果,原因是拨码开关焊反了,导致地变高电平,正常是1,2丝印朝下,NO在上的,解决方法是把拨码开关全部打上面去,或者拆下来重新焊正
DAPLINK那个下载座不能直接插那个下载器,暂时找不到原因,只能杜邦线接(原因是RST引脚也接了,不要接RST就行)
ASR正常,但是一开始不知道为啥不行8002A一直发烫严重,最后尝试换一块板子焊,然后就正常可以使用了,可能还是哪里虚焊或者啥的吧,但是我都看了也没看到哪里,然后ASR的PA4引脚需要高电平使能才能下载程序,一开始不知道悬空了,所以硬件上只能通过飞线到3.3V了,所以这个教训告诉我要认真看数据手册,不要粗心大意略过
轮子的话一开始我是万向轮在前,两路电机在后的,但是后面调转向环在跑图时发现速度快点或者万向轮卡在地砖的缝的话会导致翻车因为阻力关系后轮速度一直匀速运动所以很危险,后面我尝试了改成前驱,万向轮放后面,电机带动它效果很好,速度上来了或者后轮卡缝里也丝毫不影响正常寻迹
资源分配
- 引脚分配
| 引脚 | 引脚功能 | 用作 |
|---|---|---|
| A7 | TIM3_CH2 | E_R_B |
| A6 | TIM3_CH1 | E_R_A |
| A5 | TIM2_CH1 | E_L_A |
| B3 | TIM2_CH2 | E_L_B |
| A4 | ADC1_IN4 | Power_ADC |
| B1 | ADC1_IN9 | Fire_ADC |
| B0 | ADC1_IN8 | MQ2_ADC |
| E2 | 上拉输入 | L3 |
| E3 | 上拉输入 | L2 |
| E4 | 上拉输入 | L1 |
| E5 | 上拉输入 | M |
| E6 | 上拉输入 | R1 |
| C13 | 上拉输入 | R2 |
| C14 | 上拉输入 | R3 |
| C15 | 推挽输出 | Buzzer |
| D0 | 推挽输出 | L_AIN1 |
| D1 | 推挽输出 | L_AIN2 |
| A1 | TIM5_CH2 | L_PWMA |
| A2 | TIM5_CH3 | R_PWMB |
| D2 | 推挽输出 | R_BIN1 |
| D3 | 推挽输出 | R_BIN2 |
| D4 | 开漏输出 | MPU6050_SCL |
| D7 | 开漏输出 | MPU6050_SDA |
| C5 | 开漏输出 | ESP01S_RST |
| D5 | USART2_TX | BT_ESP01_TX |
| D6 | USART2_RX | BT_ESP01_RX |
| C6 | USART6_TX | ASR_TX |
| C7 | USART6_RX | ASR_RX |
| B10 | USART3_TX | openMV_TX |
| B11 | USART3_RX | openMV_RX |
| B8 | 开漏输出 | SHT30_SCL |
| B9 | 开漏输出 | SHT30_SDA |
| B12 | 开漏输出 | VL53_SCL |
| B13 | 开漏输出 | VL53_SDA |
| E0 | 上拉输入 | K1 |
| E1 | 上拉输入 | K2 |
| D12 | TIM4_CH1 | WS2812B |
| B15 | 推挽输出 | LED_1 |
| B14 | 推挽输出 | LED_2 |
| A3 | TIM5_CH4 | C_Motor |
| A0 | 推挽输出 | LED_sys |
| A9 | USART1_TX | HMI_TX |
| A10 | USART1_RX | HMI_RX |
| C0 | 开漏输出 | EEPROM_SCL |
| C1 | 开漏输出 | EEPROM_SDA |
| B6 | 推挽输出 | OLED_SCL |
| B7 | 推挽输出 | OLED_SDA |
- 其他分配
| 名称 | 用途 |
|---|---|
| TIM9 | 串口2WiFI接收中断计数用 |
| TIM8 | 中断里MPU6050,编码器读取10ms |
| TIM12 | 裸机任务调度1ms |
| TIM13 | us延时不需要中断,设置频率最大arr最大值 |
| TIM10 | 按键检测,LED翻转等1ms |
- 中断分组
每一版都用,隔开
| 中断 | 主优先级 | 子优先级 |
|---|---|---|
| DMA1 stream0(WS2812B) | 3 | 0 |
| TIM9(串口2WiFI接收中断计数用) | 2 | 0 |
| TIM2(左电机编码器) | 3 | 0 |
| TIM3(右电机编码器) | 3 | 0 |
| USART1 | 2 | 0 |
| USART2 | 2 | 0 |
| USART3 | 2 | 0 |
| USART6 | 2 | 0 |
| TIM12(裸机任务调度) | 0 | 0 |
| TIM8(MPU6050,编码器读取) | 1 | 0 |
| TIM10(其他外设计数需要) | 1 | 0 |
主要模块
WS2812B
- 数据手册
每一个灯的数据是24位的,高到低是 GRB
- 发0码
0码的周期大概是假设高电平时间是 0.4us,低电平时间是 0.85us ,那周期就是 1.25us ,那发0的话高电平时间的占空比就是
那低电平的占空比就是 68%了,也就是 2/3是低电平,1/3是高电平
- 发1码
跟发0码相反即可,就是高电平时间占空比是 68%,低电平时间占空比是 32%,也就是 2/3是高电平,1/3是低电平
因为我这里ARR设置是150,所以只需要计算 105的 1/3 和 2/3 即可
发送的话是一组一起发送的,就是灯有多少个就发多少
需要设置频率为800KHz
窗口看门狗
计算:设置了
8分频,窗口值是100,重装载值是127,APB1时钟频率是42MHz超时时间是:
中断优先级需要设置为最高,避免喂狗被打断
- MX
ADC
电池的话充满是12.6V,低于9V就要充电了
MPU6050
陀螺仪有零漂,我采集100次计算平均值,后面减去零漂,得出的角速度会比较稳
不使用DMP库的读取数据函数,但是初始化还是需要的,要自检
10ms定时器读取角速度
us延时
MX在上面设置了,时钟分频看你是多少,72MHz就设置为72-1
/*
* @function: Public_Delay_us
* @param: us -> 需要延时的时间(us)
* @retval: None
* @brief: 系统us延时
*/
static void Public_Delay_us(uint16_t us)
{
// Set timer period for desired delay in microseconds
__HAL_TIM_SET_AUTORELOAD(&htim13, us - 1);//定时器响应时间为period*定时器频率
HAL_TIM_Base_Start(&htim13);//start the timer
//通过轮询的方式等待定时器的更新事件
//当定时器溢出并计数器更新时,TIM_FLAG_UPDATE标志会被置位。
while(__HAL_TIM_GET_FLAG(&htim13,TIM_FLAG_UPDATE)==RESET);
__HAL_TIM_CLEAR_FLAG(&htim13,TIM_FLAG_UPDATE);//清楚更新标志位
HAL_TIM_Base_Stop(&htim13);//Stop the timer
}ESP01S
接收阿里云的消息的话需要把云产品流转停止了,因为之前开了跟APP连通
蓝牙
蓝牙模块一开始是HC-05,但是不知道什么原因后面坏了不能通信,所以换成BT04
- 参数
默认调试波特率是9600,AT指令跟HC05也不一样,密码默认1234
进入AT模式不需要按着按键上电,直接插就行了,500ms间隔闪烁表示未连接,常亮表示已连接,按键是断开连接作用
设置波特率的话是用 AT+BAUDx 指令,x的话 (1~7),其中7是115200,3是9600,可能有的模块是(1~8)看手册反正,修改完断电重新插才生效,AT模式下的波特率跟通信的是同一个
电机PID调试
调试时启动的话按键启动两个电机就行了不需要给基础速度,给目标值就会跑
调试速度环
首先是在PID.h里面把速度环宏定义打开,其他3个环关闭
#define USE_Speed_Ring 1硬件参数初始化函数里面把寻迹开关关闭
Motor_Ctrl.Track_Switch_Flag = FALSE;参数上传的话,上传速度实际值即可(屏蔽一个轮子测另一个轮子那样)
MyHC05.BT_Upload_ActualValue((int)Motors[lb].Speed, CURVES_CH1); // 上传实际值--左轮速度
MyHC05.BT_Upload_ActualValue((int)Motors[rb].Speed, CURVES_CH1); // 上传实际值--右轮速度目标值的话是基础速度就行
Motor_Ctrl.base_speed = actual_temp;- Ki超调现象
- 加Kp抑制超调现象
- 最终
- 总结
先给积分,积分出现超调,先高后低,这两个幅度相比差不多4:1就可以调比例,调比例就是尽可能把超调抑制,速度环就是要响应速度快和快速稳定,出现基本成矩形就很好了。速度环给不给微分都不影响,单单使用积分+比例就很好了。速度环是内环,切记一定要稳,不然影响外面的环
转向环
首先是在PID.h里面把转向环宏定义打开,其他3个环关闭
#define USE_Turn_Ring 1硬件参数初始化函数里面把寻迹开关打开,寻迹模式需要设置为左或者右
TrackMode_Flag.track_Mode = LEFT_FIRST;
Motor_Ctrl.Track_Switch_Flag = TRUE;参数上传的话,上传灰度误差实际值即可
MyHC05.BT_Upload_ActualValue((int)Track.Track_Error, CURVES_CH1); // 上传实际值--灰度err目标值也不需要给,默认就是目标值是误差为0
首先测一下寻迹灯顺序对不对跟误差值,正常是有一个阶梯状的,从左到右
注意寻迹灯顺序,还有误差值(寻迹灯读取函数里面是方向 L3-L2-L1-M-R1-R2-R3,误差对应是 3,2,1,0,-1,-2,-3
还有车的结构,转向环PID的 max_out 不要设置得太大,最好差不多就行了可能是因为我车底板是10x10有点挤
- 总结
转向环就给个寻迹地图给他跑,它在地图上跑的又快又稳就ok了,先给一个比较慢的速度,调一下转向环的参数,然后就开始调整基础速度,因为差速跟基础速度在1.2米以下的时候还是成正比的,所以我差速这个地方是乘上基础速度的:
// 1. 转向环PID结构体 2. 灰度实际误差 3. 灰度期望误差(0)
PidTarget.DifferentialSpeed_target = -PID_Ops.PID_Calc(&pid_Turn, Track.Track_Error, 0) * (Motor_Ctrl.base_speed) * 0.04;这个0.04的参数也是试出来的,调好PID后把基础速度加上去,调整这个比例,让它跑的又快又好就行。转向环其实单单用比例也能很好的,我不用积分,用积分的话震荡比较厉害,所以我是先调比例,比例太大时如果速度上来了也会出现抖动现象,给个微分抑制一下抖动
角速度环
首先是在PID.h里面把角速度环宏定义打开,其他3个环关闭
#define USE_Angle_Ring 1硬件参数初始化函数里面把寻迹开关关闭,打开转向环开关
Motor_Ctrl.TurnRing_Switch_Flag = TRUE; // 打开转向环
Motor_Ctrl.Track_Switch_Flag = FALSE; // 关闭寻迹参数上传的话,上传实际角速度
MyHC05.BT_Upload_ActualValue((int)myMPU6050.gyz_RealAngleSpeed, CURVES_CH1); // 上传实际值--角速度目标值是目标角速度
PidTarget.AnaleSpeedRing_target = actual_temp; // 目标角速度然后在中断里面需要屏蔽角度环只需要角速度环:
#if USE_AngleSpeed_Ring
// 1.角速度环PID结构体 2. 期望角速度(即角度环的输出) 3. 实际角速度
Motor_Ctrl.Set_Turn_Speed(Motor_Ctrl.AngleSpeed_PID_Realize(&pid_AnaleSpeed, -PidTarget.AnaleSpeedRing_target, (myMPU6050.gyro_z - bias) * 2000 / 32768));
#else
// 1. 角度环PID结构体 2. 期望角度 3. 实际角度(偏航角)
PidTarget.AnaleSpeedRing_target = Motor_Ctrl.Angle_PID_Realize(&pid_Angle, PidTarget.AnaleRing_target, myMPU6050.gyz_integral);
// 1.角速度环PID结构体 2. 期望角速度(即角度环的输出) 3. 实际角速度
Motor_Ctrl.Set_Turn_Speed(Motor_Ctrl.AngleSpeed_PID_Realize(&pid_AnaleSpeed, -PidTarget.AnaleSpeedRing_target, myMPU6050.gyz_RealAngleSpeed));
#endif首先测一下角速度正不正常,静止时是0,然后分别左转和右转,然后注意正负问题,如果在上位机发送正值但是实际值是负数的话就需要去程序里改,要发送跟实际一样,我改的是这里,把角速度目标值加个负号:
// 1.角速度环PID结构体 2. 期望角速度(即角度环的输出) 3. 实际角速度
Motor_Ctrl.Set_Turn_Speed(Motor_Ctrl.AngleSpeed_PID_Realize(&pid_AnaleSpeed, -PidTarget.AnaleSpeedRing_target, (myMPU6050.gyro_z - bias) * 2000 / 32768));- 总结
跟速度环类似,让他原地转圈圈,首先调的是比例,慢慢加从0.01开始,积分这里我没用(因为我一加积分就轮子一直加速),微分也先不给,调到比例某个值时如果误差变大了就不要再加了开始减小,直到一个稳定的值,然后慢慢加微分,也是从0.01开始,差不多就可以了
角度环
首先是在PID.h里面把角度环宏定义打开,其他3个环关闭
#define USE_AngleSpeed_Ring 1硬件参数初始化函数里面把寻迹开关关闭,打开转向环开关
Motor_Ctrl.TurnRing_Switch_Flag = TRUE;
Motor_Ctrl.Track_Switch_Flag = FALSE;参数上传的话,上传实际偏航角
MyHC05.BT_Upload_ActualValue((int)myMPU6050.gyz_integral, CURVES_CH1); // 上传实际值--偏航角目标值是目标角度
PidTarget.AnaleRing_target = actual_temp; // 目标角度中断里面也用到角速度和角度环
- 总结
角速度环调稳定后就可以调整角度环,角度环也是用比例就差不多了,再加点微分也可以,我是直接用微分的
移植RTOS
见另一篇文章
问题
下载程序的话这样设置
F4的ADC校准函数应该是取消了,故不需要校准
结构体有个问题就是结构体本身里面的函数指针如果参数是自己的类型的话会报警告,解决方法是在typedef struct后面加一个结构体名称然后形参也需要加struct像这样:
cpp// 这个是报警告的 typedef struct { void (*Set)(AA *a); }AA; // 这个是没有警告的 typedef struct AA { void (*set)(struct AA *a); }AA;
因为画原理图分配引脚时忘记考虑定时器的ARR最大范围问题,所以左轮的编码器定时器最大值是0xFFFFFFFF,在程序里的话还是使用-65536,试了换成-0xFFFFFFFF,但是效果好像差点,MX的话还是设置最大值
注意数据类型,尤其是在循环里,比如for循环里的i如果是递减的话最好把i定义为int8_t不要定义成uint8_t,否则会导致程序莫名其妙的Bug













