ph475-xz834-yk699

This project is maintained by ece3140-sp2025

Nappy: 4-DOF Robot Arm

May or may not always be “armed”.
Peter He, Yoshiaki Kanematsu, Xia Yan Zhao

Nappy with a plastic knife.

Nappy is a 4-degrees-of-freedom (DOF) robotic arm capable of holding various tools, including exacto knives, scissors, and even Nerf guns.

Nappy can also perform tasks like discarding annoying objects such as the FRDM boards. Nappy yeets FRDM board.

Nappy tools.

The robot arm can be pre-programmed to execute specific movement sequences or controlled dynamically via a Python interface on a laptop, communicating through UART.

Nappy control scheme.

Video

https://www.youtube.com/watch?v=fvBaP8aSvRo

Technical Implementation

The initial prototyping for Nappy was done using an Arduino. However, the final implementation transitioned to an FRDM board, supplemented by an external 5-volt power supply. This external power source was crucial because the current draw from the servos exceeded the capacity of the FRDM board’s native 5-volt output. Eg. our FRDM-KL46Z crashed when we moved too many servos originally.

Our 3D CAD model was adapted from an open-source design by omartronics, found on Cults3d. We introduced modifications to enhance the robustness of the joints and to enlarge the overall base, tailoring the design to our specific requirements. All structural components of the robot were 3D printed using PLA.

The arm’s movement is actuated by four servos:

One servo controls the rotation of the base.

A second servo actuates joint one.

A third servo controls joint two.

The final servo operates the claw mechanism.

Custom Servo Library

Our biggest challenge encountered was the absence of a native servo library for the FRDM board. This meant we needed to write a custom library from scratch. Luckily, the standardized nature of analog servos simplified this task.

Conventional analog servo motors are controlled using a PWM signal with a period of 20 milliseconds (ms), which corresponds to a frequency of 50 Hertz (Hz). The angular position of the servo shaft is determined by varying the width of the PWM pulse between 1 ms and 2 ms. A pulse width of 1 ms typically corresponds to 0 degrees, while a 2 ms pulse width corresponds to 180 degrees.

Standard Servo PWM

Therefore, for the FRDM board, all we needed was to write a library capable of generating PWM signals adhering to this convention. We also implemented functions to convert desired angular positions (in degrees) into the required PWM signal parameters.

While a similar task involving PIT interrupts and LEDs was done in a previous lab, we used the FRDM board’s built-in TPM (Timer/PWM Module) Timer module for generating the PWM signals. For the sake of staying sane during finals week.

For I/O, we selected pins PTB0 through PTB3 due to their PWM support and convenient accessibility.

FRDM pins

The PWM signal generation relied on the board’s integrated MCGFLLCLK (Multipurpose Clock Generator). This clock generator operates at a frequency of 20 MHz and served as the clock source for our TPM timer modules.

To achieve the required 50 Hz PWM frequency, we configured the TPM timer module. First, the 20 MHz clock was divided by 16, resulting in a 1.25 MHz clock for the timer. Next, the timer module’s modulo register (TPM_MOD_VALUE) was set to 24999. This configuration means the TPM counter takes 25,000 ticks of the 1.25 MHz clock to complete one cycle. This setup (25,000 ticks per cycle / 1,250,000 ticks per second) yields a PWM cycle period of 20ms, or a PWM frequency of 50 Hz.

Within this 50 Hz cycle, we defined variables to represent the pulse widths for 0 and 180 degrees:

1250 ticks for a 1 ms pulse (1250 ticks / 1,250,000 ticks per second = 0.001 seconds).

2500 ticks for a 2 ms pulse (2500 ticks / 1,250,000 ticks per second = 0.002 seconds).

We also used multiple TPMs (TPM1, TPM2) to control more servos at once through the different pin configurations.

We used enums in the headerfile SERVO_BASE (PTB0), SERVO_JOINT1 (PTB1), SERVO_JOINT2 (PTB2), SERVO_CLAW (PTB3, and SERVO_COUNT to define named constants to select which servo to control in our library.

void Servo_Init(void);

typedef enum {
    SERVO_BASE,    // Connected to PTB0 (TPM1_CH0)
    SERVO_JOINT1,  // Connected to PTB1 (TPM1_CH1)
    SERVO_JOINT2,  // Connected to PTB2 (TPM2_CH0)
    SERVO_CLAW,    // Connected to PTB3 (TPM2_CH1)
    SERVO_COUNT    // Number of servos
} ServoID_t;

void Servo_SetAngle(ServoID_t servo_id, uint8_t angle);

void Servo_Delay_1s(void);

Our custom servo library then takes the specified servo name (the enums) and desired angle (in degrees) as input from the main program loop. It generates the corresponding PWM pulse with a width between 1 ms and 2 ms to control the servo’s position. To simplify operation, we hard-coded specific pins (PTB0 to PTB3) to their respective servos, eliminating the need for pin configuration with each function call.

Our Python interface sends the specific Servo Names (eg. base, joint1, joint2, and claw) and degrees (0 through 180) through UART to the FRDM-KL46Z. This is all controlled through a Python GUI built with tkinter.py. For the sake of not breaking our robot, we have the base and joints moving in 5 degree increments and the claw having a set open and close position. In the main program loop on the for FRDM-KL46Z Nappy, we control the arm by calling commands from our custom servo library corresponding to the servo name and angle it receives through UART from our python interface.

All the UART communications implementations were based off of the provided reference UART C and Python code on Canvas.

Mechanical Challenges

Mechanical stability was a significant challenge during testing. Several parts of the robotic arm were not properly press-fitted, causing the arm to collapse or components to detach. To fix, we tried different methods of attachments.

Initially, we used acrylic glue, which worked well until it caused the grip rotation to snap. We then tried super gluing the motors, but the glue never fully dried after a day or two, because it was under many layers of PLA. Finally, we used hot glue and, after reprinting some parts for a better fit, the structure didn’t fall apart. We also found that vibrations caused by motor actuation would loosen connections over time, leading us having to print new parts so that it is new.

Work Distribution

We splitted the work into mechanical and code work. We collaboratively worked on the mechanical assembly and as well as servo selection.

Yoshi primarly worked on putting the robot arm together, assembly spares for testing, soldering weak points, and strengthen wiring connections.

Xiayan primarly worked on CAD and converting mesh STL to prismatic surfaces to make STL editable to adhere to our 4 DOF design; also helped with electrical wiring for the Arduino in the earlier stages for the data ground pins. Servo selection (different from the open source CAD) was made by referencing open source python code.

Peter primarily did the electrical and the coding work such as writing the custom Servo library for the FRDM-KL46Z board. Peter discovered fragile points of the robotic arm and wrote code to adhere to the structural integrity of the arm.

Outside Resources

Github CoPilot was used as a standard coding assistant because Peter first wrote everything in VSCode before porting it over to MCUXpresso. It helped reduce development time eg. patterns like specifying ports PTB0 to PTB3 could be done automatically.

Other sources also included A LOT OF FRDM forums, StackOverFlow, as well as someone’s public github repository about using the built in FRDM timer modules https://github.com/KayeJD/FRDM-KL46Z-Programming.

Python library for tkinter: https://docs.python.org/3/library/tkinter.html

Open Source Robot Arm: https://cults3d.com/en/3d-model/gadget/omarm-6-dof-robotic-arm-for-arduino-full-3d-printed-model-stl

Finally, shoutout to caffeine.