2023年电赛总结
转眼间2023年电赛也过去了2个月了,有收获也有遗憾,所以无论如何都要写一篇文章记录一下,这也是电赛做的第一个完整的代码,硬件和软件我都有参与,虽然4天三夜很累但也学到了很多东西,至少学会了坚持对吧,继续在嵌入式这条路走下去,迟早会成功!
前言
本文会详细介绍我在电赛用到的硬件选取和软件代码,虽然不是最好的,但是也能完成基础1-4和发挥1和2的内容,目前基础1-4采用的是开环的思想,发挥1采用了闭环控制,借鉴了板球的代码。
一、硬件的选取
二维云台*2,要这种圆形的会稳一点,Y轴180°,X轴270°,也可以加一个金属大底板,用来搭载平台
激光头*2,可以直接接电源的,光线越亮越好
Openmv*2 ,用来做识别图纸坐标还有识别光点(降低环境影响,防止摄像头鱼眼)
然后就是我们比赛用的主控板,使用STM32F103C8T6然后按键加OLED屏幕(PCB程序找我拿哦)
二、主控代码部分
1.舵机原理(PWM控制)
PWM是脉冲宽度调制(Pulse Width Modulation)的缩写,它是一种常用的电子信号调制技术。PWM通过调节数字信号的占空比来控制模拟设备的输出功率或平均电压。
在使用STM32微控制器生成PWM信号时,您可以按照以下步骤进行设置:
-
配置定时器:选择一个适合的定时器,并设置其时钟源和预分频因子。您可以使用STM32提供的库函数或寄存器直接编程进行设置。
-
配置定时器模式:选择合适的计数模式和自动重载模式。
-
配置通道:选择要使用的PWM输出通道,并设置相关的工作模式。
-
设置计数值和占空比:根据所需的PWM频率和占空比,设置定时器的自动重载寄存器值和通道的比较值。
-
启动定时器:启动定时器开始生成PWM信号。
通过以上步骤,您可以在STM32微控制器上成功生成PWM信号,并通过调整占空比来控制外部设备(如电机、LED、舵机等)的输出功率或亮度。本次只需要开启两个pwm分别控制x舵机和y舵机。
控制原理
通过舵机的信号信号线发送PWM信号来控制舵机的输出量,我们直接控制pwm的占空比,也就是CCR来控制转动的位置。
PWM信号由高电平(ON)和低电平(OFF)组成,其中脉冲宽度指高电平的持续时间。脉冲宽度决定了PWM信号的占空比,即高电平的持续时间与一个完整周期的时间比值。脉冲宽度通常以毫秒为单位进行表示。
在标准的舵机控制中,通常将脉冲宽度的范围设置为1ms到2ms。脉冲宽度为1ms时,表示舵机所需的位置是最小角度(通常为0度),脉冲宽度为2ms时,表示舵机所需的位置是最大角度(通常为180度)。中间的脉冲宽度则表示舵机的中间位置或者其他相应的角度。
比如要产生频率为1KHZ,占空比为50%,分辨率为1%,周期为100us的PWM波形
代入公式 :
频率:72M/(PSC+1)/(ARR+1)=1000
占空比:CCR/(ARR+1)=50%
分辨率:1/(ARR+1)=1%
计算出 ARR=100 PSC=720 CCR=50
我们的舵机可控角度为180°,脉宽范围为500~2500us,精度为3us
需要设置T为20ms
CCR的值与旋转角度关系为 旋转角度/180*2000+500=CCR。
PWM.C代码
#include "stm32f10x.h" // Device header
void PWM_Init(void)
{
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1 | GPIO_Pin_0; //A1左右;A0上下
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
TIM_InternalClockConfig(TIM2);
TIM_TimeBaseInitTypeDef TIM_TimerBaseInitStructure;
TIM_TimerBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimerBaseInitStructure.TIM_CounterMode = TIM_CKD_DIV1;
TIM_TimerBaseInitStructure.TIM_Period = 20000 - 1;//ARR-------
TIM_TimerBaseInitStructure.TIM_Prescaler = 72 - 1;//PSC--------
TIM_TimerBaseInitStructure.TIM_RepetitionCounter = 0;
TIM_TimeBaseInit(TIM2, &TIM_TimerBaseInitStructure);
TIM_OCInitTypeDef TIM_OCInitStructure;
TIM_OCStructInit(&TIM_OCInitStructure);
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
TIM_OCInitStructure.TIM_Pulse = 0;//CCR---------------------------
TIM_OC1Init(TIM2, &TIM_OCInitStructure);//通道1
TIM_OC2Init(TIM2, &TIM_OCInitStructure);//通道2,两个通道分别输出两个PWM
TIM_Cmd(TIM2, ENABLE);
}
void PWM_SetCompare1(unsigned int Compare)
{
TIM_SetCompare1(TIM2, Compare);
}
void PWM_SetCompare2(unsigned int Compare)
{
TIM_SetCompare2(TIM2, Compare);
}
main.c
void mode1(void);
void mode2(void);
void mode3(void);
void mode4(void);
void Key_Init(void);
unsigned int KeyNum;
float Ang1,Ang2,AngFlag;
float Angle1,Angle2;
int main(void)
{
// OLED_Init();
Key_Init();
Serial_Init();
Servo_Init();
Delay_s(1);
Key_Init(); // 初始化按键
while (1) {
if (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_1) == Bit_RESET) { // PB1
mode3(); // 1
} else if (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_0) == Bit_RESET) { // PB0
mode2(); // 2
} else if (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_9) == Bit_RESET) { // PB9
mode1(); // 3
} else if (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_8) == Bit_RESET) { // PB8
mode4(); // 4
}
}
}
其他主控代码可以私聊我,回去麻烦点个赞下一期更新摄像头代码。
目前有三种方案
总结
今天主要介绍了舵机的控制,这也是这次比赛关键的部分,必须熟悉舵机的原理和控制理论才能配置好舵机,然后就是不断的调参数,我们电赛的机械结构是固定的所以就采用的开环控制,其实效果也很好,熟练的运用PWM和舵机的特性是解决前4问的关键。然后是第一次写文章还有很多不足,后续继续加强,可以再去看看PWM控制和菜单切换的文章,由于时间有限我们这次就只写了按键控制4个模式,没有写oled的代码。