写在前面:要驱动电机首先需要通过单片机输入控制信号到TB6612电机驱动板再通过TB6612驱动直流电机,所以先了解这仨兄弟再进行程序编写。有任何不清楚的地方可以在评论区提出哦!!如果你所使用的型号有所不同,理论上只需在代码稍微修改下即可。

目录
1.如何让直流电机转动

1.1 如何实现电机调速:
1.如果我们可以调节施加在电机上面的电压大小, 即可实现直流电机调速。当然,由于Arduino可以输出PWM(脉冲宽度调制)信号,在此我们使用PWM来控制电压大小;
2.改变施加电机上面电压的极性,即可实现电机正反转。
1.2 PWM介绍:
PWM中文叫做脉冲宽度调制,通过调节脉冲宽度改变占空比以改变平均输出电压
占空比:
是一个脉冲周期内,高电平的时间与整个周期时间的比例,一个脉冲周期内高电平所占时间越短,模拟出的电压越低。

2.TB6612电机驱动器的作用
电机驱动器的作用主要有仨:
- 精确控制:驱动器可以精确地控制电机的速度、位置和扭矩,以满足各种复杂的应用需求。
- 保护电机:驱动器可以监测电机的运行状态,如电流、电压和温度等,当检测到异常情况时,可以及时切断电源,以保护电机免受损坏。
- 提供多种控制方式:驱动器可以提供多种控制方式,如模拟量控制、脉冲控制、现场总线控制等,以满足不同应用场景的需求。
- 增强系统灵活性:通过驱动器,可以将电机与上位机或其他控制系统进行连接,实现更高级别的自动化控制和远程监控。
TB6612能通过额外的12V电源,来保证电机有充足电压驱动。

2.1.理论上TB6612接上电机 同时 电源输入接口接上12V电源后,即可通过单片机输入PWM信号来驱动电机并控制速度,但是由于TB6612限制需要STBY引脚置1后,才会有PWM信号输入(才能驱动电机),由此列出真值表↓

2.3.而从上述 真值表 我们可以知道,TB6612的IN引脚的 高低电平决定了电机转动状态,IN1高电平正转 IN2高电平反转,IN为同值时制动停止 因此我们需要通过单片机输入相应的信号控制电机,如图所示,TB6612上面正好有两对IN引脚:
AIN1AIN2 和BIN1 BIN2 分别连接 AO1AO2 BO1BO2 也就是俩电机正负极 ,来输入控制信号。
至此就该考虑如何使用单片机输入控制信号。↓
3.mage2560控制电机
The first: TB6612的IN引脚 PWM引脚 需要信号输入,以及STBY置1。所以,需要在mage2650找到一个PWM输出口以及数字信号输出口。

3.1:TB6612跟mage2560接线
ps:在此之前 请先准备一些公对母杜邦线,同时TB6612需要外接12V电源给电机供电
TB6612丝印标识 | mage2560主板引脚 |
---|---|
PWMA | 3(PWM) |
AIN2 | 4 |
AIN1 | 5 |
STBY | 7 |
BIN1 | 8 |
BIN2 | 9 |
PWMB | 10(PWM) |
GND | GND |
5V(稳压版可向2560供电) | 5V |
3.2:程序编写
如果没有Arduino IDE(程序烧录软件),请先下载安装,烧录步骤:
1.将Arduino与电脑连接,(如果IDE无法识别则需要在电脑上安装串口驱动).
2.在左上角有个串口标识的小窗口,下拉选择对应的端口号及开发版型号。
然后就可以根据接线编写程序并烧录了,思路如下:
- 定义相关接线引脚
- 初始化各个引脚
- 用PWM俩引脚控制电机转速
- 使用IN引脚控制电机正反转
实现:(烧录成功后两个电机会以最大速度正转)
//定义引脚名称
#define PWMA 3 //3为模拟引脚,用于PWM控制
#define AIN1 5
#define AIN2 4
#define PWMB 10 //10为模拟引脚,用于PWM控制
#define BIN1 8
#define BIN2 9
#define STBY 7 //2、4、8、12、7为数字引脚,用于开关量控制
#define Voltage A0 //使用模拟引脚
int PwmA, PwmB;
double V;
void setup() {
//TB6612电机驱动模块控制信号初始化
pinMode(AIN1, OUTPUT);//控制电机A的方向,(AIN1, AIN2)=(1, 0)为正转,(AIN1, AIN2)=(0, 1)为反转
pinMode(AIN2, OUTPUT);
pinMode(BIN1, OUTPUT);//控制电机B的方向,(BIN1, BIN2)=(0, 1)为正转,(BIN1, BIN2)=(1, 0)为反转
pinMode(BIN2, OUTPUT);
pinMode(PWMA, OUTPUT);//A电机PWM
pinMode(PWMB, OUTPUT);//B电机PWM
pinMode(STBY, OUTPUT);//TB6612FNG使能, 置0则所有电机停止, 置1才允许控制电机
//初始化TB6612电机驱动模块
digitalWrite(AIN1, 1);
digitalWrite(AIN2, 0);
digitalWrite(BIN1, 1);
digitalWrite(BIN2, 0);
digitalWrite(STBY, 1);
analogWrite(PWMA, 0);
analogWrite(PWMB, 0);
//初始化串口,用于输出电池电压
Serial.begin(9600);
pinMode(Voltage,INPUT); //初始化作为输入端
}
/**************************************************************************
函数功能:设置指定电机转速
入口参数:指定电机motor,motor=1(2)代表电机A(B); 指定转速pwm,大小范围为0~255,代表停转和满速
返回 值:无
**************************************************************************/
void SetPWM(int motor, int pwm)
{
if(motor==1&&pwm>=0)//motor=1代表控制电机A,pwm>=0则(AIN1, AIN2)=(1, 0)为正转
{
digitalWrite(AIN1, 1);
digitalWrite(AIN2, 0);
analogWrite(PWMA, pwm);
}
else if(motor==1&&pwm<0)//motor=1代表控制电机A,pwm<0则(AIN1, AIN2)=(0, 1)为反转
{
digitalWrite(AIN1, 0);
digitalWrite(AIN2, 1);
analogWrite(PWMA, -pwm);
}
else if(motor==2&&pwm>=0)//motor=2代表控制电机B,pwm>=0则(BIN1, BIN2)=(0, 1)为正转
{
digitalWrite(BIN1, 0);
digitalWrite(BIN2, 1);
analogWrite(PWMB, pwm);
}
else if(motor==2&&pwm<0)//motor=2代表控制电机B,pwm<0则(BIN1, BIN2)=(1, 0)为反转
{
digitalWrite(BIN1, 1);
digitalWrite(BIN2, 0);
analogWrite(PWMB, -pwm);
}
}
void loop()
{
SetPWM(1, 255);//电机AB同时满速正转
SetPWM(2, 255);
V=analogRead(Voltage); //读取模拟引脚A0模拟量
Serial.print(V*0.05371); //对模拟量转换并通过串口输出
Serial.println("V");
delay(500);//正转3s
// SetPWM(1, 0);//电机AB停止
// SetPWM(2, 0);
// delay(1000);//停止1s
//
// SetPWM(1, 128);//电机AB同时半速正转
// SetPWM(2, 128);
// delay(3000);//半速正转3s
//
// SetPWM(1, 0);//电机AB停止
// SetPWM(2, 0);
// delay(1000);//停止1s
//
// SetPWM(1, -255);//电机AB同时满速反转
// SetPWM(2, -255);
// delay(3000);//反转3s
//
// SetPWM(1, 0);//电机AB停止
// SetPWM(2, 0);
// delay(1000);//停止1s
//
// SetPWM(1, 255);//电机A满速正转
// SetPWM(2, -255);//电机B满速反转
// delay(3000);//持续3s
//
// SetPWM(1, 0);//电机AB停止
// SetPWM(2, 0);
// delay(1000);//停止1s
}
4.电机测速
4.1:测速原理
MG513电机采用的是霍尔式编码器,其原理是在圆盘上均匀分布若干不同的磁极,当电机旋转时就可输出若干脉冲信号,为了判断方向,输出的脉冲信号A相跟B相会有相位差,顺时针转动时A相下降沿对应B相高电平,逆时针时A相上升沿对应B相高电平。那如何计算转速呢,既然有输出脉冲信号,直接计算A或者B相单位时间内输出的脉冲数量就行了,但是 但是 但是 由于减速器的存在,计算出来的转速并不等于输出轴转速,所以 所以 所以 我们得知道电机的转速比!以及霍尔编码器的线数(编码器旋转一周能产生的脉冲数) 通过线数×减速比我们可以得知输出轴旋转一圈输出的脉冲数量。有了这个参数,我们就可以用单位时间内产生的脉冲数来计算电机输出轴转速了。
参考文档:http://t.csdnimg.cn/kUeIH
4.2:mage2560接收转速信号
知道了转速之后有什么用呢 答案是那三个字母 P~I~D!当然这不在本文章讨论范围之内,当务之急是让mage2560知道电机的转速。
4.2.1:接线
还是熟悉的图,现在主要了解一下中间四条编码电机线的用处。
需要传输的就是编码器AB相这两条线的数据,所以考虑的问题也就是如何将这两条线接到TB6612再从TB6612输出到mage2560
TB6612 | mage560 |
---|---|
E1A | 21 |
E1B | 20 |
E2A | 19 |
E2B | 18 |
将俩电机的AB相输出线分别接在mage2560中断口
4.3:程序编写
思路:
1.定义相关引脚
2.二频计数编写
3.四倍频计数
3.确定输出轴单圈转速及计算周期
#include "Arduino.h"
int reducation = 30; //减速比,根据电机参数设置,比如 15 | 30 | 60
int pulse = 13; //编码器旋转一圈产生的脉冲数该值需要参考商家电机参数
int per_round = pulse * reducation * 4;//车轮旋转一圈产生的脉冲数,四倍频计数乘以4
long start_time = millis();//一个计算周期的开始时刻,初始值为 millis();
long interval_time = 50;//一个计算周期 50ms
double current_vel_l;//左轮转速
double current_vel_r;//右轮转速
volatile int countl = 0;//左轮正转,那么每计数一次自增1,如果是反转,那么每计数一次自减1
volatile int countr = 0;//右轮正转,那么每计数一次自增1,如果是反转,那么每计数一次自减1
int motor_lA = 21;//中断口是2
int motor_lB = 20;//中断口是3
int motor_rA =19;
int motor_rB =18;
int pwma = 3;
int ain1 = 9;
int ain2 = 8;
int stby = 10;
int pwmb = 5;
int bin1 = 6;
int bin2 = 7;
int led = 13;
void count_lA(){
//2倍频计数实现
//手动旋转电机一圈,输出结果为 一圈脉冲数 * 减速比 * 2
if(digitalRead(motor_lA) == HIGH){
if(digitalRead(motor_lB) == HIGH){//A 高 B 高
countl++;
} else {//A 高 B 低
countl--;
}
} else {
if(digitalRead(motor_lB) == LOW){//A 低 B 低
countl++;
} else {//A 低 B 高
countl--;
}
}
}
//与A实现类似
//4倍频计数实现
//手动旋转电机一圈,输出结果为 一圈脉冲数 * 减速比 * 4
void count_lB(){
if(digitalRead(motor_lB) == HIGH){
if(digitalRead(motor_lA) == LOW){//B 高 A 低
countl++;
} else {//B 高 A 高
countl--;
}
} else {
if(digitalRead(motor_lA) == HIGH){//B 低 A 高
countl++;
} else {//B 低 A 低
countl--;
}
}
}
void count_rA(){
//2倍频计数实现
//手动旋转电机一圈,输出结果为 一圈脉冲数 * 减速比 * 2
if(digitalRead(motor_rA) == HIGH){
if(digitalRead(motor_rB) == HIGH){//A 高 B 高
countr++;
} else {//A 高 B 低
countr--;
}
} else {
if(digitalRead(motor_rB) == LOW){//A 低 B 低
countr++;
} else {//A 低 B 高
countr--;
}
}
}
void count_rB(){
if(digitalRead(motor_rB) == HIGH){
if(digitalRead(motor_rA) == LOW){//B 高 A 低
countr++;
} else {//B 高 A 高
countr--;
}
} else {
if(digitalRead(motor_rA) == HIGH){//B 低 A 高
countr++;
} else {//B 低 A 低
countr--;
}
}
}
//停止
void Stop(){
digitalWrite(ain1,LOW);
digitalWrite(ain2,LOW);
digitalWrite(bin1,LOW);
digitalWrite(bin2,LOW);
}
//正转
void up(){
digitalWrite(ain1,HIGH);
digitalWrite(ain2,LOW);
digitalWrite(bin1,HIGH);
digitalWrite(bin2,LOW);
delay(500);
}
//反转
void back(){
digitalWrite(ain1,LOW);
digitalWrite(ain2,HIGH);
digitalWrite(bin1,HIGH);
digitalWrite(bin2,LOW);
delay(2000);
}
//计算当前电机转速
void get_current_vel(){
long right_now = millis();
long past_time = right_now - start_time;//计算逝去的时间
if(past_time >= interval_time){//如果逝去时间大于等于一个计算周期
//1.禁止中断
noInterrupts();
//2.计算转速 转速单位可以是秒,也可以是分钟... 自定义即可(目前单位为分)
current_vel_l = (double)countl / per_round / past_time * 1000 * 60;//左轮
current_vel_r = (double)countr / per_round / past_time * 1000 * 60;//右轮
//3.重置计数器
countl = 0;
countr = 0;
//4.重置开始时间
start_time = right_now;
//5.重启中断
interrupts();
Serial.println(current_vel_l);
Serial.println(current_vel_r);
}
}
//主函数
void setup() {
Serial.begin(57600);//设置波特率
pinMode(motor_lA,INPUT);
pinMode(motor_lB,INPUT);
pinMode(motor_rA,INPUT);
pinMode(motor_rB,INPUT);
attachInterrupt(3,count_lA,CHANGE);
attachInterrupt(2,count_lB,CHANGE);
attachInterrupt(4,count_rA,CHANGE);
attachInterrupt(5,count_rB,CHANGE);
pinMode(pwma,OUTPUT);
pinMode(ain1,OUTPUT);
pinMode(ain2,OUTPUT);
pinMode(pwmb,OUTPUT);
pinMode(bin1,OUTPUT);
pinMode(bin2,OUTPUT);
pinMode(stby,OUTPUT);
pinMode(led,OUTPUT);
digitalWrite(stby,HIGH);
analogWrite(pwma,20);
analogWrite(pwmb,20);
}
void loop() {
delay(10);
get_current_vel();
up();
delay(2000);
}