The tilt motion of our PTZ kit will be controlled by PWM. We shall discuss the mechanics of the pan movement in the next part.
In the previous part we were able to get the servo to sweep through 180 degrees. We'll modify that code and create a function that can drive our servo to any given angle.
Table of Contents
Requirements
- 1 x Raspberry Pico board
- 1 x USB Cable type 2.0
- 1 x HC-05 Bluetooth module
- 1 x HMC5833L Compass Module
- 18 x M-M jumper wires
- 2 x Mini Breadboards
- 2 x SG90 Servo Motor
- 1 x PTZ Kit
- 1 x GPS Module
Implementation
Fix both servos into the PTZ kit.
Our kit will be constrained to move from 0° to 90°. The set-up will be such that at 90° the tilt part of the kit faces up and at 0° it stands vertically. On start-up it should be at 90° for accurate compass heading measurements.
The image above shows the pan kit at different angles. The dotted line traces the line of sight of the satellite dish's receiving device.
Connections Diagram
Please note that the servo motor here is mounted on the PTZ kit.
Functions
We will use code from the sweep
function that we wrote for the example in the previous part together with all the changes introduced, i.e., importing CH
and setting up delay
.
We'll wrap these around another function tilt
for cleaner execution and to help in code reuse later.
The tilt
function takes the Direction
and tilt_angle
as arguments and ensures movement is constrained within the 0° - 90° range.
fn tilt(pwm: &CH, delay: &mut Delay, tilt_angle: &mut f32, direction: Direction) {
if *tilt_angle >= 0. && *tilt_angle <= 90. {
// valid movts only if angle within range
match direction {
Direction::Up => {
if *tilt_angle != 0. {// constrain angle within range
*tilt_angle -= 1.;// update tilt angle
position_kit_tilt(pwm, tilt_angle);
delay.delay_ms(1);// delay
}
},
Direction::Down => {
if *tilt_angle != 90. {// constrain angle within range
*tilt_angle += 1.;// update tilt angle
position_kit_tilt(pwm, tilt_angle);
delay.delay_ms(1);// delay
}
},
_ => {},
}
}
}
fn position_kit_tilt(pwm: &CH, tilt_angle: &mut f32) {
// facing up --> at 90 deg
// standing vertically --> 0 deg
pwm.sweep((90. - tilt_angle.round()) as u16);
}
We have to introduce a global variable that'll hold the updated tilt angle.
static TILT: Mutex<RefCell<Option<f32>>> = Mutex::new(RefCell::new(None));
Initialize it and upload to the actual variable. The system should start with the tilt part of the kit facing up.
let mut tilt_angle = 90.; // initialize tilt angle i.e. kit facing up
position_tilt_kit(&pwm2, &mut tilt_angle);// start position of tilt
cortex_m::interrupt::free(|cs| {
TILT.borrow(cs).replace(Some(tilt_angle));
});
Application
We can now use PWM in our application code.
In the manual
section of the application code, under Up
, add the following lines.
tilt(&pwm2, delay.as_mut().unwrap(), tilt_angle.as_mut().unwrap(), Direction::Up);
writeln!(&mut serialbuf, "tilt angle: {}", tilt_angle.unwrap().round()).unwrap();
transmit_uart_data(uart_data.as_mut().unwrap(), serialbuf);
Under Down
:
tilt(&pwm2, delay.as_mut().unwrap(), tilt_angle.as_mut().unwrap(), Direction::Down);
writeln!(&mut serialbuf, "tilt angle: {}", tilt_angle.unwrap().round()).unwrap();
transmit_uart_data(uart_data.as_mut().unwrap(), serialbuf);
Results
Rearranging the code we end up with this final copy.
If you run it in the Pico, you should see the PTZ kit initialize facing up on power up and move either up or down depending on the commands given from the Bluetooth Serial App.
Up...
Down...
In the next part we shall implement the pan functionality that will enable the system pan to align with the theta
of our look angles.
Top comments (0)