• STM32控制舵机精准角度


    一、舵机原理

    二、程序介绍

    三、精准角度控制原理

    四、程序分享

            网上很多教程,都只是控制舵机0°,45°,90°等特定的角度,比如1°,很多程序都做不到,即使有也少得可怜,更不会详解介绍是怎么实现精准控制每一度的,因此,这篇文章的意义就在这里。


    一、舵机原理       

     我们以SG90、MG90等舵机为例,舵机有三个PIN,分别是VCC,GND,PWM,PWM引脚需要一个20ms周期信号,通过不同的占空比来控制不同角度,具体参数如下:

       0.5ms--------------0度;

       1.0ms------------45度;

       1.5ms------------90度;

       2.0ms-----------135度;

       2.5ms-----------180度;

            动态原理如下,源自网上。

    二、程序介绍

            产生PMW的方法很多,典型的就是用单片机,这里以STM32F1举例

    PWM配置:这个配置没有什么特别,大同小异,直接使用经典的配置就可以,重点在后面的主函数。

    1. void TIM3_PWM_Init(u16 arr,u16 psc)
    2. {
    3. GPIO_InitTypeDef GPIO_InitStructure;
    4. TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
    5. TIM_OCInitTypeDef TIM_OCInitStructure;
    6. RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
    7. RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | RCC_APB2Periph_AFIO, ENABLE);
    8. GPIO_PinRemapConfig(GPIO_PartialRemap_TIM3, ENABLE);
    9. GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;
    10. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
    11. GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    12. GPIO_Init(GPIOB, &GPIO_InitStructure);
    13. TIM_TimeBaseStructure.TIM_Period = arr;
    14. TIM_TimeBaseStructure.TIM_Prescaler =psc;
    15. TIM_TimeBaseStructure.TIM_ClockDivision = 0;
    16. TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
    17. TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);
    18. TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2;
    19. TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
    20. TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
    21. TIM_OC2Init(TIM3, &TIM_OCInitStructure);
    22. TIM_OC2PreloadConfig(TIM3, TIM_OCPreload_Enable);
    23. TIM_Cmd(TIM3, ENABLE);
    24. }

    主函数:

    1. void Servo_Control(float angle)
    2. {
    3. float temp;
    4. u16 led0pwmval=0;
    5. // temp = 195- 0.11*(float)angle;
    6. // TIM_SetCompare2(TIM3, (float)temp);
    7. pwmval = (int)(2000*(1-((0.5+angle/90.0)/20.0))) -5;
    8. TIM_SetCompare2(TIM3, pwmval);//
    9. }
    10. int main(void)
    11. {
    12. float i;
    13. Servo_Control(0);
    14. delay_init();
    15. NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
    16. LED_Init();
    17. //TIM3_PWM_Init(199,7199); //(199+1)*(7199+1)/72*10^6 0.02S 20MS
    18. TIM3_PWM_Init(1999,719);
    19. while(1)
    20. {
    21. Servo_Control(0);
    22. /*
    23. for(i=0;i<=179;i++)
    24. {
    25. Servo_Control(i);
    26. delay_ms(2);
    27. }
    28. delay_ms(2);
    29. for(i=180;i>=1;i--)
    30. {
    31. Servo_Control(i);
    32. delay_ms(2);
    33. }
    34. delay_ms(2);
    35. */
    36. }
    37. }

    这里分为两部分:

    1. //TIM3_PWM_Init(199,7199); //(199+1)*(7199+1)/72*10^6 0.02S 20MS
    2. TIM3_PWM_Init(1999,719);

            首先两个定时器都能产生20ms周期的脉冲,但是网上很多网友使用的都是第一种方式:TIM3_PWM_Init(199,7199),这个的弊端是,由于计数的数量太少了,才199,导致在控制舵机角度的时候,即使我最小修改一个单位的数值,表现出来的变化脉冲宽度都比较大,导致舵机旋转了大于一个度数,换句话说,这个代码调节的精度太差。

            因此,我们需要想办法让计数器计数得尽量多,在我们修改前期的数值时,后面的脉宽变化很小很小,小于舵机旋转1°所需的变化脉宽,我们就成功了。

    因此,我们使用:TIM3_PWM_Init(1999,719);

    三、精准角度控制原理

            精准角度控制,主要在下面这两行代码

    1. pwmval = (int)(2000*(1-((0.5+angle/90.0)/20.0))) -5;
    2. TIM_SetCompare2(TIM3, pwmval);

            假设我们需要舵机旋转45°,则占空比为1ms/20ms=5%,则TIM_SetCompare2TIMx 捕获比较 1 寄存器值就是2000-2000*5%=1900;

    那这个数值跟角度有什么关系呢,就来到了这个代码:  

    pwmval = (int)(2000*(1-((0.5+angle/90.0)/20.0))) -5;

            占空比从0.5开始为0°,因此需要以0.5开始相加,我们假设把45°为angle带进去,则最里面的括号为1,正好对标舵机45°时候的1ms。

            那为什么我后面要减5呢,这个是我舵机的误差,因为在我设定为0°的时候,我发现舵机的角度并不是完完全全的水平,因此这个相当于一个校准系数,根据实际情况而定,如果舵机质量很好,没有误差,那不需要-5,就是这个意思。

    我这里还写了一个for循环,供大家参考,作用是使得舵机以1°的步进正反旋转。

    1. for(i=0;i<=179;i++)
    2. {
    3. Servo_Control(i);
    4. delay_ms(2);
    5. }
    6. delay_ms(2);
    7. for(i=180;i>=1;i--)
    8. {
    9. Servo_Control(i);
    10. delay_ms(2);
    11. }
    12. delay_ms(2);

    四、程序分享

            这里附上下载链接,或者去我的主页

            STM32控制舵机精准角度程序,精确到某一度-嵌入式文档类资源-CSDN下载

    你的点赞或收藏是我创作的动力~~

  • 相关阅读:
    i7 11800h和i7 12800hx选哪个好
    [清华大学]漏洞挖掘之状态敏感的模糊测试StateFuzz
    基于粒子群优化的神经网络PID控制(Matlab)代码实现
    【从0开始编写webserver·基础篇#01】为什么需要线程池?写一个线程池吧
    解决:用mybatis写select语句根据属性查询出主键为null,其他数据正常显示
    Windows安装k8s
    手写ngIf,使用视图容器引用ViewContainerRef和模板引用TemplateRef
    管理类联考——数学——汇总篇——知识点突破——数据分析——1. 计数原理——排列组合——公式
    12333 - Revenge of Fibonacci (UVA)
    华为云云耀云服务器L实例评测 | 实例场景体验之搭建个人博客:通过华为云云耀云服务器构建个人博客
  • 原文地址:https://blog.csdn.net/weixin_42107954/article/details/126655769