For this project, I designed and programmed a 6-degree-of-freedom robotic arm. The main goal was to expand my technical skill set and problem-solving abilities, resulting in a diverse range of skills acquired in building a robot from scratch. This included tasks such as CAD design, 3D printing, mastering matrix transformations for inverse and forward kinematics calculations, writing control software and a Python-based GUI, embedded programming in C, implementing WiFi communication, and developing closed-loop motor control algorithms.
Mechanial
The mechanical design of the arm was centered around three main components:
Ease of Maintenance and Upgrades: The arm was built using readily available 3D printer parts, allowing for easy repairability and upgrades.
Encoder Integration: A minimum clearance of 10mm behind the stepper motors was maintained to accommodate magnetic encoders.
Spherical Wrist for Kinematics: The design features a spherical wrist, ensuring that the axes of rotation for the last three joints intersect, which allows for an analytical inverse kinematic solution using trigonometry.
The design was created in Fusion 360, utilizing standard 3D printing components such as NEMA 17 stepper motors, aluminum stepper motor mounts, and steel flange couplings to connect the joints to the links. For joints J2 and J3, 50:1 and 5:1 planetary reducers were used, respectively. This setup allowed the robot to achieve a calculated payload of up to 1 kg while maintaining high repeatability. The robot was 3D printed with PETG due to its higher heat resistance and better resistance to bending and impact forces compared to PLA.
Mechanical Specifications:
J1 & J4: 42mm NEMA 17
J5 & J6: 23mm NEMA 17
J2: NEMA 17 with 50:1 planetary reducer
J3: NEMA 17 with 5:1 planetary reducer
Maximum Calculated Payload: 1 kg
Repeatability: ±2 mm
Illustration of the robot's joints and link lengths
Electrical
This robot uses standard stepper motors from 3D printers due to their high torque and low speed, which are ideal for this application. The motors are controlled using TMC2209 silent stepper drivers, with each joint controlled through the STEP and DIR pins on the stepper driver. Each driver was configured to an 8-microstep setting to maximize torque. A 24V 6A power supply powers all six stepper motors, but each motor's current was limited to 1A by the stepper driver to prevent overheating.
For controlling the stepper drivers and communicating with an external computer, the ESP32-S3 was selected due to its excellent documentation, particularly for WiFi and Bluetooth applications. However, when programming the motors, I encountered a limitation with the ESP32, which has only four available timers. This restriction prevented me from sending separate PWM signals with unique frequencies to each stepper driver. To overcome this, I wrote an algorithm that could simultaneously control all six motors by sharing a single timer.
For motor feedback, closed-loop control was implemented on J1, J4, J5, and J6 using AS5600 magnetic encoders and diametrically magnetized magnets, allowing precise control of these joints' positions with 12 bits of resolution. For J2 and J3, due to the difference in rotation between the motor shaft and the reducer, I manually positioned the robot in the home position upon startup and used software-based step counters to track the joint positions, similar to most 3D printer software. Lastly, an I2C multiplexer was used to connect all six magnetic encoders to the ESP32, enabling simultaneous communication and switching between each encoder chip.
Electrical Specifications:
TMC2209 stepper drivers
AS5600 magnetic encoders
Software
The software for this project is divided into two main components:
Robot Controller Software & GUI: Written in Python, this component provides a graphical user interface (GUI) that allows the user full control over each joint's position and the robot's tool head position. It also features a real-time 3D simulation of the robot, and communicates with the ESP32 over WiFi. In the background, the software continuously performs forward and inverse kinematics calculations using matrix operations and trigonometry.
ESP32 Software: The lower-level software on the ESP32 handles two primary tasks simultaneously. It establishes a TCP server on the microcontroller to listen for incoming data from the Python software and then moves the joints to the desired angular positions based on readings from the magnetic encoders.
The code for this project is available on my GitHub
Schematic of the robot's software
Robot Controller Software (Python):
The Python GUI is built using the customTkinter library, providing the user with full control over each of the robot's joints by allowing them to set angles between -180 to 180 degrees. The GUI also includes a homing feature, which returns every joint to 0 degrees, and allows the user to specify the robot's tool frame position using XYZ coordinates and Euler angles. The tool frame's dimensions and orientation can be customized within the software, making the robot adaptable to various attachments, such as a gripper or camera.
The 3D simulation is created using Matplotlib by plotting the transformation matrices of the robot's joints. This leads us to the mathematical computations the software performs for forward and inverse kinematics. The software uses Denavit-Hartenberg (DH) parameters to define each joint's transformation matrix. For forward kinematics, the joint angles specified by the user are used to calculate the product of each joint's transformation matrix using NumPy, resulting in the final frame's matrix. From this matrix, the tool frame's coordinates (X, Y, Z) and orientation (Rx, Ry, Rz) can be extracted. This process is repeated every time the 3D simulation is updated to reflect the robot's new position.
For inverse kinematics, due to the robot's spherical wrist, the joint angles can be calculated analytically from a given final position and orientation. First, a transformation matrix for the robot's final frame is created based on user input. Then, we work back to the center of the spherical wrist by multiplying it by the inverse of the tool frame matrix and the J1-J6 matrix. Trigonometry is then used to calculate the joint angles for J1, J2, and J3. We perform forward kinematics from J1 to J3 and multiply the inverse of the J1-J3 matrix by the J1-J6 matrix, obtaining the J4-J6 matrix, from which the joint angles for J4, J5, and J6 can be extracted.
For communication with the ESP32, the Python program acts as a TCP client, using sockets to send a list of joint angles formatted in JSON to the ESP32's TCP server. Once the robot has moved to the new pose, the Python program receives a "status: completed" message from the ESP32, allowing it to resume taking user inputs.
ESP32 Software (C):
The ESP32 software utilizes a FreeRTOS task to run a TCP server, allowing it to communicate with the Python program while simultaneously controlling the robot by sending STEP and DIR commands to the six stepper drivers. The server listens for new joint angles from the controller, and once it receives a set of joint angles, it converts the JSON data into six separate joint angles. It then calls a motor control function, which reads the registers from the magnetic encoders. Using this data, along with the step counters for J2 and J3, the function moves all motors simultaneously to their correct angular positions.
Next Version
Experiment with BLDC motors by developing a custom BLDC actuator using ODrive
Learn more about computer vision for robotics, by applying object detection to motion planning and obstacle avoidance