Custom CAD
Robotic Arm
A 4-DOF robotic arm fully designed in SolidWorks with motion simulation. Servo motors are controlled via a Python script, demonstrating the bridge between mechanical design and software.
Mechanical Design
Robotic arms are a cornerstone of industrial automation, but off-the-shelf kits offer little insight into the engineering behind them. I wanted to design every component from scratch — understanding each joint, link length, and torque requirement before a single part was printed.
Using SolidWorks, I built a fully parametric 4-DOF arm assembly. Each joint was sized to the rated stall torque of the chosen MG996R servo, and I ran a basic static analysis to confirm the shoulder joint bracket wouldn't yield under full extension with a 150 g payload.
The final arm spans 480 mm when fully extended, weighs 620 g, and uses a direct-drive wrist with a 3-finger gripper — also designed in SolidWorks and printed in PETG for its improved layer adhesion.
Software & Control
Four MG996R servos are driven by a PCA9685 16-channel PWM board connected to a Raspberry Pi over I²C. A Python script translates target joint angles into PWM duty cycles and sends them in a synchronised update so all joints move together smoothly.
Forward kinematics were implemented to visualise the end-effector position in real time via a simple matplotlib overlay, useful for debugging reach limits before running the physical arm.
# Set joint angle (degrees) → PWM pulse
def set_angle(channel, angle):
angle = max(0, min(180, angle))
pulse = int(
SERVO_MIN + (angle / 180) *
(SERVO_MAX - SERVO_MIN)
)
pwm.set_pwm(channel, 0, pulse)
# Move all joints simultaneously
def move_to(angles: list):
for ch, ang in enumerate(angles):
set_angle(ch, ang)
time.sleep(0.02) # 20 ms settle
// Reflection
What I Learned
Joint Torque Budgeting
I underestimated the torque demand on the shoulder joint in the first revision — the servo stalled under the arm's own weight at full extension. Recalculating with proper moment arms and switching to a higher-torque servo solved this and taught me to always design with worst-case loading.
Parametric CAD Discipline
After the first torque revision required changes to four separate parts, I restructured the SolidWorks assembly to drive all link lengths from a single master sketch. Subsequent changes then propagated automatically — a lesson in design-for-change from the start.
Python I²C Timing
Sending all four PWM updates sequentially introduced a visible stagger between joints. I switched to batching I²C writes into a single transaction using the PCA9685's auto-increment register mode, which eliminated the lag and gave the arm a much smoother, more coordinated motion.
// Explore Further
See It in Action
Full SolidWorks files and Python source code are on GitHub. A demo walkthrough is available on YouTube.