一、本周工作:
9月 27 日 - 10月 3日
利用STM32F103RB芯片内部通用定时器2和4,产生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点。
保持时间为Tw
当Tw≥△T时,舵机能够到达目标,并有剩余时间;
当Tw≤△T时,舵机不能到达目标;
理论上:当Tw=△T时,系统最连贯,而且舵机运动的最快。
实际过程中w不尽相同,连贯运动时的极限△T比较难以计算出来。
假如我们的舵机1DIV =8us,当PWM信号以最小变化量即(1DIV=8us)依次变化时,舵机的分辨率最高,但是速度会减慢。
二、本周小结:
看了一些关于如何控制多路舵机的资料,发现基本上使用普通的PWM就可以正常使用,但是需要一定的精度和抗干扰性。抗干扰可以用硬件处理。在可以正常驱动16路舵机的基础上,进行位姿分析。位姿分析如果用软件模拟这个会比较复杂。
三、疑问:出现了一个问题如下图,设置IO口时启用A组和B组是可以正常产生PWM,但是如果启用的是A组和C组PWM会出现问题。目前还不知什么情况。。
四 下周计划:学习机器人多个舵机控制算法,查找软件模拟位姿动作资料。
附录:
2、舵机的追随特性
假设现在舵机稳定在A点,这时候CPU发出一个PWM信号,舵机全速由A点转向B点,在这个过程中需要一段时间,舵机才能运动到B点。
保持时间为Tw
当Tw≥△T时,舵机能够到达目标,并有剩余时间;
当Tw≤△T时,舵机不能到达目标;
理论上:当Tw=△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点。
保持时间为Tw
当Tw≥△T时,舵机能够到达目标,并有剩余时间;
当Tw≤△T时,舵机不能到达目标;
理论上:当Tw=△T时,系统最连贯,而且舵机运动的最快。
实际过程中w不尽相同,连贯运动时的极限△T比较难以计算出来。
假如我们的舵机1DIV =8us,当PWM信号以最小变化量即(1DIV=8us)依次变化时,舵机的分辨率最高,但是速度会减慢。