Introduction:
In this experiment, we will control a servo motor using the Raspberry Pi Pico microcontroller. The servo motor's position is determined by Pulse Width Modulation (PWM), where the duty cycle corresponds to specific angles. The experiment demonstrates how to rotate a servo motor between 0° and 180° using both MicroPython and Embedded C.
Scope:
The scope of this experiment includes understanding:
The basics of servo motor control using PWM.
Setting up a servo motor with the Raspberry Pi Pico.
Writing and executing control programs using MicroPython and Embedded C.
Understanding hardware and software connections.
This experiment will provide practical experience in PWM signal generation and motor control using embedded systems.
Prerequisite:
3.1. Hardware:
Pico microcontroller
Servo motor
Breadboard
Jumper wires
USB cable (to connect the computer)
3 .2. Software:
Thonny Software(For micro python)
MicroPython firmware installed on Raspberry Pi Pico
ubuntu Terminal(For embedded C)
CMake,Pico SDK,GNU Arm Embedded Toolchain,WSL.
Connection Details:
Servo Motor Connections:
Red (VCC): Connect to Pico 3.3V pin.
Brown (GND): Connect to Pico GND pin.
Orange (Signal/PWM): Connect to GPIO 15 on the Pico.
Raspberry Pi Pico Pin Layout:
3.3V: Supplies power to the servo.
GND: Common ground.
GPIO 15: Provides the PWM signal to the servo motor.

Working Principle:
Servo motors work by receiving PWM signals, where the width of the pulse determines the angle. A typical servo expects a pulse every 20ms, with the pulse width ranging from 1ms (0°) to 2ms (180°). The Raspberry Pi Pico generates PWM signals on the GPIO pin, with the PWM duty cycle mapped to control the motor's angle.
For example:
1ms pulse = 0°
1.5ms pulse = 90°
2ms pulse = 180°
Servo¶

A servo is generally composed of the following parts: case, shaft, gear system, potentiometer, DC motor, and embedded board.
It works like this: The microcontroller sends out PWM signals to the servo, and then the embedded board in the servo receives the signals through the signal pin and controls the motor inside to turn. As a result, the motor drives the gear system and then motivates the shaft after deceleration. The shaft and potentiometer of the servo are connected together. When the shaft rotates, it drives the potentiometer, so the potentiometer outputs a voltage signal to the embedded board. Then the board determines the direction and speed of rotation based on the current position, so it can stop exactly at the right position as defined and hold there.

The angle is determined by the duration of a pulse that is applied to the control wire. This is called Pulse width Modulation. The servo expects to see a pulse every 20 ms. The length of the pulse will determine how far the motor turns. For example, a 1.5ms pulse will make the motor turn to the 90 degree position (neutral position). When a pulse is sent to a servo that is less than 1.5 ms, the servo rotates to a position and holds its output shaft some number of degrees counterclockwise from the neutral point. When the pulse is wider than 1.5 ms the opposite occurs. The minimal width and the maximum width of pulse that will command the servo to turn to a valid position are functions of each servo. Generally the minimum pulse will be about 0.5 ms wide and the maximum pulse will be 2.5 ms wide.

Application code:
MicroPython:
from machine import Pin, PWM
from time import sleep
# Define servo pin and PWM settings
servo = PWM(Pin(15))
servo.freq(50) # 50Hz frequency for the servo motor
# Function to set servo angle
def set_servo_angle(angle):
duty = int(1000 + (angle / 180) * 8000) # 1000-9000 duty cycle
servo.duty_u16(duty)
while True:
# Sweep from 0 to 180 degrees
for angle in range(0, 181, 2):
set_servo_angle(angle)
sleep(0.2)
# Sweep back from 180 to 0 degrees
for angle in range(180, -1, -2):
set_servo_angle(angle)
sleep(0.2)
Embedded C:
#include "pico/stdlib.h"
#include "hardware/pwm.h"
// Define the GPIO pin for the servo motor
#define SERVO_PIN 15
// Function to map an angle (0 to 180) to a PWM duty cycle
uint16_t set_servo_angle(uint16_t angle) {
uint16_t min_duty = 1000; // 1ms pulse width
uint16_t max_duty = 9000; // 2ms pulse width
uint16_t duty = min_duty + (angle * (max_duty - min_duty) / 180);
return duty;
}
int main() {
// Initialize GPIO for PWM function
gpio_set_function(SERVO_PIN, GPIO_FUNC_PWM);
// Get PWM slice number for the given GPIO pin
uint slice_num = pwm_gpio_to_slice_num(SERVO_PIN);
// Set the PWM frequency to 50Hz
pwm_set_wrap(slice_num, 20000); // 20ms period, corresponding to 50Hz
// Enable the PWM slice
pwm_set_enabled(slice_num, true);
while (true) {
// Rotate from 0 to 180 degrees
for (uint16_t angle = 0; angle <= 180; angle += 2) {
uint16_t duty_cycle = set_servo_angle(angle);
pwm_set_chan_level(slice_num, PWM_CHAN_A, duty_cycle); // Set PWM duty cycle
sleep_ms(200); // 0.2 seconds delay
}
// Rotate back from 180 to 0 degrees
for (uint16_t angle = 180; angle > 0; angle -= 2) {
uint16_t duty_cycle = set_servo_angle(angle);
pwm_set_chan_level(slice_num, PWM_CHAN_A, duty_cycle); // Set PWM duty cycle
sleep_ms(200); // 0.2 seconds delay
}
}
}
Hardware Image:

Output:
The servo motor will continuously rotate between 0° and 180° in 2° increments, pausing for 0.2 seconds at each angle.
Video Demonstration:
Appendix:
Common CMakeLists:
cmake_minimum_required(VERSION 3.12)
# Pull in SDK (must be before project)
include(pico_sdk_import.cmake)
project(pico_experiments C CXX ASM)
set(CMAKE_C_STANDARD 11)
set(CMAKE_CXX_STANDARD 17)
if (PICO_SDK_VERSION_STRING VERSION_LESS "1.3.0")
message(FATAL_ERROR "Raspberry Pi Pico SDK version 1.3.0 (or later) required. Your version is ${PICO_SDK_VERSION_STRING}")
endif()
# Initialize the SDK
pico_sdk_init()
add_compile_options(-Wall
-Wno-format # int != int32_t as far as the compiler is concerned because gcc has int32_t as long int
-Wno-unused-function # we have some for the docs that arent called
)
if (CMAKE_C_COMPILER_ID STREQUAL "GNU")
add_compile_options(-Wno-maybe-uninitialized)
endif()
# Hardware-specific examples in subdirectories:
add_subdirectory(expt_10_LCD)
CMakeLists:
cmake_minimum_required(VERSION 3.13)
include(pico_sdk_import.cmake)
project(servo_motor)
pico_sdk_init()
add_executable(servo_motor
main.c
)
target_link_libraries(servo_motor pico_stdlib hardware_pwm)
pico_add_extra_outputs(servo_motor)
References:
These references provide comprehensive
| # | Topic | Date & time | Action |
|---|
0% Completed (0/1)