Part 3: Motor Control Programming - Raspberry Pi Pico W Robotics Course

Part 3: Motor Control Programming

Welcome to Part 3 of the Raspberry Pi Pico W Robotics Course! In this section, we’ll write Python code to control the robot’s motors using the L298N motor driver. By the end, your robot will be able to move forward, backward, left, and right.

What You’ll Do in Part 3

In this part, we’ll focus on programming the robot’s movement. Here’s what you’ll accomplish:

  • Write Python code to control the motors using the L298N motor driver.
  • Test basic movements: forward, backward, left, and right.
  • Use Pulse Width Modulation (PWM) to control motor speed.

Let’s get started!

Step 1: Understanding the L298N Motor Driver

The L298N motor driver allows you to control two DC motors independently. It uses four input pins (IN1, IN2, IN3, IN4) to control the direction of the motors and enable pins (ENA, ENB) to control their speed using PWM.

Here’s how the motor driver works:

  • IN1 and IN2: Control Motor A (e.g., forward or backward).
  • IN3 and IN4: Control Motor B (e.g., forward or backward).
  • ENA and ENB: Enable pins for Motor A and Motor B, respectively. These pins accept PWM signals to control speed.

Refer to the motor driver’s datasheet or pinout diagram for more details.

Step 2: Writing the Motor Control Code

Now, let’s write the Python code to control the motors. Open Thonny and create a new Python file. Use the following code as a starting point:


"""
This program controls two DC motors using PWM on a Raspberry Pi Pico. 
It allows the user to set a speed (0-100%) and moves the motors forward, backward, 
left, and right in a loop. If the motors move in the wrong direction, 
reverse their polarity by swapping the connections on the respective DC motor.
"""


from machine import Pin, PWM
from time import sleep

# ───── Helper function to convert 0–100% into duty_u16 value (0–65535) ─────
def percent_to_duty(percentage):
    # Clamp the percentage between 0 and 100
    if percentage < 0:
        percentage = 0
    elif percentage > 100:
        percentage = 100
    return int((65535 * percentage) / 100)

# ───── MOTOR B (Existing) ─────
in3 = Pin(2, Pin.OUT)   # GPIO2
in4 = Pin(3, Pin.OUT)   # GPIO3
enb = PWM(Pin(9))       # GPIO9 for PWM
enb.freq(1000)          # Set PWM frequency to 1 kHz (reduces audible noise, balances efficiency)

def motorB_forward(duty):
    in3.high()
    in4.low()
    enb.duty_u16(duty)

def motorB_backward(duty):
    in3.low()
    in4.high()
    enb.duty_u16(duty)

def motorB_stop():
    in3.low()
    in4.low()
    enb.duty_u16(0)

# ───── MOTOR A (New) ─────
in1 = Pin(0, Pin.OUT)   # GPIO0
in2 = Pin(1, Pin.OUT)   # GPIO1
ena = PWM(Pin(8))       # GPIO8 for PWM
ena.freq(1000)          # Set PWM frequency to 1 kHz

def motorA_forward(duty):
    in1.high()
    in2.low()
    ena.duty_u16(duty)

def motorA_backward(duty):
    in1.low()
    in2.high()
    ena.duty_u16(duty)

def motorA_stop():
    in1.low()
    in2.low()
    ena.duty_u16(0)

# ───── MAIN LOOP ─────
try:
    while True:
        # Ask the user for a speed percentage
        user_input = input("Enter speed (0–100) for both motors (Ctrl-C to quit): ")
        if not user_input.isdigit():
            print("Please enter a valid integer between 0 and 100!")
            continue

        speed_percent = int(user_input)
        # Convert percentage to duty cycle (0–65535)
        duty_value = percent_to_duty(speed_percent)

        # 1. Move FORWARD at user-specified speed
        print(f"Moving both motors FORWARD at {speed_percent}%")
        motorA_forward(duty_value)
        motorB_forward(duty_value)
        sleep(2)

        # Stop motors
        print("Stopping motors...")
        motorA_stop()
        motorB_stop()
        sleep(1)

        # 2. Move BACKWARD at user-specified speed
        print(f"Moving both motors BACKWARD at {speed_percent}%")
        motorA_backward(duty_value)
        motorB_backward(duty_value)
        sleep(2)

        # Stop motors
        print("Stopping motors...")
        motorA_stop()
        motorB_stop()
        sleep(1)

        # 3. Turn LEFT
        #    (Motor A backward, Motor B forward)
        print(f"Turning LEFT at {speed_percent}%")
        motorA_backward(duty_value)
        motorB_forward(duty_value)
        sleep(2)

        # Stop motors
        print("Stopping motors...")
        motorA_stop()
        motorB_stop()
        sleep(1)

        # 4. Turn RIGHT
        #    (Motor A forward, Motor B backward)
        print(f"Turning RIGHT at {speed_percent}%")
        motorA_forward(duty_value)
        motorB_backward(duty_value)
        sleep(2)

        # Stop motors
        print("Stopping motors...")
        motorA_stop()
        motorB_stop()
        sleep(1)

except KeyboardInterrupt:
    motorA_stop()
    motorB_stop()
    print("\nProgram stopped by user.")
            

This code defines functions to move the robot forward, backward, left, and right. It also includes a stop() function to halt the motors. The ENA and ENB pins control the speed of the motors using PWM.

Step 3: Testing Motor Responsiveness

Upload the code to your Raspberry Pi Pico W and run it. Observe the robot’s movement:

  • Does it move forward and backward as expected?
  • Does it turn left and right smoothly?
  • Adjust the PWM values in the move_forward(), turn_left(), and other functions to fine-tune the speed.

If the robot doesn’t move as expected, double-check your wiring and GPIO pin assignments.

What’s Next?

Great job! Your robot can now move in all directions. In Part 4: Adding Obstacle Detection, we’ll integrate the HC-SR04 ultrasonic sensor to detect obstacles and make the robot autonomous. Stay tuned!

Create a free account to access full content.

All access to code and resources on ShillehTek.

Signup Now

Already a member? Sign In