Back to Home

Lab 4: Motors and Open Loop Control

Week 4 | March 2026

1. Objective

The purpose of this lab is to change from manual to open loop control of the car. At the end of this lab, the car should be able to execute a pre-programmed series of moves using the Artemis board and two dual motor drivers.

2. Prelab

Battery Isolation Discussion

The Artemis microcontroller and the motor drivers are powered by separate batteries. DC motors pull high, sudden surges of current when starting or changing direction. If the motors and the microcontroller shared the same power source, these current spikes would cause severe voltage drops across the circuit, potentially browning out or resetting the Artemis. Separating the logic power (650mAh) from the motor power (850mAh) ensures the microcontroller remains stable while the motors draw the amperage they need.

My initial idea was to use slightly longer wires to proper setup the car and then route the cables underneath the motors but then later realised that we dont need to close the car top and hence could route the cable via the top itself. The IMU position is still being debated upon.

Wiring Diagram

To deliver enough current for the robot to be fast, the two inputs and outputs on each dual motor driver were parallel-coupled. This essentially uses two channels to drive each motor, allowing the delivery of twice the average current without overheating the chip.(I will mount and clean up the car better).

Parallel-Coupled Output Architecture

Artemis Nano
A15 ➔ AIN1/BIN1
A16 ➔ AIN2/BIN2
Dual Motor Driver
(Right Side)
AOUT1/BOUT1
AOUT2/BOUT2
Right Motor (A)
Artemis Nano
A14 ➔ AIN1/BIN1
A13 ➔ AIN2/BIN2
Dual Motor Driver
(Left Side)
AOUT1/BOUT1
AOUT2/BOUT2
Left Motor (B)
[+] 850mAh Batt ➔ Driver VIN [-] 850mAh Batt ➔ Driver GND [GND] Artemis ➔ Driver GND
Photo of the physical wired setup

Figure 1: Photo of the physical wired setup


3. Lab Tasks

Power Supply & PWM Testing

Before connecting the high-discharge Li-Ion battery, the parallel-coupled motor drivers were tested using an external power supply with a controllable current limit to make debugging easier. The supply was set to 3.7V (to simulate the battery) with a current limit of 1.0A.

An oscilloscope was used to verify the analogWrite() signals on the output pins of the motor driver to show that power could be regulated.

Oscilloscope showing the PWM square wave on the driver output

Figure 2: Oscilloscope showing the PWM square wave on the driver output

Video 1: Wheels spinning as expected

Calibration and Straight Line Testing

Getting the car to drive in a straight line for 2m/6ft required a calibration factor. The testing surface had a slight slope towards the end and featured a textured floor, which caused the car to wobble to the left and then back to the right, along with inconsistent rolling resistance.

The motors were found to be asymmetric. Motor B (Left) required more power to match the RPM of Motor A (Right). Initially, a baseline of Left: 60 / Right: 45 was tested, but the final straight-line movement was tuned to Left: 65 / Right: 40.

I understand using delay() results in a blocking operation, and when moving onto future labs I will use either millis() or state machines to test driving patterns. (This will become more relevant in the driving with turns demo, where a time duration is passed as an argument to a function call to perform a specific manoeuvre.)

Code Snippet: Calibrated Straight Line (driveForward)

const int motorB_In1 = 14; 
const int motorB_In2 = 13; 

const int motorA_In1 = 15; 
const int motorA_In2 = 16; 

int leftBasePWM = 65;   
int rightBasePWM = 40;  

void driveForward(int duration) {
  analogWrite(motorB_In1, leftBasePWM); 
  analogWrite(motorB_In2, 0);   
  
  analogWrite(motorA_In1, 0); 
  analogWrite(motorA_In2, rightBasePWM);   
  
  delay(duration);
}
Watch on YouTube (YouTube Short)

Video 2: Straight Trajectory Run 1

Video 3: Straight Trajectory Run 2

Open Loop Control: Sequence and Turns

For the final open-loop demonstration, the robot was programmed to execute untethered control with a sequence of straight drives and turns. Due to the textured floor, the static friction during an on-axis turn was higher.

To overcome this, a "kickstart" function was implemented. A high-power PWM burst of 150 was sent for 50 milliseconds to break static friction, immediately dropping to a sustaining PWM of 100 to complete the rotation smoothly.

Code Snippet: Turn Logic with Kickstart (turnRight)

int turnKickPWM = 150;    
int turnSustainPWM = 100; 
int turnPulseMs = 50;     

void turnRight(int duration) {
  analogWrite(motorB_In1, turnKickPWM); 
  analogWrite(motorB_In2, 0); 
  
  analogWrite(motorA_In1, turnKickPWM); 
  analogWrite(motorA_In2, 0); 
  
  delay(turnPulseMs); 

  analogWrite(motorB_In1, turnSustainPWM); 
  analogWrite(motorB_In2, 0);   
  
  analogWrite(motorA_In1, turnSustainPWM); 
  analogWrite(motorA_In2, 0);   
  
  delay(duration);
}
Watch on YouTube (YouTube Short)

Video 4: Executing open loop sequence with static friction break


4. Additional Tasks (5000-Level)

analogWrite Frequency Discussion

I considered what frequency analogWrite generates and if it is adequately fast for these motors. The SparkFun Artemis Nano utilizes the Apollo3 microcontroller. The Arduino core's analogWrite() function on this platform typically generates a PWM signal at around ~730 Hz.

Is ~730 Hz Adequate for Motors?

It depends heavily on the motor type:

Motor Type Recommended PWM Freq Is 730 Hz OK?
DC hobby motors 1 kHz – 20 kHz Marginal — may cause audible whine
Brushed DC (driver ICs) 5 kHz – 25 kHz No — too slow
Brushless/BLDC (ESCs) 50 Hz – 400 Hz Yes
Stepper (via PWM) Application dependent Often fine

Problems with low PWM frequency (~730 Hz) on DC motors:

  • Audible whining/buzzing: The motor coils vibrate at the switching frequency, which lands right in the human hearing range (~20 Hz – 20 kHz).
  • Cogging / jerky motion: The current has time to fully decay between pulses at low duty cycles, causing non-smooth rotation.
  • Increased heat: Occurs in MOSFETs/drivers due to slow transitions and incomplete switching.
  • Poor current regulation: The motor's inductance cannot smooth the current effectively at low frequencies.

Benefits of Manually Configuring Timers for Faster PWM

There are benefits to manually configuring the timers to generate a faster PWM signal. The Apollo3 features configurable CTIMER (Counter/Timer) peripherals. By directly configuring them to push the PWM into a much higher range (e.g., 20 kHz – 100 kHz), we gain several benefits:

  • Eliminate audible whine: Pushing the frequency above 20 kHz moves the switching noise outside the range of human hearing.
  • Smoother torque & lower ripple current: Higher frequency means the motor's inductance integrates the pulses into a nearly steady DC current.
  • Better low-speed control: Provides finer resolution at low duty cycles without stalling or jittering.
  • Driver IC compatibility: Many H-bridge chips have optimal efficiency ranges well above 730 Hz.
  • Reduced EMI issues: Counterintuitively, some higher-frequency configurations with proper filtering produce less radiated noise than low-frequency hard switching.

The Key Trade-off: Higher frequency equates to more switching losses in the FETs. Therefore, there is a practical upper limit of around 50–100 kHz for most motor driver setups before efficiency begins to degrade.

Lowest PWM Value and Speed

I experimentally figured out the lowest PWM value at which the robot starts moving and the lowest value to keep it running once in motion.

  • Breaking Static Friction: The lowest PWM value required to overcome static friction and get the robot moving from a complete rest was 35.
  • Sustaining Minimum Speed: Once the car was already in motion, the kinetic friction was lower than the static friction. It was possible to step the PWM value down to 30 and still have the robot settle and maintain its slowest possible forward crawl without stalling.