Open the examples file, create a relays.rs file, and copy the last iteration of the project code. Clear the critical section inside the loop section.
You may also delete the wfi instruction.
We want to pan the PTZ kit through clockwise (CW) and counterclockwise (CCW) swathes alternatively.
The Relay table from the previous part shows that to pan CW we need to enable Relay 1 while 2 is disabled.
Table of contents
- Requirements
-
Implementation
- Connections
- Pan
- Results
Requirements
- 1 x Raspberry Pico board
- 1 x USB Cable type 2.0
- 1 x HC-05 Bluetooth module
- 18 x M-M Jumper Wires
- 2 x Mini Breadboards
- 2 x SG90 Servo Motor
- 1 x PTZ Kit
- 2 x Relay Modules
Implementation
Connections
The servos are here fitted into the PTZ kit.
Pan
For CW movement Relay 1 is enabled while 2 is disabled.
// Move servo CW: Relay 1 ON, Relay 2 OFF
sio.gpio_out.modify(|r, w| unsafe { w.bits(r.gpio_out().bits() | 1 << 16)});// Set pin 16 high
sio.gpio_out().modify(|r, w| unsafe { w.bits(r.gpio_out().bits() & !(1 << 17))});// Set pin 17 low
For CCW movement Relay 1 is disabled while 2 is enabled.
// Move servo CCW: Relay 2 ON, Relay 1 OFF
sio.gpio_out().modify(|r, w| unsafe { w.bits(r.gpio_out().bits() | 1 << 17)});// Set pin 17 high
sio.gpio_out().modify(|r, w| unsafe { w.bits(r.gpio_out().bits() & !(1 << 16))});// Set pin 16 low
The above can be combined into a single pan function like so:
fn pan(delay: &mut Delay, sio: &mut SIO, direction: Direction) {
match direction {
Direction::Cw => {
// Move servo CW: Relay 1 ON, Relay 2 OFF
sio.gpio_out().modify(|r, w| unsafe { w.bits(r.gpio_out().bits() | 1 << 16)});// Set pin 16 high
delay.delay_ms(10);// delay
// Put servo OFF
sio.gpio_out().modify(|r, w| unsafe { w.bits(r.gpio_out().bits() & !(1 << 16))});// Set pin 16 low
sio.gpio_out().modify(|r, w| unsafe { w.bits(r.gpio_out().bits() & !(1 << 17))});// Set pin 17 low
},
Direction::Ccw => {
// Move servo CCW: Relay 2 ON, Relay 1 OFF
sio.gpio_out().modify(|r, w| unsafe { w.bits(r.gpio_out().bits() | 1 << 17)});// Set pin 17 high
delay.delay_ms(10);// delay
// Put servo OFF
sio.gpio_out().modify(|r, w| unsafe { w.bits(r.gpio_out().bits() & !(1 << 16))});// Set pin 16 low
sio.gpio_out().modify(|r, w| unsafe { w.bits(r.gpio_out().bits() & !(1 << 17))});// Set pin 17 low
},
_ => {},
}
}
The pan function moves the servo either CW or CCW depending on the selected direction for 10 milliseconds. Add it into our code.
Since we’ll be using SIO to un/set the relay control pins we need to operate inside a critical section as the application loop shares it with the interrupts.
Add the following into the loop section:
cortex_m::interrupt::free(|cs| {
let mut sio = SIO.borrow(cs).borrow_mut();
for i in 0..=100 {
pan(&mut delay, sio.as_mut().unwrap(), Direction::Cw);
if i == 100 {
for _ in (0..=100).rev() {
pan(&mut delay, sio.as_mut().unwrap(), Direction::Ccw);
}
}
}
delay.delay_ms(500);
});
❗ Comment out the
configure_compassfunction call at the set up area.
Results
We end up with this final copy of our code.
Running the code in the Pico should pan the servo clockwise and counterclockwise.
You may note again that the indication LED blinks at well after 1 second. This is caused by the
Delayfunction we’ve introduced which blocks interrupts.
In the next part we apply these added functions to the main project program

