Skip to content

Commit

Permalink
RampUp for DC motor
Browse files Browse the repository at this point in the history
  • Loading branch information
ArminJo committed Sep 24, 2020
1 parent 0703e9b commit 3543dd8
Show file tree
Hide file tree
Showing 19 changed files with 618 additions and 456 deletions.
1 change: 1 addition & 0 deletions .github/workflows/LibraryBuild.yml
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ jobs:
-DUSE_STANDARD_SERIAL
-DUSE_US_SENSOR_1_PIN_MODE
-DDISTANCE_SERVO_IS_MOUNTED_HEAD_DOWN
-DENABLE_MOTOR_LIST_FUNCTIONS

# - arduino-boards-fqbn: arduino:avr:leonardo
# build-properties:
Expand Down
57 changes: 39 additions & 18 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ Available as Arduino library "PWMMotorControl"

[![License: GPL v3](https://img.shields.io/badge/License-GPLv3-blue.svg)](https://www.gnu.org/licenses/gpl-3.0)
[![Build Status](https://github.com/ArminJo/PWMMotorControl/workflows/LibraryBuild/badge.svg)](https://github.com/ArminJo/PWMMotorControl/actions)
[![Hit Counter](https://hitcounter.pythonanywhere.com/count/tag.svg?url=https%3A%2F%2Fgit.luolix.top%2FArminJo%2FPWMMotorControl)](https://github.com/brentvollebregt/hit-counter)
![Hit Counter](https://visitor-badge.laobi.icu/badge?page_id=ArminJo_PWMMotorControl)

- The PWMDcMotor.cpp controls **brushed DC motors** by PWM using standard full bridge IC's like **L298**, **TB6612** (new low loss dual full bridge IC), or **Adafruit_MotorShield** (using PCA9685 -> 2 x TB6612).
- The EncoderMotor.cpp.cpp controls a DC motor with attached encoder disc and fork light barrier to enable **driving a specified distance**.
Expand All @@ -23,44 +23,65 @@ Maximal speed is the PWM value to use for driving a fixed distance. For encoder
- `initGoDistanceCount(uint8_t Unsigned_DistanceCount,uint8_tDirection)` or `setSpeed(intSigned_DistanceCount)` - for non encoder motors a formula, using distance and the difference between minimal speed and maximal speed, is used to convert counts into motor driving time.
- `updateMotor()` - call this in your loop if you use the start* functions.

# Compile options for this library
# Compile options / macros for this library
To customize the library to different requirements, there are some compile options / makros available.<br/>
Modify it by commenting them out or in, or change the values if applicable. Or define the macro with the -D compiler option for gobal compile (the latter is not possible with the Arduino IDE, so consider to use [sloeber](https://eclipse.baeyens.it).
Some options which are enabed by default can be disabled also by defining a *inhibit* macro like `USE_STANDARD_LIBRARY_FOR_ADAFRUIT_MOTOR_SHIELD`.
To customize the library to different requirements, there are some compile options / macros available.<br/>
Modify it by commenting them out or in, or change the values if applicable. Or define the macro with the -D compiler option for gobal compile (the latter is not possible with the Arduino IDE, so consider to use [sloeber](https://eclipse.baeyens.it).<br/>
Some options which are enabed by default can be disabled by defining a *inhibit* macro like `USE_STANDARD_LIBRARY_FOR_ADAFRUIT_MOTOR_SHIELD`.

| Macro | Default | File | Disable macro | Description |
|-|-|-|-|-|
| `USE_ENCODER_MOTOR_CONTROL` | disabled | PWMDCMotor.h | | Use fork light barrier and an attached encoder disc to enable motor distance and speed sensing for closed loop control. |
| `USE_ADAFRUIT_MOTOR_SHIELD` | disabled | PWMDcMotor.h | | Use Adafruit Motor Shield v2 connected by I2C instead of simple TB6612 or L298 breakout board.<br/>
This disables tone output by using motor as loudspeaker, but requires only 2 I2C/TWI pins in contrast to the 6 pins used for the full bride.<br/>
For full bride, analogWrite the millis() timer0 is used since we use pin 5 & 6. |
| `USE_OWN_LIBRARY_FOR_ADAFRUIT_MOTOR_SHIELD` | enabled | PWMDcMotor.h | `USE_STANDARD_LIBRARY_FOR_ADAFRUIT_MOTOR_SHIELD` | Saves 694 bytes program memory |
| Macro | Default | File | Description |
|-|-|-|-|
| `USE_ENCODER_MOTOR_CONTROL` | disabled | PWMDCMotor.h | Use fork light barrier and an attached encoder disc to enable motor distance and speed sensing for closed loop control. |
| `USE_ADAFRUIT_MOTOR_SHIELD` | disabled | PWMDcMotor.h | Use Adafruit Motor Shield v2 connected by I2C instead of simple TB6612 or L298 breakout board.<br/>This disables tone output by using motor as loudspeaker, but requires only 2 I2C/TWI pins in contrast to the 6 pins used for the full bride.<br/>For full bride, analogWrite the millis() timer0 is used since we use pin 5 & 6. |
| `USE_OWN_LIBRARY_FOR_`<br/>`ADAFRUIT_MOTOR_SHIELD` | enabled | PWMDcMotor.h | Saves around 694 bytes program memory.<br/>Disable macro=`USE_STANDARD_LIBRARY_`<br/>`FOR_ADAFRUIT_MOTOR_SHIELD` |
| `SUPPORT_RAMP_UP` | enabled | PWMDcMotor.h | Saves around 300 bytes program memory.<br/>Disable macro=`DO_NOT_SUPPORT_RAMP_UP` |

# Default car geometry dependent values used in this library
These values are for a standard 2 WD car as can be seen on the pictures below.
| Macro | Default | File | Description |
|-|-|-|-|
| `DEFAULT_COUNTS_PER_FULL_ROTATION` | 40 | PWMDCMotor.h | This value is compatible with 20 slot encoder discs, giving 20 on and 20 off counts per full rotation. |
| `DEFAULT_MILLIMETER_PER_COUNT` | 5 | PWMDCMotor.h | At a circumference of around 20 cm (21.5 cm actual) this gives 5 mm per count. |
| `FACTOR_CENTIMETER_TO_`<br/>`COUNT_INTEGER_DEFAULT` | 2 | CarMotorControl.h | Exact value is 1.86, but integer saves program space and time. |
| `FACTOR_DEGREE_TO_COUNT_DEFAULT` | 0.4277777 for 2 wheel drive cars, 0.8 for 4 WD cars | CarMotorControl.h | Reflects the geometry of the standard 2 WD car sets. The 4 WD car value is estimated for slip on smooth surfaces. |

# Other default values for this library
These values are used by functions and the first 2 can be overwritten by set* functions.
| Macro | Default | File | Description |
|-|-|-|-|
| `DEFAULT_START_SPEED` | 45/150 for 7.4/6.0 volt supply | PWMDCMotor.h | START_SPEED is the speed PWM value at which car starts to move. |
| `DEFAULT_DRIVE_SPEED` | 80/255(max speed) for 7.4/6.0 volt supply | PWMDCMotor.h | The speed PWM value for going fixed distance. |
| `DEFAULT_DISTANCE_TO_TIME_FACTOR` | 135/300 for 7.4/6.0 volt supply | PWMDCMotor.h | The factor used to convert distance in 5mm steps to motor on time in milliseconds using the formula:<br/>`computedMillisOf`<br/>`MotorStopForDistance = 150 + (10 * ((aDistanceCount * DistanceToTimeFactor) / DriveSpeed))` |
| `RAMP_UP_UPDATE_INTERVAL_MILLIS` | 16 | PWMDCMotor.h | The smaller the value the steeper the ramp. |
| `RAMP_UP_UPDATE_INTERVAL_STEPS` | 16 | PWMDCMotor.h | Results in a ramp up time of 16 steps * 16 millis = 256 milliseconds. |

# Compile options for examples
To customize the Robot Car example to cover different extensions, there are some compile options available.

# Compile options for RobotCar example
To customize the RobotCar example to cover different extensions, there are some compile options available.
| Option | Default | File | Description |
|-|-|-|-|
| `USE_LAYOUT_FOR_NANO` | disabled | RobotCar.h | Use different pinout for Nano board. It has A6 and A7 available as pins. |
| `CAR_HAS_4_WHEELS` | disabled | RobotCar.h | Use modified formula for turning the car. |
| `USE_US_SENSOR_1_PIN_MODE` | disabled | RobotCar.h | Use modified HC-SR04 modules or HY-SRF05 ones.</br>Modify HC-SR04 by connecting 10kOhm between echo and trigger and then use only trigger pin. |
| `CAR_HAS_IR_DISTANCE_SENSOR` | disabled | RobotCar.h | Use Sharp GP2Y0A21YK / 1080 IR distance sensor. |
| `CAR_HAS_TOF_DISTANCE_SENSOR` | disabled | RobotCar.h | Use VL53L1X TimeOfFlight distance sensor. |
| `DISTANCE_SERVO_IS_MOUNTED_HEAD_DOWN` | disabled | Distance.h | The distance servo is mounted head down to detect even small obstacles. |
| `CAR_HAS_CAMERA` | disabled | RobotCar.h | Enables the `Camera` button for the `PIN_CAMERA_SUPPLY_CONTROL` pin. |
| `CAR_HAS_LASER` | disabled | RobotCar.h | Enables the `Laser` button for the `PIN_LASER_OUT` / `LED_BUILTIN` pin. |
| `CAR_HAS_PAN_SERVO` | disabled | RobotCar.h | Enables the pan slider for the `PanServo` at the `PIN_PAN_SERVO` pin. |
| `CAR_HAS_TILT_SERVO` | disabled | RobotCar.h | Enables the tilt slider for the `TiltServo` at the `PIN_TILT_SERVO` pin.. |
| `DISTANCE_SERVO_IS_MOUNTED_HEAD_DOWN` | disabled | Distance.h | The distance servo is mounted head down to detect small obstacles. |
| `MONITOR_LIPO_VOLTAGE` | disabled | RobotCar.h | Shows VIN voltage and monitors it for undervoltage. Requires 2 additional resistors at pin A2. |
| `VIN_VOLTAGE_CORRECTION` | undefined | RobotCar.h | Voltage to be subtracted from VIN voltage. E.g. if there is a series diode between LIPO and VIN set it to 0.8. |

#### If you find this library useful, please give it a star.

# Pictures
2 wheel car
2 wheel car with encoders, 2 LiPo batteries, Adafruit Motor Shield V2, Bluetooth connection, and servo mounted head down
![2 wheel car](https://github.com/ArminJo/Arduino-RobotCar/blob/master/pictures/2WheelDriveCar.jpg)
4 wheel car
4 wheel car, like 2 WD car before, but with servo mounted head up.
![4 wheel car](https://github.com/ArminJo/Arduino-RobotCar/blob/master/pictures/4WheelDriveCar.jpg)
Encoder fork sensor
![Encoder fork sensor](https://github.com/ArminJo/Arduino-RobotCar/blob/master/pictures/ForkSensor.jpg)
Servo mounting
Servo mounted head down
![Servo mounting](https://github.com/ArminJo/Arduino-RobotCar/blob/master/pictures/ServoAtTopBack.jpg)
VIN sensing
![VIN sensing](https://github.com/ArminJo/Arduino-RobotCar/blob/master/pictures/SensingVIn.jpg)
Expand Down
54 changes: 34 additions & 20 deletions examples/RobotCarBasic/RobotCar.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@

//#define CAR_HAS_4_WHEELS

//#define USE_LAYOUT_FOR_NANO

// Modify HC-SR04 by connecting 10kOhm between echo and trigger and then use only trigger.
//#define USE_US_SENSOR_1_PIN_MODE // Comment it out, if you use modified HC-SR04 modules or HY-SRF05 ones.

Expand Down Expand Up @@ -85,15 +87,16 @@ extern CarMotorControl RobotCarMotorControl;
* Pins 9 + 10 are reserved for Servo
* 2 + 3 are reserved for encoder input
*/
#define PIN_LEFT_MOTOR_FORWARD 4
#define PIN_LEFT_MOTOR_BACKWARD 7
#define PIN_LEFT_MOTOR_PWM 5 // Must be PWM capable
#define PIN_LEFT_MOTOR_FORWARD 12 // Pin 9 is already reserved for distance servo
#define PIN_LEFT_MOTOR_BACKWARD 8
#define PIN_LEFT_MOTOR_PWM 6 // Must be PWM capable

#define PIN_RIGHT_MOTOR_FORWARD 8
#define PIN_RIGHT_MOTOR_BACKWARD 12 // Pin 9 is already reserved for distance servo
#define PIN_RIGHT_MOTOR_PWM 6 // Must be PWM capable
#define PIN_RIGHT_MOTOR_FORWARD 4
#define PIN_RIGHT_MOTOR_BACKWARD 7
#define PIN_RIGHT_MOTOR_PWM 5 // Must be PWM capable
#endif


/*
* Servo pins
*/
Expand All @@ -115,31 +118,40 @@ extern CarMotorControl RobotCarMotorControl;
* Pins for US HC-SR04 distance sensor
*/
#define PIN_TRIGGER_OUT A0 // Connections on the Arduino Sensor Shield
#ifndef USE_US_SENSOR_1_PIN_MODE
#ifdef USE_US_SENSOR_1_PIN_MODE
#define PIN_IR_DISTANCE_SENSOR A1 // Otherwise available as US echo pin
#else
#define PIN_ECHO_IN A1 // used by Sharp IR distance sensor
#endif


#ifdef CAR_HAS_LASER
#define PIN_LASER_OUT LED_BUILTIN
#endif

/*
* Different pin layout for UNO and Nano (Nano hash full bridge) boards
* Different pin layout for UNO with Adafruit motor shield and Nano (Nano hash full bridge) boards
*/
#ifdef USE_ADAFRUIT_MOTOR_SHIELD
# ifdef USE_US_SENSOR_1_PIN_MODE
// Otherwise available as US echo pin
#define PIN_IR_DISTANCE_SENSOR A1
#ifdef USE_LAYOUT_FOR_NANO
/*
* Nano Layout
*/
# ifdef USE_ADAFRUIT_MOTOR_SHIELD
#error "Adafruit motor shield makes no sense for a Nano board!"
# endif
#define PIN_SPEAKER 11

#else // USE_ADAFRUIT_MOTOR_SHIELD
#ifdef CAR_HAS_CAMERA
# ifdef CAR_HAS_CAMERA
#define PIN_CAMERA_SUPPLY_CONTROL A7 // Not available on UNO board
#endif
# endif
#define PIN_SPEAKER A6 // Not available on UNO board
#endif // USE_ADAFRUIT_MOTOR_SHIELD

#else
/*
* UNO Layout
*/
# ifdef CAR_HAS_CAMERA
#define PIN_CAMERA_SUPPLY_CONTROL 4
# endif
#define PIN_SPEAKER 11
#endif

/**************************
* End of pin definitions
Expand All @@ -151,6 +163,9 @@ extern CarMotorControl RobotCarMotorControl;
#define TIMOUT_AFTER_LAST_BD_COMMAND_MILLIS 240000L // move Servo after 4 Minutes of inactivity
#define TIMOUT_BEFORE_DEMO_MODE_STARTS_MILLIS 10000 // Start demo mode 10 seconds after boot up

//#define MOTOR_DEFAULT_SYNCHRONIZE_INTERVAL_MILLIS 500
#define MOTOR_DEFAULT_SYNCHRONIZE_INTERVAL_MILLIS 100

/*
* Servo timing correction.
* Values are for my SG90 servo. Servo is mounted head down, so values must be swapped!
Expand Down Expand Up @@ -191,7 +206,6 @@ extern float sVINVoltage;
void readVINVoltage();
#endif


void resetServos();
int doUserCollisionDetection();

Expand Down
9 changes: 3 additions & 6 deletions examples/RobotCarBlueDisplay/AutonomousDrive.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -575,7 +575,7 @@ void driveFollowerModeOneStep() {
RobotCarMotorControl.stopMotors();

clearPrintedForwardDistancesInfos();
// show current distance
// show current distance (as US distance), which triggers the rescan
showUSDistance(tCentimeter);

/*
Expand All @@ -594,7 +594,7 @@ void driveFollowerModeOneStep() {
}
for (uint8_t i = 0; i < 3; ++i) {
DistanceServoWriteAndDelay(tDegreeForSearch, true);
tCentimeter = getDistanceAsCentiMeter();
tCentimeter = getDistanceAsCentiMeter(false);
if (sCurrentPage == PAGE_AUTOMATIC_CONTROL && BlueDisplay1.isConnectionEstablished()) {
/*
* Determine color
Expand Down Expand Up @@ -669,17 +669,14 @@ void driveFollowerModeOneStep() {
// Serial.println(F("Stop"));
RobotCarMotorControl.stopMotors();
}

// show distance bars
showUSDistance(tCentimeter);
delayAndLoopGUI(40); // the IR sensor takes 39 ms for one measurement
}

unsigned int __attribute__((weak)) getDistanceAndPlayTone() {
/*
* Get distance; timeout is 1 meter
*/
unsigned int tCentimeter = getDistanceAsCentiMeter();
unsigned int tCentimeter = getDistanceAsCentiMeter(true);
/*
* play tone
*/
Expand Down
19 changes: 11 additions & 8 deletions examples/RobotCarBlueDisplay/Distance.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -284,38 +284,41 @@ void readAndShowDistancePeriodically(uint16_t aPeriodMillis) {
long tMillis = millis();
if (sLastUSMeasurementMillis + aPeriodMillis < tMillis) {
sLastUSMeasurementMillis = tMillis;
#ifdef CAR_HAS_IR_DISTANCE_SENSOR
showIRDistance(getIRDistanceAsCentimeter());
#elif CAR_HAS_TOF_DISTANCE_SENSOR
showIRDistance(getToFDistanceAsCentimeter());
#endif
// feedback as slider length
showUSDistance(getUSDistanceAsCentiMeterWithCentimeterTimeout(300));
getDistanceAsCentiMeter(true);
}
}
}

/*
* Timeout is DISTANCE_TIMEOUT_CM (1 meter)
*/
unsigned int getDistanceAsCentiMeter() {
unsigned int getDistanceAsCentiMeter(bool doShow) {
#ifdef CAR_HAS_TOF_DISTANCE_SENSOR
if (sScanMode != SCAN_MODE_US) {
sToFDistanceSensor.VL53L1X_StartRanging();
}
#endif

unsigned int tCentimeter = getUSDistanceAsCentiMeterWithCentimeterTimeout(DISTANCE_TIMEOUT_CM);
if (doShow) {
showUSDistance(tCentimeter);
}
#if defined(CAR_HAS_IR_DISTANCE_SENSOR) || defined(CAR_HAS_TOF_DISTANCE_SENSOR)
unsigned int tIRCentimeter;
if (sScanMode != SCAN_MODE_US) {
# if defined(CAR_HAS_IR_DISTANCE_SENSOR)
if (sScanMode != SCAN_MODE_US) {
tIRCentimeter = getIRDistanceAsCentimeter();
if (doShow) {
showIRDistance(tIRCentimeter);
}
}
# elif defined(CAR_HAS_TOF_DISTANCE_SENSOR)
if (sScanMode != SCAN_MODE_US) {
tIRCentimeter = readToFDistanceAsCentimeter();
if(doShow){
showIRDistance(tIRCentimeter);
}
}
# endif
if (sScanMode == SCAN_MODE_IR) {
Expand Down
7 changes: 6 additions & 1 deletion examples/RobotCarBlueDisplay/Distance.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,11 @@ extern Servo DistanceServo;
#define STEPS_PER_SCAN (NUMBER_OF_DISTANCES - 1) // -> 162 degrees for 18 DEGREES_PER_STEP, 153 for 17 degrees
#define START_DEGREES ((180 - (DEGREES_PER_STEP * STEPS_PER_SCAN)) / 2) // 9 for 18, 13,5 for 17 - we need it symmetrical in the 180 degrees range

// for future use maybe
//#define SERVO_CURRENT_LOW_THRESHOLD 100
//#define SERVO_INITIAL_DELAY 5
//#define SERVO_CURRENT_LOW_MILLIS_FOR_SERVO_STOPPED 12

/*
* Index definitions for ForwardDistancesInfoStruct
*/
Expand Down Expand Up @@ -69,7 +74,7 @@ extern int sLastDegreesTurned;

void initDistance();
void DistanceServoWriteAndDelay(uint8_t aValue, bool doDelay = false);
unsigned int getDistanceAsCentiMeter();
unsigned int getDistanceAsCentiMeter(bool doShow = false);
bool fillAndShowForwardDistancesInfo(bool aDoFirstValue, bool aForceScan = false);
void postProcessDistances();

Expand Down
6 changes: 6 additions & 0 deletions examples/RobotCarBlueDisplay/HomePage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,8 @@ void drawHomePage(void) {
TouchButtonDirection.drawButton();
#ifdef USE_ENCODER_MOTOR_CONTROL
TouchButtonCalibrate.drawButton();
#else
TouchButtonCompensation.drawButton();
#endif

SliderUSPosition.setValueAndDrawBar(sLastServoAngleInDegrees);
Expand Down Expand Up @@ -168,6 +170,8 @@ void startHomePage(void) {
TouchButtonDirection.setPosition(BUTTON_WIDTH_8_POS_4, BUTTON_HEIGHT_8_LINE_4);
#ifdef USE_ENCODER_MOTOR_CONTROL
TouchButtonCalibrate.setPosition(BUTTON_WIDTH_8_POS_5, BUTTON_HEIGHT_8_LINE_4);
#else
TouchButtonCompensation.setPosition(BUTTON_WIDTH_8_POS_5, BUTTON_HEIGHT_8_LINE_4);
#endif
TouchButtonNextPage.setCaption(F("Automatic\nControl"));

Expand All @@ -181,6 +185,8 @@ void stopHomePage(void) {
TouchButtonDirection.setPosition(BUTTON_WIDTH_8_POS_6, BUTTON_HEIGHT_8_LINE_5);
#ifdef USE_ENCODER_MOTOR_CONTROL
TouchButtonCalibrate.setPosition(BUTTON_WIDTH_8_POS_6, BUTTON_HEIGHT_8_LINE_2);
#else
TouchButtonCompensation.setPosition(BUTTON_WIDTH_8_POS_6, BUTTON_HEIGHT_8_LINE_2);
#endif
startStopRobotCar(false);
}
Expand Down
Loading

0 comments on commit 3543dd8

Please sign in to comment.