Microcontroller Project: Gesture-Controlled Robot Arm

Timeline: Spring 2025 Context: ETH Project Based Learning Lab Supervision: Dr. Philipp Meyer Alejo Restrepo

For my microcontroller course I built a pipeline that reads the orientation of an STM32 board and uses it to control a 6-axis stepper-driven robot arm.

The board I used was the STM32 B-L475E-IOT01A, which conveniently comes with the LSM6DSL and LIS3MDL onboard: a 6-axis IMU with a 3-axis gyroscope and accelerometer, and a 3-axis magnetometer.

STM32 onboard sensors: LSM6DSL 6-axis IMU and LIS3MDL 3-axis magnetometer
Onboard sensor stack: LSM6DSL 6-axis IMU and LIS3MDL 3-axis magnetometer on the B-L475E-IOT01A.

The initial implementation read the raw values from the gyroscope and accelerometer and used them individually to calculate the board's orientation: gyroscope rates integrated into pitch, yaw and roll, with the accelerometer's gravity vector as a reference. This worked to an extent.

Initial pipeline: raw LSM6DSL data processed in STM32CubeIDE and streamed to a Python 3D visualization
First pass: raw LSM6DSL readings mapped directly to pitch/yaw/roll in CubeIDE and streamed to a Python 3D view.

There were a few problems though:

The solution was to add the magnetometer and fuse all three sensors with the Madgwick algorithm, which works out how much to trust each sensor at any given moment and outputs a stable quaternion. That keeps yaw anchored and the estimate accurate during movement. The data is read over I2C inside CubeIDE, fused, then streamed over UART to a Python script on the laptop.

Sensor fusion pipeline: I2C sensor reads, Madgwick fusion, UART stream to Python 3D visualization
Embedded pipeline: I2C sensor reads → Madgwick fusion in CubeIDE → quaternion stream over UART.

The Python side renders a live 3D visualization of the board's orientation and detects tilt commands. Once pitch or roll crosses a threshold, it classifies the motion as a forward, backward, left or right command and forwards it over serial to an Arduino UNO.

Python 3D visualization of the board's orientation showing tilt state, smoothing, and Arduino connection status
Live 3D visualization of the board's orientation, with tilt detection, smoothing and the Arduino link status on screen.

The Arduino drives the arm using six NEMA steppers paired with A4988 drivers, with a micro limit switch at each joint for homing. On startup every joint rotates until its switch triggers, the same principle 3D printers use, and the arm settles into its inverted-L home stance. Without that reference position, joints can overextend, and kinematic control later on becomes impossible. I also recorded a video tutorial of the full hardware build.

Arduino UNO commanding six NEMA stepper motors through A4988 drivers, with micro limit switches
Drive train: an Arduino UNO commands six NEMA steppers through A4988 drivers, one micro limit switch per joint.
Limit-switch homing rationale beside the technical drawing of the arm's inverted-L home stance
Limit-switch homing: each joint rotates into its switch to find an absolute reference. The drawing shows the inverted-L home stance and joint ranges.
Part 1 of the hardware build tutorial, on YouTube.

The full chain: IMU data over I2C → Madgwick filter → UART → Python tilt detection → serial → Arduino → stepper motors.

Project workflow: STM32 board through CubeIDE and Python on the laptop, then Arduino, drivers, and steppers to the robot arm
End-to-end signal flow: STM32 IMU → laptop classifier → Arduino motor controller.

So far the demo controls joints 1-5 (excluding 4) directly from the board's orientation data. Tilting or rotating the board moves the corresponding joint.

Joints 1-5 (minus 4) following the board's orientation in real time.

What's next: Cartesian-space control via inverse kinematics

What's missing is inverse kinematics. Right now joints move individually in response to tilt, which works but is limited. The actual goal is Cartesian-space control: give the arm a target position and let it solve for the joint angles. I've already characterized the Denavit-Hartenberg parameters, so the IK solver is the obvious next step. In the meantime the plan is to adapt Maximilian Beck's robot GUI, a JavaScript tool where you describe the robot's geometry and it solves the inverse kinematics to a target pose in real time.

AR4 arm render beside its Denavit-Hartenberg parameters: table, transformation matrix, and joint frames
The groundwork for IK: the arm and its Denavit-Hartenberg parameters.