Lab 4: Motor Drivers & PWM Calibration
This lab focuses on wiring and testing a dual H-bridge motor driver with the Artemis, verifying PWM output
with an oscilloscope, measuring start vs keep-running PWM thresholds, and documenting open-loop driving.
I also discuss the PWM frequency created by analogWrite() and when higher PWM frequencies might help.
1. Prelab
Wiring Diagram: Motor Driver, Artemis & Battery)
Down below is my completed wiring diagram showing how I connected the dual H-bridge motor driver to the Artemis, the battery and the motors.
Artemis Control Pins
The pins I will use for motor control on the Artemis are:
- Left motor: A0 and A1
- Right motor: A2 and A5
I chose these pins because they support PWM (pulse width modulation), which lets me change the duty cycle and control motor speed.
Battery Discussion
We power the Artemis and the motor drivers/motors from separate batteries for two main reasons:
- Power limitations: the battery we have is about 3.7 V, which is not ideal to run all electronics together, especially when motors draw current and cause voltage droop.
- Noise isolation: motors and drivers introduce switching noise and current spikes. If the Artemis shares the same supply, sensitive measurement electronics can show more noise and errors. Separate supplies improve reliability.
2. Lab Tasks
PWM Setup Photo: Power Supply & Oscilloscope
Below is a photo of my set up showing the one soldered motor driver hooked up to a power supply of 3.7 V and a oscilloscope to identify the PWM signal.
Power Supply Settings Discussion
A reasonable motor supply setting is 3.7 V, which matches the battery voltage we were given. The dual H-bridge motor driver supports a motor supply voltage range of 2.7 V to 10.8 V, so other values in that range can work as long as they stay within safe operating limits for the system.
Oscilloscope PWM Capture
Using this code I was able to capture the behavior of the PWM signal on the oscilloscope.
Below is the code snippet used to test the motor drivers using PWM output from analogWrite().
Code Snippet (Motor Driver PWM Test)
#define PWM_0 A0
#define PWM_1 A1
void setup() {
pinMode(PWM_0, OUTPUT);
pinMode(PWM_1, OUTPUT);
}
void loop(){
for (int i = 0; i < 255; i++) {
analogWrite(0,255-i)
analogWrite(1,0);
delay(10);
}
}
analogWrite() Motor Test Code
Below is the code snippet used to test the motors on the robotusing PWM output from analogWrite().
Code Snippet (Motor Driver PWM Test)
#define PWM_0 A0 // backward motor 1
#define PWM_1 A1 // forward motor 1
#define PWM_2 A2 // forward motor 2
#define PWM_5 A5 // backward motor 2
void setup() {
pinMode(PWM_0, OUTPUT); pinMode(PWM_1, OUTPUT);
pinMode(PWM_2, OUTPUT); pinMode(PWM_5, OUTPUT);
}
void loop() {
drive_forward(65, 3000); stop_motors(1000);
drive_backward(65, 3000); stop_motors(3000);
}
void drive_forward(int duty1, int sec) {
float cali = 1.3; int duty2 = (int)(duty1 * cali);
analogWrite(PWM_0, 0); analogWrite(PWM_1, duty1); // Drive left motor clockwise:
analogWrite(PWM_2, duty2); analogWrite(PWM_5, 0); // Drive right motor clockwise:
delay(sec);
}
void drive_backward(int duty1, int sec) {
float cali = 1.3; int duty2 = (int)(duty1 * cali);
analogWrite(PWM_0, duty1); analogWrite(PWM_1, 0); // Drive left motor counter clockwise:
analogWrite(PWM_2, 0); analogWrite(PWM_5, duty2); // Drive right motor counter clockwise:
delay(sec);
}
void stop_motors(int sec) {
analogWrite(PWM_0, 0); analogWrite(PWM_1, 0);
analogWrite(PWM_2, 0); analogWrite(PWM_5, 0);
delay(sec);
}
Videos
- Short video of one wheel spinning.
- Short video of both wheels spinning with the battery driving the motor drivers.
Single Motor
Both Motors
Robot Assembly Photo
Here is a picture of all the components assembled on to the inside of the robot.
3. Lower Limit PWM Values & Calibration
Lower Limit PWM Values (Start Moving)
I determined the lowest PWM values where the robot could reliably start moving forward and perform on-axis turns.
Start-Motion Results
- Forward (minimum to start): Left motor PWM ≈ 60. Using a calibration constant of 1.3, the right motor PWM was ≈ 80.
- Turning (minimum to start): Turn left ≈ 150, turn right ≈ 150.
How I Found These Values
I started at a PWM where the wheels ran under the robot’s own weight, then decreased the PWM until the robot barely moved. I then went one step further to find where the motors could not overcome initial torque (static friction).
Calibration Demonstration
I have videos of the robot moving straight along a table and spining. The calibration constant identified was 1.3 is incorporated in the code snippet above.
Calibration Discussion
One difficulty was that one wheel had a larger initial torque to overcome than the other. This made it hard to keep the robot moving straight at low PWM because one wheel could lag or briefly stop while the other kept moving. My solution was to increase the PWM signal and to recharge the battery so the weaker motor could more consistently overcome static friction and have the extra power to back it up.
Robot before Calibration
Robot moving in straight-line after calibration.
Robot making on-axis turn after calibration.
4. PWM Frequency
analogWrite() PWM Frequency
The PWM frequency produced by analogWrite() is displayed in my oscillioscope readings and is 183.1 Hz.
This is set by the microcontroller timers and is typically in the hundreds of Hz to 1 kHz range.
For the small DC motors driven through an H-bridge, this is decently fast as most boards have a default frequency of 490 Hz.
Would Faster PWM Help?
Manually configuring timers to generate a faster PWM signal could provide benefits such as:
- Less audible whining (PWM above human hearing)
- Smoother low-speed motion (reduced torque ripple)
- Potentially cleaner sensor readings (less low-frequency switching noise coupling into measurements)
Lowest PWM Value to Run Robot
Procedure
- In loop() function start the robot with a decently low PWM value that you know will get the robot out of static friction.
- After motion begins, drop to a lower PWM value and evaluate how it performs.
- Decrease the keep-running PWM until the robot stalls, then record the lowest stable value.
- Repeat for forward motion and on-axis turns.
Lowest PWM for Forward Motion
Lowest PWM for On-Axis Turn
Results
- Forward (minimum to start): Both Motors PWM ≈ 40.
- Turning (minimum to start): Turn left ≈ 140, turn right ≈ 140.
In both the forward moving and the on-axis turn cases, I identified a decrease in PWM of 10.
5. Open Loop Code and Video
Below is my open-loop driving code and a video demonstrating.
Open Loop Code
#define PWM_0 A0 // backward motor 1
#define PWM_1 A1 // forward motor 1
#define PWM_2 A2 // forward motor 2
#define PWM_5 A5 // backward motor 2
void setup() {
pinMode(PWM_0, OUTPUT); pinMode(PWM_1, OUTPUT);
pinMode(PWM_2, OUTPUT); pinMode(PWM_5, OUTPUT);
}
void loop() {
drive_forward(65, 3000); stop_motors(1000);
drive_backward(65, 3000); stop_motors(3000);
turn_right(65, 3000); stop_motors(3000);
turn_left(65, 3000); stop_motors(3000);
}
void drive_forward(int duty1, int sec) {
float cali = 1.3; int duty2 = (int)(duty1 * cali);
analogWrite(PWM_0, 0); analogWrite(PWM_1, duty1); // Drive left motor clockwise:
analogWrite(PWM_2, duty2); analogWrite(PWM_5, 0); // Drive right motor clockwise:
delay(sec);
}
void drive_backward(int duty1, int sec) {
float cali = 1.3; int duty2 = (int)(duty1 * cali);
analogWrite(PWM_0, duty1); analogWrite(PWM_1, 0); // Drive left motor counter clockwise:
analogWrite(PWM_2, 0); analogWrite(PWM_5, duty2); // Drive right motor counter clockwise:
delay(sec);
}
void turn_right(int duty1, int sec) {
float cali = 1.3; int duty2 = (int)(duty1 * cali);
analogWrite(PWM_0, duty1); analogWrite(PWM_1, 0); // Left motor backward
analogWrite(PWM_2, duty2); analogWrite(PWM_5, 0); //right motor forward
delay(sec);
}
void turn_left(int duty1, int sec) {
float cali = 1.3; int duty2 = (int)(duty1 * cali);
analogWrite(PWM_0, 0); analogWrite(PWM_1, duty1); // Left motor forward
analogWrite(PWM_2, 0); analogWrite(PWM_5, duty2); //right motor backward
delay(sec);
}
void stop_motors(int sec) {
analogWrite(PWM_0, 0); analogWrite(PWM_1, 0);
analogWrite(PWM_2, 0); analogWrite(PWM_5, 0);
delay(sec);
}
Open Loop Video
6. Resources
Datasheet (Dual H-Bridge)
Used for verifying acceptable motor supply voltage range and driver behavior.
Oscilloscope
Used to verify PWM duty cycle and observe PWM waveform characteristics.
Student Pages
Used Kotey Ashie's and Becky Lee's Spring 2025 lab pages to help with understanding the concepts and procedures for my Lab.
ChatGPT
Helped format the write-up into the same webpage structure and styling as my Lab 3 page.