DEV Community

Cover image for Self-Aligning Satellite Dish in Rust: Servo Application
Ian Ndeda
Ian Ndeda

Posted on

Self-Aligning Satellite Dish in Rust: Servo Application

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.

angles

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

pwm-app-setup

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);
}
Enter fullscreen mode Exit fullscreen mode

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));
Enter fullscreen mode Exit fullscreen mode

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));
});
Enter fullscreen mode Exit fullscreen mode

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);
Enter fullscreen mode Exit fullscreen mode

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);
Enter fullscreen mode Exit fullscreen mode

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...

pwm-app-results-up

Down...

pwm-app-results-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)