Hello! It’s been a while since I’ve written here but I just completed an intensive project with my friend/roommate/classmate for my CPET-253 class, and wanted to share.
Plan:
For this project, our goal was to use an MSP430 microcontroller, and 5 components from a provided list to create something unique with real-world applications.
The options for components include:
a. State Machines
b. Speakers
c. Hardware Interrupts
d. Timer Interrupts
e. SPI – LCD
f. Bluetooth
g. IR sensing
h. Ultrasonic Sensing
i. Servos
j. Analog to Digital Converters
k. Any additional sensor items from the lab kits
We wanted to find a project idea that suited our skillsets, so considering I have experience with hardware electronics and my friend has experience writing code, we decided on something that would integrate custom hardware with software. After some pondering, we decided to make a robotic hand. The components we picked were state machines, speakers, hardware interrupts, SPI-LCD, and servos. The state machine would serve as the structure of the code, the speaker would play sounds for different gestures, the hardware interrupts would identify when buttons are pressed, the LCD would display a name for gestures, and the servos would move the fingers. Below is a simple sketch of the idea.

3D-Printing:
Our first step was finding a suitable way to make the hand. Since creating it from scratch would be very time-intensive and difficult, we decided to 3D-print it using RIT’s 3D-printing service for students in the Student Hall for Exploration and Development (SHED). We found an Instructables article with 3D files for an articulable hand that used machine screws for the joints. Since each part was a separate .stl file, we combined them using a free software called Meshmixer. All of the parts printed successfully thanks to our slicer settings, including a 1 layer raft and light supports. We used PLA filament on a Pruscia i3 MK3. Once the parts were printed, I labeled them all and we began the process of cleaning them up. Removing the supports and raft was easy, but due to the orientation of some of the parts, the rounded parts were a bit “steppy” due to having significant overhang. To fix this we dedicated a few hours to carefully sanding and filing every joint until the steps were smoothed.
Mechanical Construction:
Constructing the hand was arguably the most fun and easy part of the process. One difficulty we encountered was that the design called for metric machine screws, which are less common in the US. However, after a bit of back and forth between Lowes and Home Depot and 50 or so dollars, we had all the machine screws we needed (some slightly longer because we couldn’t find the exact sizes the design called for, but this was easily solved with some filing and sawing). As we put the fingers together, we checked how smoothly the joints bent, and sanded or filed any material that needed to be removed. To further ease the joint movement, I used a pencil to coat all the joints with a thin layer of graphite for lubrication. We avoided oil-based lubricants since they can sometimes degrade plastics. Once the hand was fully constructed we tried feeding some string we had bought at Home Depot through the loops on the fingers, only to realize that the string was too thick to fit. This was frustrating because it meant we would need to find new thinner string, and at this point, we were working on a time crunch so we were unable to go out and buy more. Luckily, I remembered that I happened to have a sewing kit in my room with a spool of black thread. The thread was not super durable, but it seemed strong enough for this application. Additionally, the black color complemented the orange 3D-printed hand nicely. Once the string was threaded through, we were able to do simple tests on the hand’s mechanical functionality.
Below is a video of the hand being opened and closed using the sewing thread.
One issue we found was that when the hand was opened too quickly or forcefully, the thumb could end up stuck in an overextended position. To fix this I added a small plate that limited the thumb’s extension. This allowed the thumb to still fully open while preventing overextension. Another modification I made to the hand was adding copper wire around the bottom of the metacarpals. This allowed the thread to move over a smooth rounded surface, rather than riding over the nuts and getting caught or abraded. One more change we made to the hand was adding additional holes to the base for the tendon threads in the front. The reason for this change was to improve the angle of the thread pulling the thumb. Since the design had an opposable thumb, it would swivel in and out when the thumb moved. Having the thumb tendon thread go through a hole in the center of the base meant that the thread’s angle was closer to vertical than horizontal. Because of this, the thumb was getting pulled down more than horizontally towards the palm. Making its tendon go through a hole across the thumb greatly improved this issue. Below is a very simplified diagram showing how the new holes for the tendons allowed better angles for the thumb tendon.

Now that the hand’s movement seemed smooth enough, I needed to find a suitable enclosure to attach the hand to, that would contain the servos. I found a perfect one sitting around, which originally contained a cheap stereo pair of iHome portable speakers. It was a black rectangular box made of plastic, with a removable front cover and a black felt-coated interior. To attach the hand, I first copied its tendon holes in the base into the top of the enclosure. I then glued the hand to the top of the enclosure, with the tendon threads going through the lined-up holes, and into the enclosure.
At this point, we had tendons on the front and back of the hand, with the ones on the back just going through one central hole in the wrist connection. I planned to then have elastic connected to these threads inside of the enclosure so that when a finger was released the elastic would straighten the finger back out by pulling the tendon threads on the back of the hand. I managed to get two of these elastics properly connected when I realized that having thread tendons running through channels on the back of the hand created way too much friction. To make the elastic strong enough to straighten the fingers back out, it would need to be tightened beyond what the small servos we had could handle. Seeing this limitation, as well as the low amount of room left in the enclosure, I decided to scrap the idea of tendon threads on the back of the hand. Instead, I cut out small strips of elastic and glued a separate piece on the back of each joint. This solved the friction problem, making it so that the elastic could be less strong, in turn reducing the eventual load on the servos.

Now it was time for the project to become serious – I was finally ready to install the servos. One thing I had to figure out to make the servos work was how to have them pull on the threads. To do this, I first considered the servos we had to work with. They take a PWM input, and the pulse width determines their position. Since they have a maximum travel of 180 degrees, I decided that rather than a spool I could simply use a cam as shown below.

With the cam system as opposed to a spool, construction of the servo arms became much simpler. This solution worked well because the servos came with attachable cam arms, to which I only had to add a piece of twisted copper wire for the thread to attach to. Now that I knew how I wanted to connect the threads to the servos, I needed to find a way to arrange the servos in the enclosure without them interfering with each other. To accomplish this I first considered the clearance I needed in the X-Y plane.

However, after considering the X-Y clearance, I realized that there was an issue. Having identical cams on each servo would lead to thread colliding with the cams in front of them. To solve this issue I considered the clearance in the Z plane.

Now that I had a plan, it was time to work on installing the servos. I went one by one, from thumb to pinky, testing clearances on each cam, and shortening or lengthening the cams to adjust the travel of threads for each finger. This meant that I could perfect the distance of travel for each finger, while also avoiding any clearance issues.
After some fiddling and adjustments, I had all 5 servos installed with their cams and threads connected. To keep the servo wires out of the way of the cams, I ran them in between the servos below the cams and used strips of paper to keep them in the bottom left corner of the enclosure as seen below.

Electronics
The next step after installing all the servos and getting the mechanical parts working was to deal with all the electronics hardware. First, I wanted a way to connect all the servos to the MSP430 without needing a ton of wires connecting each servo’s power and ground to it. To deal with this, I used pin headers and a piece of perfboard to connect all the power rails. By doing this, I only needed to connect one power and one ground wire to the MSP430 for all of the servos. Since I was socketing the servo connectors, I also soldered a socketed jumper for each servo’s PWM pin to the perfboard.

To connect the PWM pins accordingly, I followed a pinout guide made by my friend:

The next step after this was to build the control interface. This would consist of 5 momentary buttons on a surface, each corresponding to a finger. Since my friend used the internal pull-up resistors for these inputs, I made the buttons active low. One other addition I made was adding a 0.1uF capacitor in parallel with each button. The purpose of this was to debounce the buttons, since bouncing on button contacts often causes problems with hardware interrupts. Below is a sketch of the schematic of the controller, followed by an image of the completed controller.


One of the changes that was made to our original plan was the use of the LCD. After reconsidering the amount of time left and how much effort SPI communication in the MSP430 takes to set up, we decided to drop that component and replace it. After careful consideration of our options, we decided on timer interrupts as our fifth component. This decision will be further explained in the software section of this post. Part of this change was implementing a “display” mode, which would display different gestures one after another. To enter this mode, we decided to implement a rocking toggle switch. The switch connects port 6 pin 0 (as seen in the pinout) to ground when active, and uses one of the MSP430’s built-in pull-up resistors. Rocker switches are less prone to bouncing, but to play it safe I included a 0.1uF capacitor in parallel.
The speaker for this design was a small piezoelectric buzzer, to which I soldered some socketed jumpers. Below are the buzzer and rocker switch attached to the enclosure:

The final hardware change to make was finding a way to attach the MSP430 to the enclosure. Since drilling holes and using standoffs would be a bit time-consuming, I came up with an alternative. The MSP430 attaches to the chassis we use in class via socketed pin headers, which makes a secure but easy-to-disconnect attachment method. Since I have a large stock of pin headers, I decided to use them. I bent the pin headers 90 degrees, socketed them into the MSP430, and glued the exposed bottoms to the enclosure as shown below.


This attachment method worked great because it held the MSP430 to the enclosure securely, but made it very easy to remove. I’ll probably be using this approach for future microcontroller projects due to the ease and speed of putting it together.
Code
My friend did most of the writing of the code, but still had me check it every so often and provide feedback. Doing this throughout the writing of the code was very helpful because when the time came to debug, I already had a good grasp on the structure of it. We originally started this project by creating a state transition diagram for the state machine, which is shown below.

After some structuring of sample code and discussing, my friend and I decided to restructure this. The first change, as already mentioned in the hardware section, was removing the LCD. This is partly because SPI involves lots of registers and time to set up, but mainly because we didn’t want to use the robot chassis for this project. It felt unnecessary to include it only for the sake of the LCD, especially considering that without it we could make the whole arm a standalone unit besides the control pad. However, this put us in the position of needing to select a new component to fulfill our requirement of five. After some careful consideration, we decided to use timer interrupts. I had the idea of having two “modes” for the arm – active, and display. Active mode would allow interactive use of the buttons to control the arm, and display mode would cycle through different gestures, accompanied by sounds playing. The reason for this idea was that we could use timer interrupts as a way of timing the gestures for display mode. It also meant that since display mode would use the speaker, we could remove gesture detection from active mode, making the coding process a lot easier.
The very first piece of code that was put to use was a simple servo test. It used the MSP430’s timers in PWM mode, and functions to move each finger up and down. Each function would update the corresponding CCR for each finger, updating the pulse width for that pin output.


Starting with just one function, we tested various values for the maximum and minimum pulse widths. Eventually, we landed on two values that gave us a full 180-degree rotation on all servos. These values were then defined as constants that could be included in the function calls.

Once we had this tested, my friend proceeded to structure the state machine and functions while I built the electronics and mechanics. Our new state machine had three states: Active, Display, and Fingers.
Active State
This state’s purpose was to move the fingers back up when their respective buttons were released, as well as transitioning to the other two states. Entry housekeeping sets the MSP430’s onboard LED to green to indicate the state, enables interrupts for the button inputs, and disables the timer used for the Display state. If an interrupt is detected, indicating a button press, the state would be updated to Fingers. If the rocker switch was used to select Display mode, the state would update accordingly. I’ll further discuss the reason for our use of the boolean “isSwitch” later on in the functions section.

Display State
The Display state’s purpose was to cycle through various gestures and to play sounds corresponding to the gestures. In entry housekeeping, the LED color is updated to purple, interrupts for finger buttons are disabled, the gesture variable is reset to 0, and the Display mode timer is set to continuous mode. This timer would use interrupts to update the gesture value, which will be explained later in the functions section.
In the first gesture (a “rock on” sign), the fingers are updated one by one, and after a one-second delay, it plays an alternating half-step interval on the speaker.
The second gesture is a thumbs-up, and similarly updates the fingers, waits one second for them to move, and then plays a tune. This one plays an arpeggiated C-major chord once and then again up an octave, making a pleasant chime sound.
The third and final gesture is an “ok” sign. It updates the fingers one by one, waits a second, and then plays a C-note twice (the first one being much shorter than the second), and then does the same up an octave.
Finally, the Display state checks for the rocker switch being set back to Active mode. When this is detected, it sets isSwitch low again, and sets the state to Active.

Fingers State
This state is the simplest. It is entered any time a hardware interrupt is detected on the finger buttons. When fingers is entered, it sets wasInterrupt to 0, sets the LED color to red, and goes back to Active state. The actual moving of the fingers occurs in the IRQ handler, which will be discussed later in the functions section.

Functions






Once this code was all written, we were able to move on to testing the full functionality of the hand. The only changes made after this point that haven’t already been mentioned were fixing small errors in the code. Some of these include accidentally setting the wrong registers in port initializations (causing two fingers to not move), or calling fingerInit() at the beginning of the Active state (causing fingers to open every time the state machine left the Fingers state).
Demo
Conclusion/Closing Thoughts
This project felt like a great success overall. I had many concerns about encountering issues with the mechanics and code that we wouldn’t be able to fix in time, but we managed to have everything working for the day of our presentation. However, throughout the process of making this project, I learned a lot and have thought of a few improvements I would make in a future redesign.
Mechanical Improvements
One of the first struggles we encountered in this project was the smoothness of 3D prints. While the hand worked very smoothly after lots of sanding and filing, there are some changes I would make to the way we printed parts to reduce the cleanup time. Many of the hand pieces were oriented to minimize the need for supports, but in this process I neglected to consider overhang on the areas that needed to be smoothest – the joints. Many of the pieces printed with the joint aligned with the vertical axis had lots of layer “stepping” on the undersides, requiring more cleanup. Next time, I would make sure to align all the parts to have the joints flat on the print bed, meaning that any supports would go on flat parts rather than the rounded joints. This would probably result in cleaner prints, meaning less time spent sanding and filing.
Another mechanical change I would make is using fishing line instead of sewing thread. While I chose sewing thread out of necessity, it did break a few times during testing (as well as right before our presentation which was terrifying). It was also very hard to work with since it was so thin and would often unravel. Fishing line would be more durable, smoother, and a bit thicker and therefore easier to work with. I would also spend more time making sure that the holes for the threads that go through the wrist connection are smoother, or have more copper wire lining them to provide a smooth surface for the threads to slide over.
One final mechanical adjustment I would make is using larger servo motors with more rigid cams. Since we need to return these servos to the lab, I didn’t want to damage the provided servo arms at all, meaning the cams I made with them were relatively flimsy, being dependent on copper wire pressure fit through holes in the arms. Next time I would consider first doing the math to find the necessary travel distance for each thread, and then design 3D-printable cams. One of the downsides of copper wire on the cams was that the ends of the cams were a bit sharp, and if a thread slipped over the end of them it could sometimes break.
Electronic Improvements
One consistent issue faced with the electronics on this project was wires being disconnected. I didn’t want to solder to the MSP430’s pin headers for obvious reasons, so I used socketed jumper wires exclusively. However, these can sometimes be loose and come undone. In a future rendition of this project, I would use pin sockets soldered to perfboard. This way all socketed pins would be held together mechanically, greatly reducing the likelihood of them becoming disconnected.
Another change I would make to the electronics is adding decoupling caps to the servo board. Since the servos all share power rails from just two pins on the microcontroller, the voltage might sag a bit under higher load. The servos might also be introducing some noise to the power rails, which could be detrimental to the performance of future features such as analog to digital conversion. Decoupling caps would help make up for this, supplying current when the servos draw more current. I think a 100uF electrolytic cap for voltage sag, and a 0.1uF ceramic capacitor on each servo’s connector for noise would do the trick.
One final electronic adjustment that I would make is changing the input method for active mode. The buttons we used take a relatively high amount of force to actuate, making it slightly more difficult to use the hand. I would replace them with either buttons that take less force to press, or an analog input that senses finger position continuously rather than only detecting fully open or closed. This would take significant work changing hardware as well as software around, and I’m not entirely sure if the MSP430 has enough ADCs to accomplish this without some sort of multiplexing.
Code Improvements
I found our resulting code for this project to be deeply satisfactory, giving us the full functionality that we hoped to display. However, we did make some compromises for the sake of time.
One of these such sacrifices was eliminating gesture detection, which I think was a very cool feature concept that we could learn a lot from implementing. My thoughts for how this would be implemented would require a change in how fingers are opened and closed. Instead of having the IRQ handler directly call the finger closing functions, I would have it update a 5-bit binary number representing the states of each finger. This 5-bit binary number could then be used in a switch statement, with cases for various gestures such as a thumbs-up, ok-sign, etc.
Another change to the code that I would consider implementing relates to my ideas for the control input electronics – using flex sensors on a glove, pressure sensors, or potentiometers mounted on joints as an analog input for finger position. This would entail using the MSP430’s ADCs to convert the analog voltages to discrete digital values. I think that this could work well in the form of a 1D array of five finger position values. The values could then be converted to CCR values, and used in the finger up and finger down function calls. One benefit of this method is that gesture detection could still be implemented. The 1D 5 value array of finger positions could be checked against thresholds for “open” and “closed”, and this could be used to update a 5-bit binary representation of which fingers are closed. By doing this, the code would still be able to detect various gestures from continuous finger position inputs rather than just binary ones.

































