Robot 第三周(16路PWM产生)

一、本周工作:

 

9月 27 日 - 10月 3日 

利用STM32F103RB芯片内部通用定时器24,产生16路周期固定20ms、占空比控制范围(0.5ms~2.5ms)、补进为1us可控的PWM。辉盛舵机MG995(死区设定4微秒、0.13/60(6.0V) ),产生的PWM可以正常控制该舵机。程序见附录。

舵机简介:

1、舵机的原理和控制

控制信号由接收机的通道进入信号调制芯片,获得直流偏置电压。它内部有一个基准电路,产生周期为20ms,宽度为1.5ms的基准信号,将获得的直流偏置电压与电位器的电压比较,获得电压差输出。最后,电压差的正负输出到电机驱动芯片决定电机的正反转。当电机转速一定时,通过级联减速齿轮带动电位器旋转,使得电压差为0,电机停止转动。

舵机的控制一般需要一个20ms左右的时基脉冲,该脉冲的高电平部分一般为0.5ms-2.5ms范围内的角度控制脉冲部分,总间隔为2ms。以180度角度伺服为例,那么对应的控制关系是这样的:

  

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

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

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

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

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




   2舵机的追随特性

  假设现在舵机稳定在A点,这时候CPU发出一个PWM信号,舵机全速由A点转向B点,在这个过程中需要一段时间,舵机才能运动到B点。

保持时间为T

   当Tw≥△T时,舵机能够到达目标,并有剩余时间;

Tw≤△T时,舵机不能到达目标;

理论上:当T=T时,系统最连贯,而且舵机运动的最快。

实际过程中w不尽相同,连贯运动时的极限△T比较难以计算出来。

假如我们的舵机1DIV =8us,当PWM信号以最小变化量即(1DIV=8us)依次变化时,舵机的分辨率最高,但是速度会减慢。



二、本周小结:

看了一些关于如何控制多路舵机的资料,发现基本上使用普通的PWM就可以正常使用,但是需要一定的精度和抗干扰性。抗干扰可以用硬件处理。在可以正常驱动16路舵机的基础上,进行位姿分析。位姿分析如果用软件模拟这个会比较复杂。

三、疑问:出现了一个问题如下图,设置IO口时启用A组和B组是可以正常产生PWM,但是如果启用的是A组和CPWM会出现问题。目前还不知什么情况。

 

四 下周计划:学习机器人多个舵机控制算法,查找软件模拟位姿动作资料。


附录:

   2舵机的追随特性

  假设现在舵机稳定在A点,这时候CPU发出一个PWM信号,舵机全速由A点转向B点,在这个过程中需要一段时间,舵机才能运动到B点。

保持时间为T

   当Tw≥△T时,舵机能够到达目标,并有剩余时间;

Tw≤△T时,舵机不能到达目标;

理论上:当T=T时,系统最连贯,而且舵机运动的最快。

实际过程中w不尽相同,连贯运动时的极限△T比较难以计算出来。

假如我们的舵机1DIV =8us,当PWM信号以最小变化量即(1DIV=8us)依次变化时,舵机的分辨率最高,但是速度会减慢。


#include "stm32f10x.h"
#include "duojikongzhiwork.h"


#define PWMout1  GPIO_Pin_0
#define PWMout2  GPIO_Pin_1
#define PWMout3  GPIO_Pin_2  
#define PWMout4  GPIO_Pin_3


#define PWMout5  GPIO_Pin_8
#define PWMout6  GPIO_Pin_9
#define PWMout7  GPIO_Pin_10  
#define PWMout8  GPIO_Pin_11


#define PWMout9   GPIO_Pin_5
#define PWMout10  GPIO_Pin_6
#define PWMout11  GPIO_Pin_7  
#define PWMout12  GPIO_Pin_8


#define PWMout13  GPIO_Pin_12
#define PWMout14  GPIO_Pin_13
#define PWMout15  GPIO_Pin_14  
#define PWMout16  GPIO_Pin_15


#define SetA(n)    GPIO_SetBits(GPIOA,n) //IO口置1
#define ResetA(n)  GPIO_ResetBits(GPIOA,n)//IO口清0
#define SetB(n)    GPIO_SetBits(GPIOB,n) //IO口置1
#define ResetB(n)  GPIO_ResetBits(GPIOB,n)//IO口清0
u16 PWMZQ=2500,PWMOUTbuff1,PWMOUTbuff2,PWMOUTcnt_1,PWMOUTcnt_2,PWMOUTcnt_3,PWMOUTcnt_4,PWMOUTcnt_5,PWMOUTcnt_6,PWMOUTcnt_7,PWMOUTcnt_8,PWMOUTcnt_9,PWMOUTcnt_10,PWMOUTcnt_11,PWMOUTcnt_12,PWMOUTcnt_13,PWMOUTcnt_14,PWMOUTcnt_15,PWMOUTcnt_16;
u16 PWMOUTbuf_1,PWMOUTbuf_2,PWMOUTbuf_3,PWMOUTbuf_4,PWMOUTbuf_5,PWMOUTbuf_6,PWMOUTbuf_7,PWMOUTbuf_8,PWMOUTbuf_9,PWMOUTbuf_10,PWMOUTbuf_11,PWMOUTbuf_12,PWMOUTbuf_13,PWMOUTbuf_14,PWMOUTbuf_15,PWMOUTbuf_16;


u8  mark=1,cnt1,cnt2;




/********IO口初始化*************/
void DJKZGIPO_ConfingA(void) //IOA口设置
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);//使能GPIOA口
GPIO_InitStructure.GPIO_Pin =  (GPIO_Pin_12|PWMout1|PWMout2|PWMout3|PWMout4|PWMout5|PWMout6|PWMout7|PWMout8);  //选择了哪个IO口
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;    //配置为推挽输出模式
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;   //IO口速度为50M
GPIO_Init(GPIOA, &GPIO_InitStructure);
}
void DJKZGIPO_ConfingB(void)//IOB口设置
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);//使能GPIOB口
GPIO_InitStructure.GPIO_Pin =  (PWMout9|PWMout10|PWMout11|PWMout12|PWMout13|PWMout14|PWMout15|PWMout16);  //选择了哪个IO口
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;  //配置为推挽输出模式
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //IO口速度为50M
GPIO_Init(GPIOB, &GPIO_InitStructure);
}








/********定时器2和4中断设置初始化*************/
void TIM4_Configuration(void)
{
  TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
NVIC_InitTypeDef         NVIC_InitStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE); //开启定时器4的时钟
TIM_ClearITPendingBit(TIM4,TIM_IT_Update);           //清除中断标志位
TIM_TimeBaseStructure.TIM_Period =  PWMOUTbuff1 - 1; //设置ARR初值
TIM_TimeBaseStructure.TIM_Prescaler = 72 - 1 ;       //预分频预分配系数 PSC   
TIM_TimeBaseStructure.TIM_ClockDivision = 0;         //设置时钟分割
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  //TIM向上计数模式
TIM_TimeBaseInit(TIM4, &TIM_TimeBaseStructure);      //根据TIM_TimeBaseInitStruct中指定的参数初始化TIMx模块的寄存器
TIM_ITConfig(TIM4,TIM_IT_Update,ENABLE);             //开启TIM4中断

NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);     // 设置NVIC中断分组2,  2位抢占优先级,2位响应优先级
NVIC_InitStructure.NVIC_IRQChannel = TIM4_IRQn;  
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;//抢占式优先级4级
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;  //响应优先级4级
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;      //TIM4通道使能
NVIC_Init(&NVIC_InitStructure);                    //根据NVIC_InitStruct中指定的参数初始化外设NVIC寄存器
TIM_Cmd(TIM4, ENABLE);                            //使能TIM4模块  
}
void TIM4_IRQHandler(void)   //TIM4中断
{
if(TIM_GetITStatus(TIM4, TIM_IT_Update) != RESET)
{
PWMOUTcnt_1=PWMOUTcnt_2=PWMOUTcnt_3=PWMOUTcnt_4=PWMOUTcnt_5=PWMOUTcnt_6=PWMOUTcnt_7=PWMOUTcnt_8=2000;
GPIO_PinReverse(GPIOA, GPIO_Pin_12);
duojikongzhiwork1();
TIM_SetAutoreload(TIM4, PWMOUTbuff1);
TIM_ClearITPendingBit(TIM4,TIM_IT_Update);//清除中断标志位
}
}




void TIM2_Configuration(void)
{
  TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
NVIC_InitTypeDef         NVIC_InitStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); //开启定时器2的时钟
TIM_ClearITPendingBit(TIM2,TIM_IT_Update);//清除中断标志位
TIM_TimeBaseStructure.TIM_Period =  PWMOUTbuff2 - 1; //设置ARR初值
TIM_TimeBaseStructure.TIM_Prescaler = 72 - 1 ; //预分频预分配系数 PSC   
TIM_TimeBaseStructure.TIM_ClockDivision = 0; //设置时钟分割
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  //TIM向上计数模式
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure); //根据TIM_TimeBaseInitStruct中指定的参数初始化TIMx模块的寄存器
TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE);//开启TIM4中断

NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);          // 设置NVIC中断分组2,  2位抢占优先级,2位响应优先级
NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;  
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;  //抢占式优先级4级
NVIC_InitStructure.NVIC_IRQChannelSubPriority =1;  //响应优先级4级
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //TIM2通道使能
NVIC_Init(&NVIC_InitStructure);  //根据NVIC_InitStruct中指定的参数初始化外设NVIC寄存器
TIM_Cmd(TIM2, ENABLE);  //使能TIM2模块  
}
void TIM2_IRQHandler(void)   //TIM2中断
{
if(TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET)
{
PWMOUTcnt_9=PWMOUTcnt_10=PWMOUTcnt_11=PWMOUTcnt_12=PWMOUTcnt_13=PWMOUTcnt_14=PWMOUTcnt_15=PWMOUTcnt_16=2000;
duojikongzhiwork2();
TIM_SetAutoreload(TIM2, PWMOUTbuff2);
TIM_ClearITPendingBit(TIM2,TIM_IT_Update);//清除中断标志位
}
}










/********八路周期20ms、占空比可控PWM*************/
void duojikongzhiwork1(void)
{
ResetA(PWMout1);
ResetA(PWMout2);
ResetA(PWMout3);
ResetA(PWMout4);
ResetA(PWMout5);
ResetA(PWMout6);
ResetA(PWMout7);
ResetA(PWMout8); 
switch (cnt1)
{
case 0:
if( mark )
{PWMOUTbuf_1 = PWMOUTcnt_1; SetA(PWMout1);mark=0;}   
else 
{PWMOUTbuf_1 = PWMZQ-PWMOUTcnt_1; ResetA(PWMout1);cnt1 = 1;mark=1;} 
PWMOUTbuff1 = PWMOUTbuf_1;  
break;


case 1:  
if(mark) 
{PWMOUTbuf_2 = PWMOUTcnt_2; SetA(PWMout2);mark=0;}   
else
{PWMOUTbuf_2 = PWMZQ-PWMOUTcnt_2; ResetA(PWMout2);cnt1 = 2;mark=1;} 
PWMOUTbuff1 = PWMOUTbuf_2;  
break;


case 2: 
if(mark) 
{PWMOUTbuf_3 = PWMOUTcnt_3; SetA(PWMout3);mark=0;}   
else
{PWMOUTbuf_3 = PWMZQ-PWMOUTcnt_3;ResetA(PWMout3);cnt1 = 3;mark=1;} 
PWMOUTbuff1 = PWMOUTbuf_3;  
break;
case 3:
if(mark)
{PWMOUTbuf_4 = PWMOUTcnt_4; SetA(PWMout4);mark=0;}   
else 
{PWMOUTbuf_4 = PWMZQ-PWMOUTcnt_4; ResetA(PWMout4);cnt1 = 4;mark=1;}    
PWMOUTbuff1 = PWMOUTbuf_4;  
break;


case 4:  
if(mark) 
{PWMOUTbuf_5 = PWMOUTcnt_5; SetA(PWMout5);mark=0;}   
else
{PWMOUTbuf_5 = PWMZQ-PWMOUTcnt_5;ResetA(PWMout5);cnt1 = 5;mark=1;} 
PWMOUTbuff1 = PWMOUTbuf_5;  
break;


case 5:
if(mark) 
{PWMOUTbuf_6 = PWMOUTcnt_6; SetA(PWMout6);mark=0;}   
else
{PWMOUTbuf_6 = PWMZQ-PWMOUTcnt_6;ResetA(PWMout6);cnt1 = 6;mark=1;} 
PWMOUTbuff1 = PWMOUTbuf_6;  
break;


case 6:  
if(mark) 
{PWMOUTbuf_7 = PWMOUTcnt_7; SetA(PWMout7);mark=0;}
else
{PWMOUTbuf_7 = PWMZQ-PWMOUTcnt_7;ResetA(PWMout7);cnt1 = 7;mark=1;} 
PWMOUTbuff1 = PWMOUTbuf_7;  
break;


case 7:
if(mark) 
{PWMOUTbuf_8 = PWMOUTcnt_8; SetA(PWMout8);mark=0;}   
else
{PWMOUTbuf_8 = PWMZQ-PWMOUTcnt_8;ResetA(PWMout8);cnt1= 0;mark=1;} 
PWMOUTbuff1 = PWMOUTbuf_8;  
break;
default: break;
}
}
/********八路周期20ms、占空比可控PWM*************/
void duojikongzhiwork2(void)
{
ResetB(PWMout9);
ResetB(PWMout10);
ResetB(PWMout11);
ResetB(PWMout12);
ResetB(PWMout13);
ResetB(PWMout14);
ResetB(PWMout15);
ResetB(PWMout16); 
switch (cnt2)
{
case 0:
if( mark )
{PWMOUTbuf_9 = PWMOUTcnt_9; SetB(PWMout9);mark=0;}   
else 
{PWMOUTbuf_9 = PWMZQ-PWMOUTcnt_9; ResetB(PWMout9);cnt2 = 1;mark=1;} 
PWMOUTbuff2 = PWMOUTbuf_9;  
break;


case 1:  
if(mark) 
{PWMOUTbuf_10 = PWMOUTcnt_10; SetB(PWMout10);mark=0;}   
else
{PWMOUTbuf_10 = PWMZQ-PWMOUTcnt_10; ResetB(PWMout10);cnt2 = 2;mark=1;} 
PWMOUTbuff2  = PWMOUTbuf_10;  
break;


case 2: 
if(mark) 
{PWMOUTbuf_11 = PWMOUTcnt_11; SetB(PWMout11);mark=0;}   
else
{PWMOUTbuf_11 = PWMZQ-PWMOUTcnt_11;ResetB(PWMout11);cnt2 = 3;mark=1;} 
PWMOUTbuff2  = PWMOUTbuf_11;  
break;

case 3:
if(mark)
{PWMOUTbuf_12 = PWMOUTcnt_12; SetB(PWMout12);mark=0;}   
else 
{PWMOUTbuf_12 = PWMZQ-PWMOUTcnt_12; ResetB(PWMout12);cnt2 = 4;mark=1;}    
PWMOUTbuff2  = PWMOUTbuf_12;
break;


case 4:  
if(mark) 
{PWMOUTbuf_13 = PWMOUTcnt_13; SetB(PWMout13);mark=0;}   
else
{PWMOUTbuf_13 = PWMZQ-PWMOUTcnt_13;ResetB(PWMout13);cnt2 = 5;mark=1;} 
PWMOUTbuff2  = PWMOUTbuf_13;  
break;


case 5:
if(mark) 
{PWMOUTbuf_14 = PWMOUTcnt_14; SetB(PWMout14);mark=0;}   
else
{PWMOUTbuf_14 = PWMZQ-PWMOUTcnt_14;ResetB(PWMout14);cnt2= 6;mark=1;} 
PWMOUTbuff2  = PWMOUTbuf_14;  
break;


case 6:  
if(mark) 
{PWMOUTbuf_15 = PWMOUTcnt_15; SetB(PWMout15);mark=0;}
else
{PWMOUTbuf_15 = PWMZQ-PWMOUTcnt_15;ResetB(PWMout15);cnt2 = 7;mark=1;} 
PWMOUTbuff2  = PWMOUTbuf_15; 
break;


case 7:
if(mark) 
{PWMOUTbuf_16 = PWMOUTcnt_16; SetB(PWMout16);mark=0;}   
else
{PWMOUTbuf_16 = PWMZQ-PWMOUTcnt_16;ResetB(PWMout16);cnt2 = 0;mark=1;} 
break;
default: break;
}
 


   2舵机的追随特性

  假设现在舵机稳定在A点,这时候CPU发出一个PWM信号,舵机全速由A点转向B点,在这个过程中需要一段时间,舵机才能运动到B点。

保持时间为T

   当Tw≥△T时,舵机能够到达目标,并有剩余时间;

Tw≤△T时,舵机不能到达目标;

理论上:当T=T时,系统最连贯,而且舵机运动的最快。

实际过程中w不尽相同,连贯运动时的极限△T比较难以计算出来。

假如我们的舵机1DIV =8us,当PWM信号以最小变化量即(1DIV=8us)依次变化时,舵机的分辨率最高,但是速度会减慢。

发布了54 篇原创文章 · 获赞 2 · 访问量 6万+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章