Available as Arduino library "PWMMotorControl"
Version 2.1.0 - work in progress
- The PWMDcMotor.cpp controls brushed DC motors by PWM using standard full bridge IC's like L298, SparkFun Motor Driver - Dual TB6612FNG, or Adafruit_MotorShield (using PCA9685 -> 2 x TB6612).
- The EncoderMotor.cpp.cpp controls a DC motor with attached encoder disc and slot-type photo interrupters to enable driving a specified distance.
- The CarPWMMotorControl.cpp controls 2 motors simultaneously like it is required for most Robot Cars.
- To compensate for different motor characteristics, each motor can have a positive compensation value, which is subtracted from the requested speed PWM if you use the
setSpeedPWMCompensation()
functions. For car control, only compensation of one motor is required.
- Direction / motor driver control. Can be FORWARD, BACKWARD, BRAKE (motor connections are shortened) or RELEASE (motor connections are high impedance).
- SpeedPWM which is ignored for BRAKE or RELEASE. Some functions allow a signed speedPWM parameter, which incudes the direction as sign (positive -> FORWARD).
init(uint8_t aForwardPin, uint8_t aBackwardPin, uint8_t aPWMPin)
.setSpeedPWM(uint8_t aRequestedSpeedPWM, uint8_t aRequestedDirection)
orsetSpeedPWM(int Signed_RequestedSpeedPWM)
.stop()
orsetSpeedPWM(0)
.startRampUp(uint8_t aRequestedDirection)
,goDistanceMillimeter(unsigned int aRequestedDistanceMillimeter, uint8_t aRequestedDirection);
,startGoDistanceMillimeter(int aRequestedDistanceMillimeter)
andupdateMotor()
.getSpeed()
,getAverageSpeed()
,getDistanceMillimeter()
andgetBrakingDistanceMillimeter()
for encoder motors or MPU6050 IMU equipped cars.
Drving speed PWM is the PWM value to use for driving a fixed distance. The software generates a ramp up from start PWM to driving speed PWM at the start of the movement and a ramp down to stop.
calibrate()
to automatically set start speed for encoder or IMU supported cars.startGoDistanceMillimeter(unsigned int aRequestedDistanceMillimeter, uint8_t aRequestedDirection)
orsetSpeedPWM(uint8_t aRequestedSpeedPWM, uint8_t aRequestedDirection)
- for non encoder motors a formula, using distance and the drive speed PWM, is used to convert counts into motor driving time.updateMotor()
orupdateMotors()
- call this in your loop if you use the start* functions.
2 wheel car from LAVFIN with 2 LiPo batteries case, and IR receiver, with wires in original length.
Arduino Plotter diagram of PWM, speed[rpm] and encoder count for USB 3.8 volt supply and a Mosfet bridge. Timebase is 50 ms per plotted value. Generated by the PrintMotorDiagram example.
Diagram of PWM, speed[rpm] and encoder count for 2 LiPo (7.5 volt) supply and a Mosfet bridge.
To customize the library to different requirements, there are some compile options / macros available.
Modify it by commenting them out or in, or change the values if applicable. Or define the macro with the -D compiler option for global compile (the latter is not possible with the Arduino IDE, so consider using Sloeber.
Some options which are enabled by default can be disabled by defining a inhibit macro like USE_STANDARD_LIBRARY_FOR_ADAFRUIT_MOTOR_SHIELD
.
Macro | Default | File | Description |
---|---|---|---|
USE_ENCODER_MOTOR_CONTROL |
disabled | PWMDCMotor.h | Use slot-type photo interrupter and an attached encoder disc to enable motor distance and speed sensing for closed loop control. |
USE_MPU6050_IMU |
disabled | CarIMUData.h | Use GY-521 MPU6050 breakout board connected by I2C for support of precise turning and speed / distance calibration. Connectors point to the rear. |
USE_ACCELERATOR_Y_FOR_SPEED |
undefined | CarIMUData.h | The y axis of the GY-521 MPU6050 breakout board points forward / backward, i.e. connectors are at the left / right side. |
USE_NEGATIVE_ACCELERATION_FOR_SPEED |
undefined | CarIMUData.h | The speed axis of the GY-521 MPU6050 breakout board points backward, i.e. connectors are at the front or right side. |
USE_ADAFRUIT_MOTOR_SHIELD |
disabled | PWMDcMotor.h | Use Adafruit Motor Shield v2 connected by I2C instead of simple TB6612 or L298 breakout board. 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 bridge. For full bridge, analogWrite the millis() timer0 is used since we use pin 5 & 6. |
USE_OWN_LIBRARY_FOR_ ADAFRUIT_MOTOR_SHIELD |
enabled | PWMDcMotor.h | Disable macro=USE_STANDARD_LIBRARY_ FOR_ADAFRUIT_MOTOR_SHIELD .Disabling savesaves around 694 bytes program memory. |
These values are for a standard 2 WD car as can be seen on the pictures below.
Macro | Default | File | Description |
---|---|---|---|
DEFAULT_CIRCUMFERENCE_MILLIMETER |
220 | PWMDCMotor.h | At a circumference of around 220 mm this gives 11 mm per count. |
ENCODER_COUNTS_PER_FULL_ROTATION |
20 | EncoderMotor.h | This value is for 20 slot encoder discs, giving 20 on and 20 off counts per full rotation. |
FACTOR_DEGREE_TO_MILLIMETER_DEFAULT |
2.2777 for 2 wheel drive cars, 5.0 for 4 WD cars | CarPWMMotorControl.h | Reflects the geometry of the standard 2 WD car sets. The 4 WD car value is estimated for slip on smooth surfaces. |
These values are used by functions and some can be overwritten by set* functions.
Macro | Default | File | Description |
---|---|---|---|
VIN_2_LIPO |
undefined | PWMDCMotor.h | If defined sets FULL_BRIDGE_INPUT_MILLIVOLT to 7400. |
VIN_1_LIPO |
undefined | PWMDCMotor.h | If defined sets FULL_BRIDGE_INPUT_MILLIVOLT to 3700. |
FULL_BRIDGE_INPUT_ MILLIVOLT |
6000 or 7400 if VIN_2_LIPO is defined |
PWMDCMotor.h | The supply voltage used for the full bridge. |
MOSFET_BRIDGE_USED |
undefined | PWMDCMotor.h | If defined sets FULL_BRIDGE_LOSS_MILLIVOLT to 0. |
FULL_BRIDGE_LOSS_ MILLIVOLT |
2000 or 0 if FULL_BRIDGE_LOSS_MILLIVOLT is defined |
PWMDCMotor.h | The internal voltage loss of the full bridge used, typically 2 volt for bipolar bridges like the L298. |
FULL_BRIDGE_OUTPUT_ MILLIVOLT |
(FULL_BRIDGE_INPUT_MILLIVOLT - FULL_BRIDGE_LOSS_MILLIVOLT) |
PWMDCMotor.h | The effective voltage available for the motor. |
DEFAULT_START_ MILLIVOLT |
1100 | PWMDCMotor.h | The DC Voltage at which the motor start to move / dead band voltage. |
DEFAULT_DRIVE_ MILLIVOLT |
2000 | PWMDCMotor.h | The derived DEFAULT_DRIVE_SPEED_PWM is the speed PWM value used for fixed distance driving. |
DEFAULT_MILLIMETER_ PER_SECOND |
320 | PWMDCMotor.h | Value at DEFAULT_DRIVE_MILLIVOLT motor supply. A factor used to convert distance to motor on time in milliseconds using the formula:computedMillisOf MotorStopForDistance = 150 + (10 * ((aRequestedDistanceCount * DistanceToTimeFactor) / DriveSpeedPWM)) |
First, use Sketch > Show Sketch Folder (Ctrl+K).
If you did not yet stored the example as your own sketch, then you are instantly in the right library folder.
Otherwise you have to navigate to the parallel libraries
folder and select the library you want to access.
In both cases the library files itself are located in the src
directory.
If you are using Sloeber as your IDE, you can easily define global symbols with Properties > Arduino > CompileOptions.
This library was tested with the bipolar full bridge IC L298 and the MOSFET IC MTB6612.
The L298 has a loss of around 2 volt, which the reason for the attached heat sink, the MTB6612 has almost no loss.
- PWM period is 600 µs for Adafruit Motor Shield V2 using PCA9685.
- PWM period is 1030 µs for using AnalogWrite on pin 5 + 6.
One motor starts with DriveSpeedPWM / 2 for one second, then runs 1 second with DriveSpeedPWM. After stopping the motor, it tries to run for one full rotation (resulting in a 90 degree turn for a 2WD car). Then the other motor runs the same cycle. For the next loop, the direction is switched to backwards.
4 times drive 40 cm, then 90 degree left turn. After the square, the car is turned by 180 degree and the direction is switched to backwards. Then the square starts again.
Prints PWM, distance and speed diagram of an encoder motor. The encoder is inverted at falling PWM slope to show the quadratic kind of encoder graph.
Diagram for car controlled by an MosFet bridge | Diagram for car controlled by an L298 bridge |
---|---|
![]() |
![]() |
Template for your RobotCar control. Currently implemented is: drive until distance too low, then stop, and turn random amount.
The car tries to hold a distance between 20 and 30 cm to an obstacle. The measured distance is converted to a pitch as an acoustic feedback.
The car tries to hold a distance between 20 and 30 cm to an target. If the target vanishes, the distance sensor scans for the vanished or a new target.
Enables autonomous driving of a 2 or 4 wheel car with an Arduino and a Adafruit Motor Shield V2.
To avoid obstacles a HC-SR04 Ultrasonic sensor mounted on a SG90 Servo continuously scans the environment.
Manual control is implemented by a GUI using a Bluetooth HC-05 Module and the BlueDisplay library.
Just overwrite the function doUserCollisionDetection() to test your own skill.
You may also overwrite the function fillAndShowForwardDistancesInfo(), if you use your own scanning method.
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. 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.. |
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. |
Connection schematic of the L298 board for the examples. If motor drives in opposite direction, you must flip the motor to L298 connections.
Connections on the Arduino and on the L298 board.
2 wheel car with encoders, slot-type photo interrupter, 2 LiPo batteries, Adafruit Motor Shield V2, HC-05 Bluetooth module, and servo mounted head down.
4 wheel car with servo mounted head up.
Encoder slot-type photo interrupter sensor
Servo mounted head down
VIN sensing
Start page
Test page
Automatic control page with detected wall at right
- Green bars are distances above 1 meter or above double distance of one ride per scan whichever is less.
- Red bars are distanced below the distance of one ride per scan -> collision during next "scan and ride" cycle if obstacle is ahead.
- Orange bars are the values between the 2 thresholds.
- The tiny white bars are the distances computed by the doWallDetection() function. They overlay the green (assumed timeout) values.
- The tiny black bar is the rotation chosen by doCollisionDetection() function.
- Renamed *.cpp to *.hpp.
- Added and renamed functions.
- Support of off the shelf smart cars.
- Added and renamed functions.
- Converted to voltage based formulas.
- Initial Arduino library version.