In this part, we'll use the configured PWM from the previous part to sweep a servo motor through 180°.
Create a new project file pwm.rs
under examples
, copy the contents of the last part into it and empty the loop
section.
Table of contents
Requirements
- 1 x Raspberry Pico board
- 1 x USB Cable type 2.0
- 9 x M-M jumper wires
- 2 x Mini Breadboards
- 1 x SG90 Servo Motor
Implementation
Connections Diagram
The electrical connections of the modules will be as shown below.
Sweep
Duty cycle in the RP2040 is achieved by writing a value to the PWM
's counter compare register. This value is compared to the value we earlier fixed as the TOP wrap around value (50,000 in our case). The duty cycle can be thus compared:
.
We saw in the last part that the SG90 operates within a duty cycle range of 5 - 10% of a 50Hz PWM signal. With a TOP value of 50,000 this translates to a CC value range of 2500 - 5000.
However, this value seems to vary across suppliers. After testing I found my particular servo's range is 3 - 13%, translating to CC value of 1500 - 6500.
Applying these to a servo sweep of 0° to 180° and back.
Add the below example application code under loop
.
// Servo sweep trhough 180
for ccv in 1500..=6500 {
pwm2.cc().modify(|_, w| unsafe { w.a().bits(ccv) });
delay.delay_ms(1);
if ccv == 6500 {
delay.delay_ms(500);
for ccv in (1500..=6500).rev() {
pwm2.cc().modify(|_, w| unsafe { w.a().bits(ccv) });
delay.delay_ms(1);
}
}
delay.delay_ms(500);
❗ You may have to tweak the above values for your servo.
At this point it we shall have to add the Delay
function to our program. We begin by introducing its handle.
let mut delay = Delay::new(cp.SYST, 125_000_000);
Delay
is acquired from the cortex-m
crate:
use cortex_m::delay::Delay
❗ We shall comment away the
configure_compass
function call at the setup section of our code to allow the program to run without the compass being physically attached. Otherwise, the blocking writes ofI2C
we included earlier in the series will stop the code coming after from running.
Flashing the code thus far into the Pico should sweep the servo from 0° to 180° then 180° back to 0° every half a second.
We can refactor the above above application code into a function sweep
as below.
pub fn sweep(pwm: &pwm2, mut degrees: u16) {
const BASE: u16 = 1500;// here pwm at position 0 degrees
degrees = BASE + (degrees * 24);// ~28: movt by 1 degree
unsafe {
pwm.cc().modify(|_, w| w.a().bits(degrees) );// move by one degree * no of degrees
}
}
Import the pwm channel.
use rp2040_pac::pwm::ch::CH;
Our application code will now be:
// Servo sweep through 180
for deg in 0..=180 {
sweep(pwm2, deg);
delay.delay_ms(10);
if deg == 180 {
delay.delay_ms(500);
for deg in (0..=180).rev() {
sweep(pwm2, deg);
delay.delay_ms(10);
}
}
delay.delay_ms(500);
Flashing this into the Pico should have the same sweep results as before.
Final Code
The final code up to this point can be found here.
In the next part we apply the PWM in our overall project
Top comments (0)