Skip to content

Commit

Permalink
refactor: Optimize motor speeds via decay modes and PWM
Browse files Browse the repository at this point in the history
Also rewrite the DRV8833 driver.
  • Loading branch information
madskjeldgaard committed Jul 10, 2024
1 parent c679cda commit b563442
Show file tree
Hide file tree
Showing 4 changed files with 271 additions and 95 deletions.
26 changes: 26 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,32 @@ These midi notes are 60-63.

It also features a small auto sleep function which will activate the DRV8833's sleep mode when idle.

## Midi mapping

These are the midi messages expected by the device, and their effect.

In all note on messages, the velocity is mapped to the speed of the motor.

| midi message | motor | effect|
| --- | --- | --- |
| note on 48 | motor 1 a | reverse|
| note off 48 | motor 1 a | stop |
| note on 49 | motor 1 b | reverse|
| note off 49 | motor 1 b | stop |
| note on 50 | motor 2 a | reverse|
| note off 50 | motor 2 a | stop |
| note on 51 | motor 2 b | reverse|
| note off 51 | motor 2 b | stop |
| note on 60 | motor 1 a | forward|
| note off 60 | motor 1 a | stop |
| note on 61 | motor 1 b | forward|
| note off 61 | motor 1 b | stop |
| note on 62 | motor 2 a | forward|
| note off 62 | motor 2 a | stop |
| note on 63 | motor 2 b | forward|
| note off 63 | motor 2 b | stop |


## Dependencies

You need to have platformio installed to make use of this.
Expand Down
191 changes: 159 additions & 32 deletions include/DRV8833.h
Original file line number Diff line number Diff line change
@@ -1,28 +1,131 @@
/*
*
* This file represents a DRV8833 motor driver chip. The DRV8833 is a dual
* H-bridge motor driver that can drive two DC motors or one stepper motor.
*
* See the datasheet here:
* https://www.ti.com/lit/ds/symlink/drv8833.pdf
*
*
*/

#pragma once
#include <Arduino.h>

namespace motor {

// A simple arduino class to control a DRV8833 motor driver
class DRV8833Channel {
enum class DecayMode {
Slow = 0,
Fast = 1,
};

enum class Direction {
Forward,
Backward,
};

/**
* @class DRV8833_HBridge
* @brief One bridge of a DRV8833 motor driver chip. This repsentation of a
* bridge supports fast and slow decay modes.
*
*/
class DRV8833_HBridge {
public:
DRV8833Channel(uint8_t in1, uint8_t in2) : mIn1(in1), mIn2(in2) {
// Constructor
// in1 and in2 are the pins connected to the motor
// The default decay mode is slow
/**
* @brief Default constructor for the DRV8833_HBridge class. The default
* decay mode is slow.
*
* @param in1 pin1 of the motor driver bridge
* @param in2 pin2 of the motor driver bridge
*/
DRV8833_HBridge(uint8_t in1, uint8_t in2) : mIn1(in1), mIn2(in2) {
pinMode(in1, OUTPUT);
pinMode(in2, OUTPUT);
mDecayMode = DecayMode::Slow;
}

// The resolution of the PWM speed is 10 bits, so the speed can be between
// -1023 and 1023
void setSpeed(int16_t speed) {
if (speed > 0) {
/**
* @brief Constructor for the DRV8833_HBridge class. The decay mode can be
* specified.
*
* @param in1 pin1 of the motor driver bridge
* @param in2 pin2 of the motor driver bridge
* @param mode Decaymode of the motor driver bridge
*/
DRV8833_HBridge(uint8_t in1, uint8_t in2, DecayMode mode)
: mIn1(in1), mIn2(in2), mDecayMode(mode) {
pinMode(in1, OUTPUT);
pinMode(in2, OUTPUT);
}

analogWrite(mIn1, abs(speed));
digitalWrite(mIn2, LOW);
void setDecayMode(DecayMode mode) { mDecayMode = mode; }

/**
* @brief Set speed. This version of the method assumes the motor is moving in
* the forward direction.
*
* @param speed The speed of the motor. The speed is a value between 0 and
* 1023.
*/
void setSpeed(uint16_t speed) { setSpeed(speed, Direction::Forward); }

/**
* @brief Set speed and direction of the motor
*
* @param speed The speed of the motor. The speed is a value between 0 and
* 1023.
* @param dir The direction of the motor. Forward or Backwards.
*/
void setSpeed(uint16_t speed, Direction dir) {

switch (mDecayMode) {
case DecayMode::Fast:

switch (dir) {
case Direction::Forward:
digitalWrite(mIn1, speed);
analogWrite(mIn2, LOW);
break;
case Direction::Backward:
digitalWrite(mIn1, LOW);
analogWrite(mIn2, speed);
break;
}
break;
case DecayMode::Slow:

switch (dir) {
case Direction::Forward:

digitalWrite(mIn1, HIGH);
analogWrite(mIn2, speed);
break;
case Direction::Backward:
digitalWrite(mIn1, speed);
analogWrite(mIn2, HIGH);
break;
}

break;
}
}

/**
* @brief Set the speed and direction of the motor
*
* @param speed The speed of the motor, between -1023 and 1023. Positive
* values are forward, negative values are backward, and 0 is stopped.
*
*/
void setSpeedBipolar(int16_t speed) {
if (speed > 0) {
setSpeed(speed, Direction::Forward);
} else if (speed < 0) {
digitalWrite(mIn1, LOW);
analogWrite(mIn2, abs(speed));

setSpeed(speed, Direction::Backward);
} else {
stop();
}
Expand All @@ -35,44 +138,68 @@ class DRV8833Channel {

private:
uint8_t mIn1, mIn2;

DecayMode mDecayMode;
};

// Represents a two channel DRV8833 motor driver with sleep pin
class DRV8833
{
/**
* @class DRV8833
* @brief Represents a DRV8833 motor driver with two H-bridges and a sleep pin.
* Each H Bridge may be configured in a fast or slow decay mode.
*
* For more information about decay modes and their impact on performance, see
* this article:
* https://learn.adafruit.com/improve-brushed-dc-motor-performance/overview
*
*/
class DRV8833 {
public:
/**
* @brief Default constructor for the DRV8833 class. The default decay mode
* is slow.
*
* @param in1 Pin connected to AIN1 on the DRV8833
* @param in2 Pin connected to AIN2 on the DRV8833
* @param in3 Pin connected to BIN1 on the DRV8833
* @param in4 Pin connected to BIN2 on the DRV8833
* @param sleep Pin connected to SLEEP on the DRV8833
*/
DRV8833(uint8_t in1, uint8_t in2, uint8_t in3, uint8_t in4, uint8_t sleep)
: mChannelA(in1, in2), mChannelB(in3, in4), mSleep(sleep) {
: mBridgeA(in1, in2), mBridgeB(in3, in4), mSleep(sleep) {
pinMode(sleep, OUTPUT);
digitalWrite(sleep, HIGH);
}

void setSpeedA(int16_t speed) {
mChannelA.setSpeed(speed);
}

void setSpeedB(int16_t speed) {
mChannelB.setSpeed(speed);
/**
* @brief Constructor for the DRV8833 class. The decay mode can be specified.
*
* @param in1 Pin connected to AIN1 on the DRV8833
* @param in2 Pin connected to AIN2 on the DRV8833
* @param in3 Pin connected to BIN1 on the DRV8833
* @param in4 Pin connected to BIN2 on the DRV8833
* @param sleep Pin connected to SLEEP on the DRV8833
* @param mode Decay mode of the motor driver chip
*/
DRV8833(uint8_t in1, uint8_t in2, uint8_t in3, uint8_t in4, uint8_t sleep,
DecayMode mode)
: mBridgeA(in1, in2, mode), mBridgeB(in3, in4, mode), mSleep(sleep) {
pinMode(sleep, OUTPUT);
digitalWrite(sleep, HIGH);
}

void stopAll() {
mChannelA.stop();
mChannelB.stop();
mBridgeA.stop();
mBridgeB.stop();
}

void stopA () {
mChannelA.stop();
}

void stopB () {
mChannelB.stop();
}
auto &getBridgeA() { return mBridgeA; }
auto &getBridgeB() { return mBridgeB; }

void sleep() { digitalWrite(mSleep, LOW); }
void wake() { digitalWrite(mSleep, HIGH); }

private:
DRV8833Channel mChannelA, mChannelB;
DRV8833_HBridge mBridgeA, mBridgeB;
uint8_t mSleep;
};

Expand Down
3 changes: 3 additions & 0 deletions platformio.ini
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@
framework = arduino
build_unflags = -std=gnu++11
build_flags = -std=gnu++17 -fconcepts -DUSE_TINYUSB
check_tool = clangtidy
check_flags =
clangtidy: --checks=-*,cert-*,clang-analyzer-* --fix
lib_deps =
# USB support
Adafruit TinyUSB Library
Expand Down
Loading

0 comments on commit b563442

Please sign in to comment.