Close
0%
0%

Precision-Tracking and Self-Stabilizing Camera

Lana and Venus: CS012 Project!

Public Chat
Similar projects worth following
A precision-tracking, self-stabilizing system, with a multi-axis gimbal, Raspberry Pi Pico, IMU (accelerometer & gyroscope), high-torque servos, and a joystick, that ensures consistent targeting despite position changes. Perfect for astrophotography and cinematography!

Thanks for checking our page out!
Lana & Venus ☺️

General Overview

Function

This gimbal design lets users balance the camera in an upright position (with all servos at 90 degrees) or adjust the locked position using the joystick. Press the joystick button to toggle between manual (joystick) and auto (IMU) servo control.

Main Components

  1. Raspberry Pi Pico Microcontroller: Controls and receives input from IMU, servos, and joystick module.
  2. IMU BNO085: Gives linear acceleration (Accelerometer) and rotational velocity (Gyroscope) data across the X, Y, and Z axes.
  3. High Torque Servos: Control the gimbal's axes, stabilizing the camera by counteracting position changes detected by the IMU.
  4. Joystick: Toggles between manual and auto servo control modes.

CAD

Main 3D Printed Pieces (STL Files Provided Below):

  • Piece 1. Houses breadboard circuit and serves as base for Servo Y.
  • Piece 2. Serves as base for Servo Z
  • Piece 3. Serves as base for Servo X and supports platform for camera system.

Direction of Axes

  • Servo X corresponds to X-axis (tilting forward/backward), like "pitch" in an airplane.
  • Servo Y corresponds to Y-axis (tilting left/right), like "yaw" in an airplane.
  • Servo Z corresponds to Z-axis (rotating left or right), like "roll" in an airplane.
  • Pushing joystick up/down corresponds to tilting forward/backward on X-axis.
  • Pushing joystick left/right corresponds to tilting left/right on Y-axis.

Design

Wiring

General

  • Power Pins: All components must connect to power pins (3VO, 5V) & ground pins (GND).
  • ADC Pins: Reads analog outputs from joystick potentiometers (x-axis and y-axis).
  • I2C Pins: Sends and receives data with two lines, a serial clock pin (SCL) and a serial data pin (SDA).
  • PWM Pins: Generates a pulsed signal to control the servo position by varying the duty cycle.
  • Push-Button Pin: Pressing the joystick down closes and opens the switch, changing the output between high and low.

Pin Overview (Raspberry Pi Pico)

  • Power Pins: 3VO, GND
  • ADC Pins: GPIO26 (to VRx), GPIO27 (to VRy)
  • I2C Pins: GPIO4 (to SCL), GPIO5 (to SDA)
  • PWM Pins: GPIO16 (to Servo X), GPIO17 (to Servo Y), GPIO18 (to Servo Z)
  • Push-Button Pin: GPIO13 (to SW)

Code

  • Full CircuitPython code provided in instructions.

DIY Gimbal - Self-Stabilizing Platform back-2.stl

Standard Tesselated Geometry - 644.81 kB - 03/21/2025 at 09:05

Download

DIY Gimbal - Self-Stabilizing Platform - handle box4.stl

Standard Tesselated Geometry - 226.55 kB - 03/21/2025 at 09:05

Download

DIY Gimbal - Self-Stabilizing Platform - base.stl

Standard Tesselated Geometry - 93.15 kB - 03/21/2025 at 09:05

Download

  • 1 × Raspberry Pi Pico Microcontroller
  • 1 × IMU BNO085
  • 3 × High Torque Servo Motors
  • 1 × Joystick Module
  • 1 × Bread Board

View all 8 components

  • Final Demo Updates

    Venus Aradhya03/10/2025 at 20:29 0 comments

    We printed out our final gimbal base model after modifying some of the dimensions to fit the newer high torque motors we switched into using. We also got our raspberry pi camera and worked on adding that to the final model. Everything was set up and finalized for the final demo which occurred on Friday!

    Final 3d print where we fixed the dimensions to be compatible with the new high torque motors, and made some other final adjustments based on previous designs:

    (link to 3d print design will be added in project instructions)

    Simple circuit board just connected to one servo and no joystick module- later, two servos were added (high-torque) with similar circuit configuration, and the joystick module was added:

    Final model - all three servos were successfully moving the gimbal, imu was placed on top of main blue board to hold steady position:

    Acai bowls to celebrate project completion:

    Final demo updates:

    One issue we faced was the shallow nodes of the servo motors not fitting completely and falling out- we attempted to address this by using hot glue which got stuck in the rotor area and made it very hard to attach and therefore use. We are fixing this by manually removing all hot glue, printing out new parts, and using spares to reattach servos without hot glue. Main tip is to not use hot glue on servos. 

  • Integrating Angle Control with Joystick Module

    Lana Saopraseuth03/05/2025 at 02:57 0 comments

    We added a new angle control feature, enabling users to select and lock a camera position using the joystick, allowing more diverse applications. Initially, I planned for the joystick to activate when moved past its neutral center position, with the servos locking into the last active position when the joystick returned to center. Additionally, pressing the joystick would reset all servo angles to a default position of 90°. However, this proved difficult, as the servos couldn't differentiate between being inactive or passing through the neutral center position. The current design now requires the user to press the joystick to activate it, allowing control of the servos. Pressing it again deactivates the joystick, locking the current servo orientation and allowing the IMU to solely control the servo movement.

  • Incorporating Multiple Servos

    Lana Saopraseuth03/04/2025 at 23:35 0 comments

    The gimbal incorporates three high-torque servos, each controlling a specific axis. Servo X stabilizes angular velocity around the X-axis (tilting forward/backward), Servo Y stabilizes the Y-axis (tilting left/right), and Servo Z stabilizes the Z-axis (rotational movement).

    Additionally, due to issues with the USB power source causing the servos to slow down and lock after a minute of use, the system has been switched to an external power supply.

  • Gimbal Check

    Venus Aradhya02/19/2025 at 17:18 0 comments

    First big checkpoint has been reached; gyroscope & accelerometer data is being read into into Circuitpython and servos have been programmed to counterbalance motion and auto stabilize acting as gimbal

    Next steps: attach raspberry pi camera to base and redesign handheld CAD structure to accommodate for new servo placement  rather than the previous model

  • Printing First Model

    Venus Aradhya02/15/2025 at 20:12 0 comments

    We spent last week working on the construction of the mainframe of the gimbal and printed our first 3d printed frame- may be a few issues requiring us to reprint after some testing out

    Orca Slicer:

    Final product (trial one):

    ft. team no rain no gain (weather was lots of rain little gain) with a 3d printed space needle repping WA

  • PDR

    Venus Aradhya01/29/2025 at 19:28 0 comments

    We presented our project proposal in class on 1/28 to get some feedback

    + parts have been ordered 

View all 6 project logs

  • 1
    Wiring

    General

    • Power Pins: All components must connect to power pins (3VO, 5V) & ground pins (GND).
    • ADC Pins: Reads analog outputs from joystick potentiometers (x-axis and y-axis).
    • I2C Pins: Sends and receives data with two lines, a serial clock pin (SCL) and a serial data pin (SDA).
    • PWM Pins: Generates a pulsed signal to control the servo position by varying the duty cycle.
    • Push-Button Pin: Pressing the joystick down closes and opens the switch, changing the output between high and low.

    Raspberry Pi Pico

    • Power Pins: 3VO, GND
    • ADC Pins: GPIO26 (to VRx), GPIO27 (to VRy)
    • I2C Pins: GPIO4 (to SCL), GPIO5 (to SDA)
    • PWM Pins: GPIO16 (to Servo X), GPIO17 (to Servo Y), GPIO18 (to Servo Z)
    • Push-Button Pin: GPIO13 (to SW)

    Credits: Raspberry Pi Microcontrollers

    IMU BNO085

    • Power Pins: 3VO, GND
    • I2C Pins: SDA (to GPIO4), SCL (to GPIO5)

    Joystick Module

    • Power Pins: 5V, GND
    • ADC Pins: VRx (to GPIO26), VRy (to GPIO27)
    • Push-Button Pin: SW (to GPIO13)

    Servo Motors

    • Servos have 3 wires: Brown (Ground), Red (Power), Yellow (PWM)
    • PWM: Servo X (to GPIO16), Servo Y (to GPIO17), Servo Z (to GPIO18)
    • We recommend using wire connectors to link the power and ground wires of the servos to the Pi Pico and an external power supply, like a wall outlet.
  • 2
    CircuitPython Code
    import time
    import board
    import busio
    import pwmio
    import analogio
    import digitalio
    from adafruit_motor import servo
    from adafruit_bno08x import BNO_REPORT_GYROSCOPE
    from adafruit_bno08x import BNO_REPORT_ACCELEROMETER
    from adafruit_bno08x.i2c import BNO08X_I2C
    
    # Initialize I2C
    i2c = busio.I2C(board.GP5, board.GP4, frequency=400000)
    bno = BNO08X_I2C(i2c)
    
    # Enable Gyroscope
    bno.enable_feature(BNO_REPORT_GYROSCOPE)
    
    # Enable Accelerometer
    bno.enable_feature(BNO_REPORT_ACCELEROMETER)
    
    # Read Accelerometer Data
    accel_x, accel_y, accel_z = bno.accelerometer
    
    # Initialize Joystick
    x_axis = analogio.AnalogIn(board.GP26)
    y_axis = analogio.AnalogIn(board.GP27)
    
    # Initialize Joystick Push-Button
    button = digitalio.DigitalInOut(board.GP13)
    button.switch_to_input(pull=digitalio.Pull.UP) 
    
    # Initialize PWM
    pwm_x = pwmio.PWMOut(board.GP16, duty_cycle=0, frequency=50)
    pwm_y = pwmio.PWMOut(board.GP17, duty_cycle=0, frequency=50)
    pwm_z = pwmio.PWMOut(board.GP18, duty_cycle=0, frequency=50)
    
    servo_x = servo.Servo(pwm_x)
    servo_y = servo.Servo(pwm_y)
    servo_z = servo.Servo(pwm_z)
    
    # Initial Servo Angles
    servo_angle_x = 90
    servo_angle_y = 90
    servo_angle_z = 90
    
    # Scaling Factors
    gyro_scale_factor = 10  
    joystick_dead_zone = 5
    joystick_active = False
    
    # Lock Servo Angles
    locked_angle_x = servo_angle_x
    locked_angle_y = servo_angle_y
    locked_angle_z = servo_angle_z
    
    # Track the last state of the button press for toggling
    last_button_state = False
    button_pressed = False
    
    # Function to map joystick input (0-65535) to servo angle (0-180)
    def map_range(value, in_min=0, in_max=65535, out_min=0, out_max=180):
        return (value - in_min) * (out_max - out_min) // (in_max - in_min) + out_min
    
    while True:
        time.sleep(0.1)
    
        # Read Joystick Values
        joy_x = map_range(x_axis.value, 0, 65535, -100, 100)
        joy_y = map_range(y_axis.value, 0, 65535, -100, 100)
        button_state = not button.value
    
        # Button is Pressed
        if button_state != last_button_state:
            if button_state:
                joystick_active = not joystick_active
                if joystick_active:
                    print("Joystick is now active!")
                else:
                    print("Joystick is now inactive, position locked.")
            last_button_state = button_state
    
        # When Joystick is Active
        if joystick_active:
            # Joystick controls servos
            servo_angle_x = map_range(x_axis.value)
            servo_angle_y = map_range(y_axis.value)
            locked_angle_x = servo_angle_x
            locked_angle_y = servo_angle_y
        else:
            # When Joystick is Inactive
            gyro_x, gyro_y, gyro_z = bno.gyro
    
            locked_angle_x += gyro_x * gyro_scale_factor
            locked_angle_y += gyro_y * gyro_scale_factor
            locked_angle_z += gyro_z * gyro_scale_factor
    
            locked_angle_x = max(0, min(180, locked_angle_x))
            locked_angle_y = max(0, min(180, locked_angle_y))
            locked_angle_z = max(0, min(180, locked_angle_z))
    
        # Set Servo Angle (Based on Locked Angles)
        servo_x.angle = locked_angle_x
        servo_y.angle = locked_angle_y
        servo_z.angle = locked_angle_z
    
        mode = "Joystick" if joystick_active else "IMU"
        print(f"Mode: {mode}")
        print(f"X: {locked_angle_x}, Y: {locked_angle_y}, Z: {locked_angle_z}")
        print("-" * 50)
  • 3
    CAD Design

    STL Files for 3D Printed Designs

    • Piece 1. Houses breadboard circuit and serves as base for Servo Y.
    • Piece 2. Serves as base for Servo Z
    • Piece 3. Serves as base for Servo X and supports platform for camera system.

    Direction of Axes

    • Servo X corresponds to X-axis (tilting forward/backward).
    • Servo Y corresponds to Y-axis (tilting left/right)
    • Servo Z corresponds to Z-axis (rotating left or right)
    • Pushing joystick up/down corresponds to tilting forward/backward on X-axis.
    • Pushing joystick left/right corresponds to tilting left/right on Y-axis.

    During assembly, ensure each servo is connected to the correct axis by verifying that the GPIO pins correspond to the appropriate PWM pins. As shown in the image above, each servo corresponds to a specific plane and is responsible for controlling a particular axis (X, Y, or Z).

    • ZY Plane (X-axis data): Held in the side of the gimbal, like "pitch" in an airplane.
    • XZ Plane (Y-axis data): Held in the base of the gimbal, like "yaw" in an airplane.
    • XY Plane (Z-axis data): Held in the back of the gimbal, like "roll" in an airplane.

    Credits: Wikipedia

    Servos can be attached using bolts, nuts, and washers. While servos come with mounting parts for easy attachment, additional holes must be drilled for a secure fit in this model. A key challenge we faced was the shallow servo mounts, causing the servos to wedge out over time. Our initial attempt to secure them with hot glue provided only a temporary fix, as the glue lacked strength and made reattachment more difficult. The final solution was to use screws to secure the servos to the axes at the center of the mount, ensuring a stable and lasting fit.

View all 3 instructions

Enjoy this project?

Share

Discussions

Similar Projects

Does this project spark your interest?

Become a member to follow this project and never miss any updates