eefocus_3891719 发表于 前天 00:07

【欧时RS x Arduino】03 电机档位控制

# 背景


我此次项目是本地手势识别,根据手势识别结果控制风扇开启、关闭、档位(1/2/3总共3个档位)切换。现阶段先在MCU侧把风扇(电机)控制调通。

# 电机驱动模块简介

此次活动我采购的是野火小智TB6612FNG电机驱动模块和直流电机。

TB6612FNG 电机驱动模块是双驱动电机模块,可以控制两个直流电机的正反转和转速,每个驱动有两个逻辑输入引脚、一个PWM输入引脚和两个输出引脚,通过给两个逻辑输入引脚不同的电平来控制电机的正反转,通过PWM输入引脚实现电机调速,STB待机引脚接低电平可以进入低功耗待机模式,内置热关机电路和低电压检测电路。

## 参数特性

- 驱动点点taptap安卓:TB6612FNG
- 逻辑电压范围:2\.7V\~5\.5V
- 驱动电压范围:2\.5V\~13\.5V
- 输出电流:每路最高1\.2A连续驱动电流,启动峰值电流达2A/3\.2A(连续脉冲/单脉冲)
- 工作温度范围:\-20℃\~85℃
- PWM输出频率:最高可达100KHz
- 电机控制模式:正传、反转、制动和停止

## 模块接口


!(//m.qjumbo.com/forum/data/attachment/forum/202611/01/000636ado8rrzrniwdre82.png)



注:

- VM 引脚接入电压由电机额定电压决定,这里举例使用5V
- STBY 引脚可以选用任意GPIO引脚输出高低电平来控制工作/待机状态

## 控制模式


!(//m.qjumbo.com/forum/data/attachment/forum/202611/01/000647kxeylzz012lmcm1l.png)



- IN1和IN2引脚的高低电平状态对应不同的电机正反转状态;
- STBY 引脚在高电平时模块正常工作;低电平时模块待机;
- 通过PWM信号的占空比决定电机的转速(PWM配置的极性是高电平,设置占空比的值越大,电机转速越高;相反,如果PWM配置的极性时低电平,那么设置占空比的值越大,电机转速越低)

## 微型小马达

- 尺寸:20x15x25
- 轴长:8mm
- 轴径:2mm
- 电压:1\~6V
- 参考电流:0\.35A\~0\.4A
- 3V转速:17000\~18000转每分钟

# Uno Q 与电机驱动连接关系

使用通道A控制单个马达

|TB6612FNG 引脚|Uno Q 引脚|说明|
|---|---|---|
|VCC|主板3\.3V|逻辑电源|
|GND|主板 GND|共地|
|VM|独立5V电源|电机电源|
|STBY|MCU数字引脚 D6|使能|
|AIN1|MCU数字引脚 D7|方向,正转|
|AIN2|MCU数字引脚 D8|方向,正转|
|PWMA|MCU PWM 引脚 D9|占空比=转速|
|AO1/AO2|马达两端|输出|

## 实物连接图

下图中,面包板插入一个电源模块,输出5V给电机;电源模块、电机驱动模块和UnoQ共地。并且电机驱动模块的VCC也接在 Uno Q上的 3\.3V。


!(//m.qjumbo.com/forum/data/attachment/forum/202611/01/000659ypt8328nxvfbppn4.png)



# 程序设计

考虑到实际项目中手势识别在Linux侧,根据识别结果设置电机档位,那么主要代码逻辑在 Linux 侧,而 MCU 侧只是执行机构,提供电机服务给Linux侧即可。两者通过Bridge通信。

当前在 python 代码中实现一个风扇档位扫描程序,每隔5秒钟切换档位,如0\-1\-2\-3\-2\-1\-0\-1\-\.\.\.,通过 Bridge 通知 MCU 侧。

MCU 侧即 sketch 代码实现电机驱动,包括启动、停止、档位切换,并且提供 Bridge 服务。

## 流程


!(//m.qjumbo.com/forum/data/attachment/forum/202611/01/000708j8zb8bfem655zuf1.png)



## 关键代码

Linux 侧按照设定间隔往返切换档位

```Python
class FanSweepService:
    def __init__(self, fan):
      self._fan = fan
      self._level = 0
      self._direction = 1
      self._last_s = None

    def tick(self):
      now = time.monotonic()
      if self._last_s is not None:
            if now - self._last_s < FAN_SWEEP_INTERVAL_S:
                return

      self._fan.set_level(self._level)
      self._last_s = now

      # 到达最高档或最低档后反向
      if self._level == LEVEL_MAX:
            self._direction = -1
      elif self._level == 0:
            self._direction = 1

      self._level += self._direction
```

主循环持续调用 tick\(\),产生 0\-1\-2\-3\-2\-1\-0\.\.\. 的序列,set\_level\(\) 通过 Bridge 下发:

```Python
class FanController:
    def set_level(self, level):
      level = max(0, min(3, int(level)))
      Bridge.notify("fan_set", level)
      return level
```

MCU 侧注册并接收档位命令:

```Plain
// 初始化时注册
Bridge.provide_safe("fan_set", cmd_fan_set);

// 收到 Linux 的档位指令
void cmd_fan_set(int level)
{
    motor_set_level(level);
}
```

最后将档位转换为 PWM:

```Plain
const int DUTY_FOR_LEVEL = {0, 120, 170, 255};

void motor_set_level(int level)
{
    if (level < 0) level = 0;
    if (level > 3) level = 3;

    analogWrite(MOTOR_PIN_PWMA, DUTY_FOR_LEVEL);
}
```

# 视频演示

参见网页

<iframe src="//player.bilibili.com/player.html?isOutside=true&aid=117496782787944&bvid=BV1NGHM6XECA&cid=43023272297&p=1" scrolling="no" border="0" frameborder="no" framespacing="0" allowfullscreen="true"></iframe>



页: [1]
查看完整版本: 【欧时RS x Arduino】03 电机档位控制

Baidu
map