基于74HC595/L293D电机驱动板控制麦克纳姆轮小车

L293D电机驱动板控制麦克纳姆轮小车

前言:
第一次接触74HC595芯片搞Arduino的时候也没想过要写实现原理,过程也查了些资料,慢慢喜欢研究功能背后的东西,能力有限不算深挖,简单记录一下。

准备

主控板(Ardunio UNO)X 1
电机驱动板 X1
TT马达电机 X4
轮子 X 4
蓝牙模块 X 1
底板 X 1
杜邦线 若干
蓝牙调试器:用来发送蓝牙信息控制小车

1.介绍L293D电机驱动板


1.1外观

在这里插入图片描述
(为了兼容Arduino UNO和引出IO0、IO1做蓝牙通讯,已做了一些排针调整)

1.2 参数

电机驱动模块,可驱动四通直流电机;

采用芯片串/并转换器,称为74HC595。该芯片有8个输出(完美)和3个输入,用它来一次一位地输入数据。在接收脉冲时如果数据引脚为高电平,则将1移入移位寄存器;否则为0。当所有8个脉冲都接收到后,将8个值复制到锁存寄存器。

该芯片还有一个输出使能(OE)引脚,用于启用或禁用一次所有输出。
您可以将其连接到PWM引脚,然后使用“analogWrite()”函数来控制电机的速度。

2.介绍麦克纳姆轮


2.1 外观

在这里插入图片描述在这里插入图片描述在这里插入图片描述

2.2 特点

麦克纳姆轮是一种带有周边轮轴的机轮,一般分两种,一种周边轮轴向左倾斜,另一种轮轴向右倾斜。这些成角度的周边轮轴把一部分的机轮转向力转化到一个机轮法向力上面,所以能够使汽车实现左右平移的运动。

2.3.运动原理

2.3.1组装要点(俯视视角)

在这里插入图片描述

2.3.2 运动方向

轮子不同旋转方向对应前进、后退移动:
在这里插入图片描述


轮子不同旋转方向对应逆时针旋转和顺时针旋转:
在这里插入图片描述


轮子不同旋转方向对应向左、向右平移:

在这里插入图片描述


左下角和右上角侧移:
在这里插入图片描述


左上角和右下角侧移:

在这里插入图片描述

3.接线


3.1 电机接线

在这里插入图片描述

3.2 蓝牙接线

在这里插入图片描述

4.编程实现


4.1定义

//PWM控制引脚
const int PWM2A = 11;      //M1 motor
const int PWM2B = 3;       //M2 motor
const int PWM0A = 6;       //M3 motor
const int PWM0B = 5;       //M4 motor

//芯片引脚
const int DIR_CLK = 4;     // Data input clock line 输入时钟
const int DIR_EN = 7;      //Equip the L293D enabling pins 使能端
const int DATA = 8;        // USB cable
const int DIR_LATCH = 12;  // Output memory latch clock 输出锁存器

//作为shiftOut函数的Dir参数,控制运动状态
const int Forward = 216;    //216 save to Forward 前进
const int Back = 39;      //39 save to Back 后退
const int Left = 116;      //116 save to Left 左移
const int Right = 139;     //139 save to right 右移
const int Stop = 0;        //Parking variable 停止
const int L_turn = 198;    //turn left 左转
const int R_turn = 57;    //turn right 右转

//电机速度变量 1 and 255,越大速度越快
int Speed1 = 180;
int Speed2 = 180;
int Speed3 = 180;
int Speed4 = 180;

//其他变量
char cmd; 

4.2 初始设置

设置波特率9600用来调试,再设置引脚为输出

void setup() 
{
    Serial.begin(9600); //Set the serial port baud rate 9600
    
    //Configure as output mode
    pinMode(DIR_CLK,OUTPUT);
    pinMode(DATA,OUTPUT);
    pinMode(DIR_EN,OUTPUT);
    pinMode(DIR_LATCH,OUTPUT);
    pinMode(PWM0B,OUTPUT);
    pinMode(PWM0A,OUTPUT);
    pinMode(PWM2A,OUTPUT);
    pinMode(PWM2B,OUTPUT);
}

4.3 主程序部分

void loop()
{
    control_func();                   //Call the Bluetooth car control function
    // Motor(mytest,Speed1,Speed1,Speed1,Speed1);                   //test
}

void control_func()
{
    if(Serial.available() > 0)      //判断串口是否有接收到蓝牙发来的数据
    {   
        serialData = Serial.read(); //将数据保存到变量
        
        if     ('F' == serialData )  cmd = 'F'; //如果接收到字符 F, 将 F 保存到变量cmd
        else if('B' == serialData )  cmd = 'B';   
        else if('L' == serialData )  cmd = 'L';    
        else if('Y' == serialData )  cmd = 'Y';  
        else if('S' == serialData )  cmd = 'S';   
        else if('C' == serialData )  cmd = 'C';
        else if('D' == serialData )  cmd = 'D';
        else if( serialData == '+' && Speed1 < 245) //接收到字符“+”,速度就增加 
        {
            Speed1 += 10;                           //每次加10
            Speed2 = Speed1;
            Speed3 = Speed1;
            Speed4 = Speed1;
        }
        else if( serialData == '-' && Speed1 > 30)
        {
            Speed1 -= 10;   
            Speed2 = Speed1;
            Speed3 = Speed1;
            Speed4 = Speed1;
        }
        // Serial.println(serialData);
    }
    
    //变量cmd确实为“F”字符,证明遥控那边按下按钮发送了字符过来,这时小车执行前进
    if('F' == cmd)   
    {      
       Motor(Forward,Speed1,Speed2,Speed3,Speed4); //调用电机控制函数,执行Forward前进
    }
    else if('B' == cmd)     
    {   
        Motor(Back,Speed1,Speed2,Speed3,Speed4);//后退
    }
    else if('L' == cmd)    
    {              
        Motor(Left,Speed1,Speed2,Speed3,Speed4); //左移
    }
    else if('Y' == cmd)     
    {
        Motor(Right,Speed1,Speed2,Speed3,Speed4);      //右移
    }
    else if('S' == cmd)      
    {
        Motor(Stop,0,0,0,0);                                        //停止
    }
    else if('C' == cmd)     
    {
        Motor(L_turn,Speed1,Speed2,Speed3,Speed4);      //左转   
    }
    else if('D' == cmd)    
    {
        Motor(R_turn,Speed1,Speed2,Speed3,Speed4);      //右转  
    }
}

void Motor(int Dir,int Speed1,int Speed2,int Speed3,int Speed4)
{
    analogWrite(PWM2A,Speed1); //Motor PWM speed regulation
    analogWrite(PWM2B,Speed2); //Motor PWM speed regulation
    analogWrite(PWM0A,Speed3); //Motor PWM speed regulation
    analogWrite(PWM0B,Speed4); //Motor PWM speed regulation
    
    digitalWrite(DIR_LATCH,LOW); //DIR_LATCH 设置低电平
    
    shiftOut(DATA,DIR_CLK,MSBFIRST,Dir);//不同的Dir值对应不同运动状态
    
    digitalWrite(DIR_LATCH,HIGH);//设置高电平
}

至此已完成了所有代码,并不多,后面是相关的解析。

4.4代码解析

通过74HC595芯片控制各个电机旋转方向,该芯片对应的一个函数

shiftOut(DATA,DIR_CLK,MSBFIRST,Dir);

前三个参数设置时钟等,最后一个参数 Dir为一个10进制数,该数值由一个8位二进制数转换而来,不同的数值将影响汽车的移动状态

已知小车每个轮子各有“前进”和“后退”两种旋转状态,共有8种情况,每次控制小车移动时就需要控制轮子的旋转。一个8位二进制每一个“位”对应一个轮子状态,1为高电平起作用,0为低电平不起作用

以前进“Forward”变量为例,设置变量值为216(换成8位二进制为1101 1000),也就是从左到右第1/2/4/5位高电平1起作用,相应地在扩展板中(如下图)控制电机端口M3-A、M4-A、M2-B、M1-B为高电平,这时候对应接到该端口的电机就旋转起来。可以看出来,如果同一个电机A和B互换,轮子就会反转,并且A和B不能同时高电平(同时高电平意味着同时存在正转和反转,这是不可能的),否则电机不转,那么8位二进制就只能其中4个为1,另4个为0。

在这里插入图片描述
测试获取每种运动状态对应的编码值

我们如何知道8位二进制哪些“位”为1呢,可以通过以下方式测试而来:

新定义一个变量mytest并赋值1(转换8位二进制为0000 0001)

const int mytest = 1;

在loop()中再添加一条代码调用函数Motor(测试完成后记得删除)语句,然后观察电机旋转情况。

void loop()
{
  control_func();
  Motor(mytest,Speed1,Speed1,Speed1,Speed1);  //新加的测试,改变mytest变量测试轮子运动
}

当mytest=1,烧录代码后可以看到只有一个电机在旋转,就代表0000 0001为该电机该旋转方向的编码。

如下图所示,当设置变量为2(二进制为0000 0010),代表另一个电机另一种旋转状态。当设置变量为4(二进制为0000 0100)又代表另一个电机另一种旋转状态。将八位2进制逐位给1来测出4个电机正反2种旋转方式共8种状态对应的编码。

总结数据记录,想要汽车前进就要让四个电机保持往前旋转状态,也就是1101 1000,转换成十进制为216.最后得出所有运动状态的所有对应编码。特别地,控制同一个电机的电位不能同时为1(高电平),这样会导致失效。

对应的编码表如下图:
在这里插入图片描述
正如前面所述,小车左移时四个轮子的旋转方向是有要求的,就是右前轮前进,右后轮后退、左后轮前进和左前轮后退,所以对应01110100,每一个1代表该位为高电平,0代表低电平,换成十进制116。
在这里插入图片描述

将最右边一列的数值传入函数shifOut的变量Dir,即可得到不同运动状态。

蓝牙遥控部分
重点是要做判断成功接收蓝牙信息(串口接收大于0),并保存到变量serialData ,然后利用serialData 做字符判断即可。

    if(Serial.available() > 0)     
    {   
        serialData = Serial.read(); //Receiving function
  • 8
    点赞
  • 39
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
以下是使用74HC595扩展io口和A4988驱动来控制8个步进电机的Arduino接线步骤和代码: 接线步骤: 1. 将Arduino的GND连接到74HC595和A4988的GND引脚。 2. 将Arduino的5V引脚连接到74HC595和A4988的VCC引脚。 3. 将Arduino的数字引脚2、3和4分别连接到74HC595的SER、SRCLK和RCLK引脚。 4. 将Arduino的数字引脚5连接到A4988的STEP引脚。 5. 将Arduino的数字引脚6连接到A4988的DIR引脚。 6. 将Arduino的数字引脚7连接到A4988的ENABLE引脚。 7. 将A4988的MS1、MS2和MS3引脚分别连接到74HC595的Q0、Q1和Q2引脚,用于设置步进电机的分辨率。 8. 将A4988的STEP、DIR和ENABLE引脚分别连接到8个步进电机。 代码: ``` #include <SPI.h> const int SER_Pin = 2; // 74HC595的SER引脚连接到Arduino的数字引脚2 const int SRCLK_Pin = 3; // 74HC595的SRCLK引脚连接到Arduino的数字引脚3 const int RCLK_Pin = 4; // 74HC595的RCLK引脚连接到Arduino的数字引脚4 const int STEP_Pin = 5; // A4988的STEP引脚连接到Arduino的数字引脚5 const int DIR_Pin = 6; // A4988的DIR引脚连接到Arduino的数字引脚6 const int ENABLE_Pin = 7; // A4988的ENABLE引脚连接到Arduino的数字引脚7 int numOutputs = 8; // 74HC595输出引脚数量 byte outputs = 0; // 74HC595输出状态 void setup() { SPI.begin(); // 初始化SPI通讯 pinMode(SER_Pin, OUTPUT); pinMode(SRCLK_Pin, OUTPUT); pinMode(RCLK_Pin, OUTPUT); pinMode(STEP_Pin, OUTPUT); pinMode(DIR_Pin, OUTPUT); pinMode(ENABLE_Pin, OUTPUT); digitalWrite(DIR_Pin, HIGH); // 设置步进电机的旋转方向 digitalWrite(ENABLE_Pin, LOW); // 启用A4988驱动器 } void loop() { outputs = 0; // 清除74HC595输出状态 // 设置步进电机的分辨率 byte resolution = 0b000; // 1/1分辨率 outputs |= (resolution << 0); // 设置MS1引脚的值 outputs |= (resolution << 1); // 设置MS2引脚的值 outputs |= (resolution << 2); // 设置MS3引脚的值 // 设置步进电机的步进角度 int stepsPerRevolution = 200; int steps = stepsPerRevolution / 4; // 步进角度为90度 for (int i = 0; i < steps; i++) { // 通过74HC595设置MS1、MS2和MS3引脚的值 SPI.transfer(outputs); digitalWrite(SRCLK_Pin, HIGH); digitalWrite(RCLK_Pin, HIGH); digitalWrite(RCLK_Pin, LOW); digitalWrite(SRCLK_Pin, LOW); digitalWrite(STEP_Pin, HIGH); // 向步进电机发送一个脉冲信号 delayMicroseconds(500); // 等待一段时间 digitalWrite(STEP_Pin, LOW); delayMicroseconds(500); } } ``` 这段代码会使8个步进电机旋转90度。你可以通过修改步进电机的分辨率和步进角度来控制它们的旋转。
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值