舵机
1.舵机简介
在机器人机电控制系统中,舵机控制效果是性能的重要影响因素。舵机可以在微机电系统和航模中作为基本的输出执行机构,其简单的控制和输出使得单片机系统非常容易与之接口。
舵机是一种位置(角度)伺服的驱动器,适用于那些需要角度不断变化并可以保持的控制系统。目前在高档遥控玩具,如航模,包括飞机模型,潜艇模型;遥控机器人中已经使用得比较普遍。舵机是一种俗称,其实是一种伺服马达。
2. 其工作原理是:
控制信号由接收机的通道进入信号调制芯片,获得直流偏置电压。它内部有一个基准电路,产生周期为20ms,宽度为1.5ms的基准信号,将获得的直流偏置电压与电位器的电压比较,获得电压差输出。最后,电压差的正负输出到电机驱动芯片决定电机的正反转。当电机转速一定时,通过级联减速齿轮带动电位器旋转,使得电压差为0,电机停止转动。当然我们可以不用去了解它的具体工作原理,知道它的控制原理就够了。就象我们使用晶体管一样,知道可以拿它来做开关管或放大管就行了,至于管内的电子具体怎么流动是可以完全不用去考虑的。
3. 舵机的控制:
舵机的控制一般需要一个20ms左右的时基脉冲,该脉冲的高电平部分一般为0.5ms~2.5ms范围内的角度控制脉冲部分。以180度角度伺服为例,那么对应的控制关系是这样的:
0.5ms--------------0度;
1.0ms------------45度;
1.5ms------------90度;
2.0ms-----------135度;
2.5ms-----------180度;
28BYJ48旋转
按照设定方向转动一个固定的角度,28BYJ48型4相8拍电机,当对电机施加一系列连续不断的控制脉冲时,它可以连续不断的转动,当通电状态的改变完成一个循环时,转子转过一个齿距。4相步进电机可以在不同的脉冲序列下运行,常见的脉冲序列有单相四拍(单相绕组通电):A-B-C-D-A..,双相四拍(双向绕组通电):AB-BC-CD-DA-AB...,八拍:A-AB-B-BC-C-CD-D-DA-A...。
- 技术参数:
表2
参数 |
值 |
参数 |
值 |
电压VDC |
12 |
空载牵入频率 |
≥500 |
直流电阻25°C Ω±7% |
85 |
空载牵出频率 |
≥800 |
步距角 |
5.625°/64 |
绝缘耐压 |
600 |
减速比 |
1/64 |
温升 K |
≤55 |
牵入转矩(100Hz时) |
550 |
噪音 dB |
≤40 |
自定位转矩 |
300 |
驱动方式 |
四相八拍 |
连接线长:230mm,采用UL 26AWG 1061的电源线 |
二:接线示意图
矩阵按键扫描原理
方法一:
逐行扫描:我们可以通过高四位轮流输出低电平来对矩阵键盘进行逐行扫描,当低四位接收到的数据不全为1的时候,说明有按键按下,然后通过接收到的数据是哪一位为0来判断是哪一个按键被按下。
方法二:
行列扫描:我们可以通过高四位全部输出低电平,低四位输出高电平。当接收到的数据,低四位不全为高电平时,说明有按键按下,然后通过接收的数据值,判断是哪一列有按键按下,然后再反过来,高四位输出高电平,低四位输出低电平,然后根据接收到的高四位的值判断是那一行有按键按下,这样就能够确定是哪一个按键按下了。
接线方法及试验现象
本次试验采用的是stm32f103vct6Z作为控制器,键盘采用行列扫描,步进电机采用四相八拍的控制方法。
- 将28BYJ-48步进电机的导线插到开发板步进电机1接口处。将舵机的导线插到开发板舵机3接口处。如下图所示:
- 将开发板用数据线与电脑连接,然后打开USB下载器,将相应的HEX文件下载到开发板上。
舵机的试验现象为:
按下KEY1:
输出0.5ms的脉冲到舵机,舵机转动0°
按下KEY2:
输出1ms的脉冲到舵机,舵机转动45°
按下KEY3:
输出1.5ms的脉冲到舵机,舵机转动90°
按下KEY4:
输出2ms的脉冲到舵机,舵机转动135°
按下KEY5:
输出2.5ms的脉冲到舵机,舵机转动180°
步进电机的试验现象为:
按下KEY6:步进电机加速旋转
按下KEY7:步进电机减速旋转
按下KEY8:步进电机反向旋转
试验代码:
试验代码分为三部分。第一位主函数main.c,第二部分为key.c和key.h,第三部分为motor.c和motor.h。
1.
main.c
#include "stm32f10x.h"
#include "key.h"
#include "motor.h"
u8 key_num = 0;
u8 dir = 0;
u8 sp=8;
int main(void)
{
ChipHalInit(); //片内硬件初始化
ChipOutHalInit(); //片外硬件初始化
while (1)
{
key_num=key();
if(key_num=='1'){
SetSG90(1,1);
}
else if(key_num=='2'){
SetSG90 (1,45);
}
else if(key_num=='3'){
SetSG90(1,90);
}
else if(key_num=='4'){
SetSG90(1,135);
}
else if(key_num=='5'){
SetSG90(1,179);
}
else if(key_num=='6'){
sp++;
SteppingRun4(sp,dir,1);
}
else if(key_num=='7'){
sp--;
SteppingRun4(sp,dir,1);
}
else if(key_num=='8'){
dir=~dir;
SteppingRun4(sp,dir,1);
}
}
}
2.key.h
#ifndef _KEY_H_
#define _KEY_H_
#define COLKEY1_H() GPIOC->BSRR=0x00000200
#define COLKEY1_L() GPIOC->BRR=0x00000200
#define COLKEY2_H() GPIOC->BSRR=0x00000400
#define COLKEY2_L() GPIOC->BRR=0x00000400
#define COLKEY3_H() GPIOC->BSRR=0x00000800
#define COLKEY3_L() GPIOC->BRR=0x00000800
#define COLKEY4_H() GPIOC->BSRR=0x00001000
#define COLKEY4_L() GPIOC->BRR=0x00001000
#define ROWKEY1() (GPIOB->IDR & 0x00000400)
#define ROWKEY2() (GPIOB->IDR & 0x00000020)
#define ROWKEY3() (GPIOE->IDR & 0x00000001)
#define ROWKEY4() (GPIOE->IDR & 0x00000002)
u8 key(void);
u8 read_key(void);
#endif
Key.c
#include "stm32f10x.h"
#include "key.h"
u8 realkeynum[16][2] =
{
{17,'1'},{33,'2'},{49,'3'},{65,'A'},
{18,'4'},{34,'5'},{50,'6'},{66,'B'},
{19,'7'},{35,'8'},{51,'9'},{67,'C'},
{20,'*'},{36,'0'},{52,'#'},{68,'D'},
};
u8 read_key(void)
{
if(ROWKEY1() == 0)
return 1;
else if(ROWKEY2() == 0)
return 2;
if(ROWKEY3() == 0)
return 3;
if(ROWKEY4() == 0)
return 4;
return 0;
}
u8 key(void)
{
u8 key_return = 0,i;
COLKEY1_L();
COLKEY2_H();
COLKEY3_H();
COLKEY4_H();
if(read_key() > 0)
{
key_return = 0x10 + read_key();
}
COLKEY1_H();
COLKEY2_L();
COLKEY3_H();
COLKEY4_H();
if(read_key() > 0)
{
key_return = 0x20 + read_key();
}
COLKEY1_H();
COLKEY2_L();
COLKEY3_H();
COLKEY4_H();
if(read_key() > 0)
{
key_return = 0x20 + read_key();
}
COLKEY1_H();
COLKEY2_H();
COLKEY3_L();
COLKEY4_H();
if(read_key() > 0)
{
key_return = 0x30 + read_key();
}
COLKEY1_H();
COLKEY2_H();
COLKEY3_H();
COLKEY4_L();
if(read_key() > 0)
{
key_return = 0x40 + read_key();
}
for(i = 0;i < 16;i ++)
{
if(realkeynum[i][0] == key_return)
{
key_return = realkeynum[i][1];
break;
}
}
return key_return;
}
Motor.h
#ifndef __MOTOR_H
#define __MOTOR_H
#define MOTOR1A_L() GPIOB->BRR = 0x00000002 //PB1
#define MOTOR1A_H() GPIOB->BSRR = 0x00000002
#define MOTOR1B_L() GPIOE->BRR = 0x00000080 //PE7
#define MOTOR1B_H() GPIOE->BSRR = 0x00000080
#define MOTOR1C_L() GPIOE->BRR = 0x00000100 //PE8
#define MOTOR1C_H() GPIOE->BSRR = 0x00000100
#define MOTOR1D_L() GPIOE->BRR = 0x00000200 //PE9
#define MOTOR1D_H() GPIOE->BSRR = 0x00000200
void SteppingRun4(u8 sp,u8 dir,u8 en);
void SetSG90(u8 ch,u8 angle);
#endif
Motor.c
#include "stm32f10x.h"
#include "Motor.h"
#include "delay.h"
#include "pwm.h"
//步进电机4驱动 sp-速度,dir-方向 ,en - 使能
//定时执行,执行一次走一步(测试代码为500us执行一次)
void SteppingRun4(u8 sp,u8 dir,u8 en)
{
u16 i = 0;
static u8 flag = 1,sp_delay = 12;
if(en)
{
if(sp > 0 && sp <= 10)
{
if(sp_delay <= sp)
{
sp_delay = 12;
if(flag == 1)
{
MOTOR1A_H();
MOTOR1B_L();
MOTOR1C_L();
MOTOR1D_L();
}
else if(flag == 2)
{
MOTOR1A_H();
MOTOR1B_H();
MOTOR1C_L();
MOTOR1D_L();
}
else if(flag == 3)
{
MOTOR1A_L();
MOTOR1B_H();
MOTOR1C_L();
MOTOR1D_L();
}
else if(flag == 4)
{
MOTOR1A_L();
MOTOR1B_H();
MOTOR1C_H();
MOTOR1D_L();
}
else if(flag == 5)
{
MOTOR1A_L();
MOTOR1B_L();
MOTOR1C_H();
MOTOR1D_L();
}
else if(flag == 6)
{
MOTOR1A_L();
MOTOR1B_L();
MOTOR1C_H();
MOTOR1D_H();
}
else if(flag == 7)
{
MOTOR1A_L();
MOTOR1B_L();
MOTOR1C_L();
MOTOR1D_H();
}
else if(flag == 8)
{
MOTOR1A_H();
MOTOR1B_L();
MOTOR1C_L();
MOTOR1D_H();
}
if(dir == 1)
{
flag ++;
if(flag > 8)
{
flag = 1;
}
}
else
{
flag --;
if(flag < 1)
{
flag = 8;
}
}
}
sp_delay--;
}
}
}
//舵机角度设置 ch-通道数(0-4) angle-角度(0-180)
void SetSG90(u8 ch,u8 angle)
{
if(angle > 180)
{
angle = 180;
}
SetTim4Pwm(ch,angle);
}