This project is a ball-balancing platform that uses PID control to keep a ball near the center of a tilting plate, or move it toward a target setpoint. The system combines a 3-RPS parallel mechanism driven by three stepper motors, an OAK camera for ball position tracking, and an Arduino Uno running PID control plus inverse kinematics.
The mechanical concept, overall design, and inverse kinematics approach for the 3-RPS mechanism are based on this guide:
- Ball Balancer - Instructables: https://www.instructables.com/Ball-Balancer/
This repository is not a direct copy of the original project. The code has been adapted for this hardware setup, camera pipeline, Serial communication flow, and PID tuning values.
-
The OAK camera captures frames at
1024x836. -
A Python script uses OpenCV to threshold the ball color in HSV space.
-
The ball center is calculated from the moment of a valid contour.
-
The ball position is sent over Serial in this format:
x y\r -
The Arduino reads the position and calculates the X/Y error.
-
The PID controller converts that error into a plate tilt vector.
-
Inverse kinematics converts the tilt vector into target angles for the three mechanism legs.
-
AccelStepper drives the three stepper motors to the calculated positions.
When the ball is not detected, the firmware moves the platform back to its default balanced position.
- Arduino Uno
- 3 stepper motors
- 3 STEP/DIR stepper drivers
- 3-RPS parallel mechanism based on the Ball Balancer design
- Luxonis OAK camera, or another DepthAI-compatible camera
- Computer running Python for image processing and Serial communication
- Suitable power supply for the stepper motors and drivers
Pins are configured in src/Setup.h:
| Function | Pin |
|---|---|
| Stepper 1 STEP | 2 |
| Stepper 1 DIR | 3 |
| Stepper 2 STEP | 4 |
| Stepper 2 DIR | 5 |
| Stepper 3 STEP | 6 |
| Stepper 3 DIR | 7 |
| Driver enable | 13 |
The current Serial baud rate is 112500.
.
├── platformio.ini
├── src/
│ ├── main.ino
│ └── Setup.h
├── lib/
│ ├── InverseKinematics/
│ └── Point/
└── oak-webcam/
├── oak-webcam.py
└── sending.py
src/main.ino: main loop, PID control, stepper control, and IK calls.src/Setup.h: baud rate, timeout, speed limits, and pin mapping.lib/InverseKinematics: calculates each leg angle for the 3-RPS mechanism.lib/Point: reads the ball position from Serial.
oak-webcam/oak-webcam.py: reads frames from the OAK camera, thresholds the ball color, finds the contour center, and sends coordinates.oak-webcam/sending.py: opens the Serial port and sends data to the Arduino.
By default, sending.py uses COM12. Change this to match the port used by your Arduino.
This is a PlatformIO project targeting Arduino Uno.
pio run
pio run --target uploadMain Arduino libraries:
AccelStepperMultiStepper- Internal
InverseKinematicslibrary - Internal
Pointlibrary
Install the required Python packages for the camera and image processing pipeline:
pip install opencv-python depthai pyvirtualcam numpy pyserialRun the camera pipeline:
python oak-webcam/oak-webcam.pyIf the Arduino does not receive position data, check:
- The COM port in
oak-webcam/sending.py - Whether the baud rate matches
src/Setup.h - Whether the camera detects the ball with the HSV range in
oak-webcam.py - Whether the sent data format is
x y\r
These values usually need adjustment when the hardware changes:
Xoffset,Yoffsetinsrc/main.ino: image center / platform center.kp,ki,kd: PID constants.alpha,beta: additional derivative-related coefficients.MAX_SPEED,STEP_RANGE: stepper configuration.Machine machine(d, e, f, g): geometry dimensions of the mechanism.- HSV threshold and contour area limits in
oak-webcam/oak-webcam.py.
Recommended calibration order:
- Check the rotation direction of each stepper motor.
- Verify that the platform returns to a level home position.
- Recalculate the image center values
XoffsetandYoffset. - Confirm that ball coordinates are being sent over Serial.
- Start with small PID values and increase gradually until the system is stable.
- Do not power the stepper motors while the mechanism is mechanically blocked.
- Check the mechanical travel range before increasing speed.
- During PID tuning, start with a small tilt range to avoid throwing the ball off the plate.
- Make sure the motor supply and logic supply share a common ground if your circuit requires it.
This project uses the design idea and inverse kinematics reference from Ball Balancer on Instructables. Please keep this attribution when reusing or extending the project.