小突突的诞生日记
1.需求分析
单纯的想给即将出生的小孩做个遥控小车玩具。
2.材料准备
单纯四驱太简单,就想着做个麦轮带pid控制的小车。
某多多上买了铝合金底盘+电机+麦轮,剩下的硬件和软件就纯靠自己设计。
3.硬件设计
之前从来没有学过pcb知识,但是非常喜欢pcb板拿在手里的那种感觉,也是趁这次制作学习了一下自己画pcb。
涉及到了stm32核心板、小车驱动底板以及rc遥控器。均在嘉立创白嫖pcb打样。具体可以参见stm32f4zet6核心板和遥控器,底板部分后续将会开源。
其实涉及到的硬件知识不复杂,stm32f4核心板原理图网上一大堆,rc遥控器功能也简单,本质是按键信号传输。具体可以参考我的pcb。
4.软件设计
4.0 总体功能
-
编码电机的PID控制
-
4个麦轮整体的运动学控制
-
mpu6050姿态解析
-
TB6612FNG多路电机驱动
-
OLED屏幕显示(u8g2库移植)
-
蓝牙及NRF24L01无线数据传输
-
超声波避障
以上其实都是基本的功能,网上搜搜都能找到一大堆资料,基本的原理和实现就不详解了,这里只做一个记录,遇到的特殊问题文末会总结。
将来还想实现无线图传、手势控制、云台炮塔等功能,等有空了再说吧。。
5.写在最后
5.0 自己的代码链接:
主控程序:https://github.com/CharlesPu/Little_TuTu
rc遥控器:https://github.com/CharlesPu/TuTu_RC
5.1 硬件设计注意点
5.1.1 蜂鸣器使用
pnp和npn三极管的使用恶补了一下知识,两种三极管用反了。。
5.1.2 串口一键下载电路
https://blog.youkuaiyun.com/weixin_70317234/article/details/127224498?spm=1001.2014.3001.5506
https://blog.youkuaiyun.com/weixin_48848862/article/details/136055314?spm=1001.2014.3001.5506
注意要结合boot电路设计,即boot引脚电平要可变。
5.1.3 pcb线宽
简单说就是gnd和vcc尽可能地大。
https://blog.youkuaiyun.com/qq_52940987/article/details/124570167?spm=1001.2014.3001.5506
5.2 软件设计注意点
5.2.1 stm32f1和f4的定时器分频设置
在使用f1和f4时,要注意时钟总线在不同定时器上的区别。可以参考。所以在使用定时器进行精确定时时要注意频率选择。
5.2.2 ADC采集摇杆数据
注意hal配置连续采集时要设置每个采集通道的频率一致。设置字长时要注意halfword的含义(决定了程序中存储采集数据时要使用uint16t类型)
https://blog.youkuaiyun.com/m0_64551204/article/details/135296070?spm=1001.2014.3001.5506
5.2.3 float和char [4]转换
char[4]转float: *(float*)&(buf[0])
float转char[4]:*(float*)&buf[0] = 1.234
上面两个转换函数在stm32上无法运行,可以改成:
char[4]转float:
float res;
uint8 *pp = (uint8*)&res;
pp[0] = buf[0];
pp[1] = buf[1];
pp[2] = buf[2];
pp[3] = buf[3];
return res;
float转char[4]:
buf[0] = *((uint8*)&data); //获取a的首地址
buf[1] = *((uint8*)&data + 1);//获取a的首地址的后一个字节地址
buf[2] = *((uint8*)&data + 2);//获取a的首地址的后两个字节地址
buf[3] = *((uint8*)&data + 3);//获取a的首地址的后三个字节地址
5.2.4 stm32中断开启
本来以为中断初始化了就行了,但是在实际使用时各种中断、pwm等都要手动开启!!
HAL_TIM_Base_Start_IT(&TIM_HC_SR04);
HAL_TIM_PWM_Start(motor_A1.tim_pwm,motor_A1.tim_pwm_channel);
5.2.5 串口中断中不能有其他串口的发送
5.2.6 串口中断中连续发送问题
如果在某个串口中断中使用HAL_UART_Transmit_IT
和HAL_UART_Transmit_DMA
连续发送时会阻塞,改为HAL_UART_Transmit
发送即可。
5.2.7 mpu6050数据初始化经常失败
发现同样的程序在f1上可以正常运行,但是f4上频繁失败,定位到最后是io口配置问题。SDA要配置成上拉输入,避免不确定的io状态。
void MPU_SDA_IN()
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
GPIO_InitStruct.Pin = MPU_I2C_SDA_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = GPIO_PULLUP; // note!!!!!
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
}
void MPU_SDA_OUT()
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
GPIO_InitStruct.Pin = MPU_I2C_SDA_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_OD;
GPIO_InitStruct.Pull = GPIO_PULLUP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
}
5.2.8 rc遥控断连保护
nrf接收端要注意编写断连保护代码,防止遥控器关机没电或者超出遥控距离等情况出现,这种时候要及时监测到,并让小车停止运动。
// 接受成功才会使用遥控数据,否则断连保护,速度都是0
if(NRF24L01_RxPacket(rc.buf)==0)// 成功
{
rc_disconnect_cnt = 0;
motion_control_kinematics(motion_control_rc_to_kinematics(&rc));
}else { // 说明遥控断了
if (rc_disconnect_cnt > 12) // 断了(600ms左右)就停止控制
motion_control_stop();
else
rc_disconnect_cnt++;
}
断连监测时间不能太短,要对遥控接收数据失败有一定容忍次数,否则会出现小车一顿一顿的情况,即对遥控接收数据太敏感,稍微丢掉一些数据车就停止。