Introduction: Build a Robotic Arm for the Science Olympiad

About: My name is Daniel Kramnik - I like building Tesla coils, quadrotors, and robots!
For those who are struggling to find the right parts, trying to figure out how to put them together, or having difficulty with code, this is the right place! This instructable is a complete documentation of Newton South High School Science Team's 2012 robotic arm entry. It was built by Daniel Kramnik (myself) and Timothy Chong. We are 16 and 17 years old respectively, so I'd like this instructable to be considered for the student prizes in the robot challenge.

Here is a video of the arm in action at the state olympiad - first place!

Step 1: P.1, Plan: Control Structures

i. Manual

In this scheme, one or two pilots have direct control over every actuator in the entire system. This usually means a VEX remote with joysticks that are supposed to position a bunch of servos all at the same time. One competitor we saw had some sort of Lego or K'nex kit that allowed him to type in angles using a laptop with a bluetooth transmitter.

Although it's by far the easiest way to go about building a robotic arm, it also doesn't work very well, and is slow to control. At best, the people with VEX robots were able to place 2 - 3 objects (not the batteries though, since they were too heavy), and at worst, they placed none and wrecked the game board.

One team used this robotic arm kit, along with some very minor mechanical modifications (just enough for them not to get disqualified, though), but was unable to place a single object.

Advantages:
- Inexpensive and easy to assemble, if VEX or Lego parts are on hand
- Can be built the night before if you procrastinated
- No code
Disadvantages:
- Difficult to control and imprecise

ii. Automated, No Feedback

Why make a human pilot the arm when you can just preprogram a bunch of angle coordinates and gripper states for the arm to travel between? Because we know the locations of all of the objects on the game board beforehand, their locations can be hard-coded, and we can hope that the judges will set up their game board exactly to the correct specifications.

Advantages
- No user error
- Faster than fully manual control
- No GUI required
Disadvantages
- Will fail if the objects are not exactly at the preprogrammed locations, except for the nails, which can be picked up by an electromagnet that just needs to be close enough, but not precisely at their locations
- Significant coding (compared to zero) involved

iii. Automated, With Feedback

OK, in reality, the judges make mistakes - big enough mistakes for the arm to miss if you just hard code some coordinates. We found this out the hard way at regionals, although we did still win with an automated controller without feedback, placing the majority of the objects we intended to pick up.

One solution to this problem is to add sensors such as infrared sensors or ultrasonic sensors to try to determine where an object is. This would require much more code than any other alternative, and two-way communication between the computer and microcontroller, unless all of the code is on the chip.

Advantages
- Same as automated, without feedback
- Will not fail if the objects are positioned with some error
Disadvantages
- Requires expensive sensors
- Even more code, again it increases by a significant amount from the previous case

iv. A Compromise...

The simplest solution to the problem posed by the automated controller with no feedback is to add some basic user input options to adjust the position of the arm once it is about to pick up or place an object, not to add sensors. The arm cycles through hard-coded positions, waits for the user to use the arrow keys to make adjustments, and then continues. Essentially, the user provides feedback, instead of any sensors on the arm itself. This is what we did.

Advantages
- All of the advantages of a controller that is automated with feedback, but without the disadvantage of requiring sensors and a lot more code
Disadvantages
- You'll want to write a GUI for this (Picture 1), which is a bit more code

Step 2: P.1, Plan: Microcontroller and Circuit Assembly Considerations

Simply put, a microcontroller is a compact computer-on-a-chip with a CPU, memory, and a few or more internally-defined input and output ports, as well as other built-in peripherals such as timers or analog to digital converters.  Practically, a microcontroller allows a programmer to gain direct access to hardware from a higher-level language (than assembly), often based on C or C++. Examples include Atmel-C and the Arduino language. In other words, you can read and write digital signals to the IO pins, get or send analog signals using an ADC or DAC (if your controller has one), and access and modify internal timers, registers, and other hardware.

When prototyping, it is often inconvenient to build up the necessary support structure to run a microcontroller such as a clock generator, USB interface (not necessary, but useful if you want serial debugging or serial communication), or power supply, so a breakout board that includes these features is used instead. Arduino for the 8-bit Atmel AVR and mbed for 32-bit ARM are two examples.

i. Arduino

Arduino is by far the most popular and easiest to use microcontroller for do-it-yourself electronics. It comes with its own development tool that is available as a free download and the standard variant, Arduino Uno, can be programmed with a USB male type A to male type B cable (Picture 1).

In addition to being programmed through the USB cable, the Arduino can also send and receive serial data through this connection. Since managing simple serial input and output does not require the programmer to implement the USB protocol, it is much easier than what one might expect, serial.print and read on the Arduino’s end and popen/pclose on the computer's side (more on this later).

Other variants of the Arduino platform offer additional features that may be desirable: we chose to use the Arduino Mega 2560 (Picture 2) because it boasts the greatest amount of program space, number of IO ports, and number of extra hardware serial ports for future expansion. At the time I purchased the microcontroller, I hadn’t yet decided on a control scheme, so having as much program space as possible just in case I chose to implement everything (including inverse kinematics!) directly on the chip was a priority.

Which Arduino do I buy? How do I put together the robotic arm's circuitry?

One challenge you will face is in the actual physical construction of the robotic arm circuit – how do I connect the servos to the Arduino, the battery to the servos, etc.? The standard Arduino packages offer rows of female headers for sticking wires into, but this sort of rat’s nest style construction is hardly durable or easy to debug. The best alternative is to use an additional circuit board to connect all of the electrical components of the arm. A few options exist:

1. Cheat by buying an Arduino prototyping shield (I mention this first because it’s probably the best option)
An Arduino “shield” is any add-on circuit board that plugs into the top of the microcontroller. Examples include the SD Shield for reading or writing to flash memory cards, the LCD shield for interfacing with a display, and literally hundreds of others. Several different prototyping shields exist that are essentially just empty circuit boards with convenient connections to the Arduino’s pins. The robotic arm circuit can be assembled on one of these blank cards with a soldering iron and a handful of components (Picture 3).

2. Use a breadboard
A breadboard accommodates rapid prototyping of electronic circuits by allowing components to loosely press fit into interconnected rows and columns of headers. Some Arduino board such as the Arduino Nano (Picture 4) and Arduino Mini are equipped with rows of downward facing male headers instead of upward facing female headers, allowing them to plug into a breadboard like an integrated circuit DIP. This path is the easiest to choose in terms of design modification flexibility and experimentation – you are not forced to solder anything, but breadboards are prone to becoming rat’s nests. If you decide this is the best option, use an Arduino Nano, the Arduino Mini does not come with all of the hardware that you need in order to program or communicate with it via serial.

3. Make the breadboard permanent with a protoboard
A protoboard (Picture 5) is a blank fiberglass circuit board with predrilled holes and vias with standard (0.1”) component spacing, the same as on a breadboard. Protoboards allow you to make a breadboarded design permanent with solder, but also suffer from rat’s nesting problems. Never solder an Arduino directly onto a perfboard – use two parallel rows of female headers for a Nano to plug in to rather than sticking it through the board and soldering it. If you make a mistake that can’t be fixed, or if you want to install an upgrade, it’s both cheaper and easier to buy a new $3 protoboard than a $40 Arduino.

4. Etch your own circuit board (What we did)
Making a custom circuit board from scratch can be a difficult process, but is by far the best choice; there is little chance of human error during assembly and if the board is designed correctly, it will work the first time you power it on, 100% of the time (Picture 6). Making a circuit board from scratch requires Eagle CAD, a laser printer, photo paper, an iron (like, an actual iron, not a soldering iron), blank PCB material, and ferric chloride, most of these supplies can be bought at a local electronics hobby shop like “You-Do-It” Electronics, or online if you like to save money, but wait for shipping. There are other instructables that describe this process in detail.

ii. Other Options (for the more adventurous)

I only mention these to be complete -

If you find Arduino to be too expensive, or you want to etch one board that contains both the microcontroller and robotic arm circuitry, you can use a bare Atmega chip loaded with the Arduino bootloader, a crystal oscillator, and an FTDI converter chip for serial communication through USB. Alternately, if you don't need serial communication, a bare Atmega chip, or an Arduino Pro Mini, programmed using an FTDI adaptor cable would also work.

If you need more speed or memory than an Arduino or AVR can deliver, or a 32-bit processor (none of which were necessary for this project, I found), the mbed is a good alternative (Picture 7). It comes with a neat online compiler and development tool, "drag and drop" programming over USB, and tons of libraries that can easily be included in your project without a download - just point the online tool to the page on the mbed website with the library, and you're good to go. I have not tried to communicate with an mbed over serial, but I don't imagine it's too different than doing so with an Arduino. If you have the time and the budget, and plan to implement more than just a serial to servo bridge on the micro, the mbed is a good choice.

Where to buy: Sparkfun Electronics (http://www.sparkfun.com)
Recommended:
-Arduino Uno R3 (with a prototyping shield)
-Arduino Nano (with a breadboard or protoboard)
-Arduino Mega 2560 (with a custom-etched board, or in a case where the entire program will be on the micro) (What we did)

Step 3: P.1, Plan: Motors

Several very different possibilities exist for robotic arm motors:

i. DC Brushed

This is what most people think of as a “motor” (Picture 1) – it’s by far the cheapest, and by far the worst kind to use (in fact, I’d argue that it’s even impossible to use in this scenario). In the most primitive application, you apply power and it spins, uncontrollably. With a gearbox and a motor controller, it's possible to get more control, but a brushed motor on its own will never be able to hold a constant angular position, like we would want it to in a robotic arm. To solve this problem, we need to add feedback and a control loop – meet the servo.

ii. Servo (What we did)

This is the type of motor you'll want to use. In addition to a DC brushed motor, gearbox, and motor controller, a servo contains a feedback mechanism that allows you to set the motor's angular position rather than angular velocity using a pulse width modulated (PWM) signal generated by a microcontroller (Picture 2). Once you set a position, the servo will go to it and resist any outside force that attempts to move it. This is perfect for a robotic arm because it must hold the joints in place as it manipulates objects and go to particular angular coordinates in order to place them properly.

Servo “Scales”
When shopping for a servo, you'll notice them called all sorts of things - "standard", "quarter-scale", "micro", etc. What do those terms actually mean? Almost nothing, almost.

At best, the scale label tells you a range of sizes that the servo in question might fall under. For example, if you're shopping for the main servos that will drive the bottom and middle angle joints in your arm, you probably won't want micro or standard-sized servos. However, most servos under the same scale will not have the same dimensions! You must check the actual dimensions of each servo you look at to make sure they will fit your bracket. If you plan to machine brackets yourself, this is less of a problem, but still a major inconvenience if you find out that the thing you just machined is the wrong size.

Analog vs. Digital
Some servos will come labeled as analog servos with bipolar drive while others are digital with MOSFET drive – the difference refers to the internal PID and motor controller schemes. Both types of servos will respond in exactly the same way to external control signals, they just have different ways of doing it. I’ve found that in addition to being cheaper, analog servos are more tolerant to silly mistakes like being connected backward and being over-volted, while still having similar torque and speed characteristics. There is usually no reason to spend more for a digital servo.

If you buy non-Hitec servos, make sure to get the metal CNC machined horns Hobbyking sells (otherwise, get some metal horns from lynxmotion along with the frame) - plastic horns will strip. Note that Hobbyking brand servos use Futaba-style horns.

iii. Stepper
I mention stepper motors because they are often used in robotic arms (Picture 3), but I would recommend against it for this project. Stepper motors don't work like regular DC motors (apply power and go!), a stepper driver is required to spin the motor (each "step" is a different combination of internal electromagnets). Also, steppers motors have no feedback, so the entire system would suffer from the same problem as an inertial navigation system - if you make one small mistake, for example, if the torque exerted by the weight of the object at the end of the arm pushes a stepper back by a few steps, then the entire path afterwords will be incorrect. Errors will accumulate, and after some time, all of the preprogrammed coordinates will be completely off.

Steppers motors are perfect for driving something like a 3-axis positioning system on a 3D printer where the printing head doesn't exert any opposing force, but not so great when they encounter one. Also, using stepper motors will require more machining to get into an robotic arm, which is a problem considering the 1 - 2 month time during-school time constraint of this project.

Where to buy: Hobbyking RC (http://www.hobbyking.com)
Recommended:
Hitec HS805BB Quarter Scale Servo (2x for main drive)
Hitec HS645MG Standard Scale Servo (1x for gripper, 1x for grip angle, 1x for base rotation)

Step 4: P.1, Plan: Power Source

i. Alkaline

Everyone knows what an alkaline battery is. They’re everywhere, you can buy piles of them at CVS. Don’t.

ii. NiCd

In general, hobby aircraft parts will offer the best price and power density when compared to other electrical components. Several years ago, rechargeable Nickel-Cadmium, or NiCd batteries were the leading type among hobbyists and they can be purchased locally at RadioShack or at almost any other hobby shop. Unfortunately, there are a few reasons for why they’re no longer used; they’re much heavier than comparably spec’d Lithium batteries (although this doesn’t matter unless your arm has to fly), they can take up to several hours to charge with a standard trickle charger, and they degrade significantly over time. On top of that, they’re more expensive than hobbyist Lithium batteries because there’s little demand for such an inferior product. Avoid using a NiCd battery pack unless you have to.

iii. Lithium (LiFe, LiPo, etc.)

This type of battery is the best kind to use for basically any project. They're cheap (thanks to Hobbyking), light, support high-current discharge, and charge back up quickly. I would strongly recommend this type of cell. A 2-series (2S) pack is around the right voltage for a servo, 7.4V. The maximum that Hitecs are rated to is 6V, but I found that they work find up to around 10V (that's as high as I've had the courage to go). Some servos that Hobbyking sells are "high voltage" rated top 7.4V specifically to work with a 2S lipo pack. The "P" characteristic is the number of cells in parallel inside the pack - it's mostly unimportant for what we're doing.

Most important, other than the pack voltage, is the mAh rating - or miliamp-hours. What this rating says is "I can provide X milliamps for one hour before running out" - the more, the better, but the longer it takes to charge. I would gueest using a pair of ~2000mAh batteries so that you can test with one while charging the other and continuously switch back and forth.

Here's a good example of what I'm talking about. Find a higher C rating if you can, just to keep the battery a bit happier.

Battery connectors:

Several different types of battery connectors are common on hobby-grade lithium battery packs. XT60, Deans, and bullet-type connectors are a few. Hobbyking sells all of these for very low prices, just make sure you get the type that fits onto your lipo.

Where to buy: Hobbyking RC (http://www.hobbyking.com)
Recommended:
A pair of 2S (7.4V) LiPo packs with at least 2000mAh capacity each
Genuine iMax B8+ Universal Charger

12V @ 10A Power Supply

Step 5: P.1, Plan: Frame and Mechanics

If you're more electrically than mechanically-inclined like me, then assembling a frame for your robot will probably be the most daunting part of this project. Even though I do have some machine shop skills and access, with the competition's time constraint, I decided it would be best to focus on what I'm best at, electronics and code, and find an easy way to get the actual arm together.

Luckily for us, lynxmotion exists!

Their servo erector set parts include everything we need to put together a simple, straightforward mechanical backbone to out arm. Note that the servo brackets and metal horns will only fit Hitec servos, but this can be changed with a little bit of machining to suit almost anything you find on Hobbyking.

Take a look at the bill of materials I've included in the last step to see which parts we bought, and adjust according to your needs. The main types of parts you'll be buying are servo brackets, C brackets, aluminum tubes, tube end connectors, and metal servo horns.

The result looks something like (Picture 1).

As for the gripper, two options exist - I say got for both!

i. Electromagnet

An electromagnet uses an electric current (see: Biot-Savart Law) to induce a megnetic field that can then be used to pick up metal objects, such as the nails and batteries in the competition area. It is generally easier to get working than the mechanical gripper, but needs to be wound by hand on a laminated core from something like an AC induction motor from a microwave fan in order to work effectively. Sloppily winding an electromagnet on an iron nail might work for picking up the nails, but won't do for something as heavy as the batteries.

ii. Mechanical Gripper

A mechanical gripper usually uses another servo motor to open and close a set of jaws that pick up an object. The lynxmotion little gripper is good for our arm, and is compatible with the rest of the lynxmotion erector set.

Where to buy: Lynxmotion Robotics (http://www.lynxmotion.com/)
Recommended:
Servo Erector Set Parts (See BOM)
Little Grip Set


Also get (for the electromagnet):
AC Induction Motor from Microwave Oven
28 Gauge Enameled Wire

Step 6: P.2, Build: Assemble the Frame

I won't go into assembling the actual arm in much detail, seeing as the Lynxmotion parts come with their own assembly guide, and exact assembly will depend on the parts you choose, however, you'll need to make your own L-bracket adapter out of aluminum if you plan to use both an electromagnet and a mechanical gripper.

I machined my adapter out of a section of rectangular aluminum channel (Pictures 2 & 3). In my opinion, it's better to start with a square channel because it's easier to get into the mill, and offers you another chance if you accidentally derp a side. Once drilling and tapping was complete, I used a bandsaw to cut off the half of the rectangle that I didn't need.

(Picture 1) shows the position of this bracket inside of the robotic arm gripper - the end rotation servo is responsible for switching between the two and the two sets of tapped holes are standard lynxmotion connector-spaced.

You'll also want some sort of base to secure the arm, microcontroller, and battery to. I cut a 30 x 30cm maximum base dimension-sized piece of 1/4" acrylic, bolted on the base of the arm, secured the electronics with double-sided tape, and added tape-on rubber feet at its four corners to keep it steady.

Step 7: P.2, Build: Wind an Electromagnet, the Right Way

This isn't going to be the demo you saw in kindergarten that picks up paper clips! No, we need a real electromagnet for robotic arm.

Start by liberating the core (Picture 2) holding the windings in an AC induction motor - almost any microwave oven will contain a fan driven by such a motor (Picture 1). Be careful with disassembly - Plasmana's instructable shows you how it's done.

When dremeling, always wear safety eyewear, and use a vice if you can (less chance of injuring or killing yourself).

Once the core containing the windings has been removed, we rip them off and replace them with our own. Note that in addition to wrecking the induction motor's frame, the dremel is also a good tool for ruining the windings.

The reason we use such a core is to avoid saturation, which is common in electromagnets that are wound around nails.

Pick any direction (CW or CCW, it doesn't matter) and start winding 28 gauge magnet wire from the side of the electromagnet that will be attached to the end of the arm. My core had a C on one side that made it convenient for zip typing to the end of the arm.

Once you've wound a layer, tape it over (Picture 3) and run the wire all the way back to the other side (Picture 4). Continue this process until no more layers fit on the core, or until you feel the magnet is strong enough. Be sure you always wind in the same direction! You can test the magnet's strength by sanding off a small section of wire (without cutting the wire) on the side you're winding, and then running some current through it. If you're using a high discharge Lipo battery, you may want to add a current-limiting resistor. With the core and number of windings I had, I found that my battery was able to source enough current without becoming sad.

Once the winding is complete, cut the magnet from the roll of enameled wire, strip the ends, solder them to long wires that will go down the arm back to the controller, and apply electrical tape or heatshrink to insulate the contacts. Finally, twist the wires together for durability and neatness (Picture 5).

Step 8: P.2, Build: Solder Electronics

Because I didn't know what sort of battery we'd end up using, I designed a linear regulator based around a random opamp I found and an IRFZ24 MOSFET from my collection of coiling supplies as a pass transistor, and etched a board (Picture 5). Neither is necessary (although you won't want to exceed the servos' voltage rating too much - see (Picture 4)) - the only important parts are the servo headers and electromagnet on/off MOSFET and gate driver.

The gate driver helps because we get Vbattery gate voltage instead of 5V, from an Arduino pin. If you're running a 2S Lipo, this won't be enough to matter. If you're running 3S and regulating it down (as we did at some point), it could help. The gate driver is available as a free same from TI, and is also everyone's favorite Tesla coil part!

If you feel inclined to etch a board, I've included everything short of the actual Eagle files - you can get a 600 DPI black and white image of the bottom layer ready to print from (Picture 3).

Since we will be talking to the Arduino via serial, the computer can power the microcontroller via USB. Remember, when securing the microcontroller and battery to the base, double-sided tape is your friend!

Once everything is soldered, taped, and ready to go, run servo extension cables from the servos on the arm down to the board and plug them in to the appropriate headers.

WARNING! Do not plug anything in backwards - I reversed the battery leads the first time I soldered them, and this resulted in about $100 of dead servos!

This is another good reason to keep the Arduino powered through the USB port - it lets us detach it from any mistakes in the battery wiring.

Step 9: P.3, Code: Implement Serial Communication

Now you have a robotic arm - it's time to write the code.

For the purposes of this tutorial, I will assume that you chose to use an Arduino with the capability of serial communication over USB (so, not an Arduino Pro Mini or bare Atmega chip) and that you will use C, C++, or another C-based language such as Objective-C (What we did) on the computer's side for controlling the arm. I will also assume that you are using a UNIX-based operating system such as OSX (What we did) or linux. The code for sending serial transmissions is different on windows - you can still follow along with the rest of the tutorial, but you'll have to make changes to a few lines of code (I'm referring to popen and pclose, which don't work on windows as far as I know - I could be wrong).

The goal of your entire software package will be to determine a set of coordinates and gripper states (mainly, on or off) for the arm to cycle through to pick and place the objects on the board, and then to send these coordinates as a stream of servo angles to the Arduino, which will translate this information into servo PWM pulses. Because the locations of all of the objects are known before the competition, the locations will be hard-coded, with the option of adjusting them slightly during the three minute run in order to account for slight variations in the game board.

So let's get started!

The first task is to write some basic code that will take user input from the console and send it to the Arduino. The microcontroller will then respond by setting the angle of a servo to the user input. Error checking the user input is not necessary at this point since we can assume that ultimately, the hard-coded servo angle locations will not have errors, and that any user input will be done through a GUI that won't suffer from errors if the user mashes on random keys in the console... because there won't be a console.

In C, popen is used to access system commands, much like one would do using the command line. Sending data to the Arduino would look something like this on the computer's side (in Objective-C):

...in the .h file:

(in the @interface declaration)

NSString * serialPort;

...in the .m file:

(in the init method)

serialPort = [[NSString alloc] initWithString: @"/dev/tty.usbmodemfd121"];

... some code ...

(in the transmit method)

NSString * str = [NSString stringWithFormat:@"echo %@ > %@", toBeSent, serialPort];
char * toSend  = [str UTF8String];

FILE * sender = popen(toSend, "r");
pclose(sender);


These lines of code would transmit the string toBeSent to the Arduino on serial port /dev/tty.usbmodemfd121.

To find the serial port that your Arduino sits on, all you need to do is plug it in, and look at the name that appears under Tools > Serial Port in the Arduino code tool. You'll want to make sure that you plug your Arduino into the same USB port for this to stay the same.

The task of retrieving numerical input from the console and sending it through serial is left to the reader.... unless you want to cheat by taking a look at the sample code I included. If you build and run it with Xcode, and type in numbers between 0 and 176 (the limits of the particular servo we were testing with), it should yield the same output as the picture at the top:

sh: /dev/tty.usbmodemfd121: Permission denied

That doesn't look good! It does, however, tell us that the echo command is being successfully called, but that there is no "/dev/tty.usbmodemfd121". To fix this, we need to connect an Arduino.

Step 10: P.3, Code: Talking to a Servo

So now you're transmitting! The next step is to receive.

Start serial communications in the Arduino's setup() function at baud rate 9600 (bits per seconds):

Serial.begin(9600);

I usually print out a message at the end of the setup() function to confirm that the Arduino is working and ready to start getting serial input:

Serial.println("I work!");

Now, in the main loop, we want to wait until 3 characters (bytes) have been received, the Serial.available() function tells us how many bytes are in the buffer, so we poll it until the value reaches 3:

if (Serial.available() == 3) {
     ... some code ...
}


To read bytes out of the buffer, we use Serial.read(), which also clears the read byte out of the buffer. Since we're receiving 3 bytes, this means 3 calls to Serial.read(). Each byte represents a digit encoded in ASCIITake a look at this website: http://www.asciitable.com/

Notice anything about where 0, 1, 2... are? That's right! They start at 48, 49, 50...! That means you need to subtract 48 from the ASCII value to get the transmitted digit. (Thank us for this, because we were stumped for about a day, until scolton explained it)

The buffer is FIFO (first in first out), so we read the hundreds digit first, the tens second, and the ones last (the same order as they were transmitted):

angle =  (Serial.read() - 48) * 100;
angle += (Serial.read() - 48) * 10;
angle += (Serial.read() - 48);


Now, we want to write that angle to a servo - import the servo library:

#include <Servo.h>

Declare a servo object before the setup method (this is also where you declare the angle, which should be an integer, or a volatile short if you're pedantic =P):

Servo myServo;

Finally, write the received angle inside of the Serial.available() if-statement:

myServo.write(angle);

If you followed along the last step (or compiled the example), you should have a console-based servo controller ready to go!

Here's a video of us testing the entire system. The scope is monitoring the servo PWM waveform, and Tim is entering numbers between 0 and 176 on the Mac's console, and the Arduino is setting the angle of a servo:



Youtube video description:

"A command line tool written in Objective-C to control the position of a servo motor using serial interface and an Arduino Mega 2560 - the first step in my robotic arm project."

I've attached a copy of the Arduino-side code so you can test both the transmitter and receiver. The hardware is pretty straightforward, connect a servo's signal lead to the Arduino Mega's pin 50 (you can change this), connect the ground pin to the Arduino's ground, and connect +5V to an external power supply with, its ground also connected to the Arduino's ground. It's imperative that you use an external power supply as the currents drawn by a servo can cause the Arduino to brownout or behave erratically.

Step 11: P.3, Code: Talking to More Servos

Is one servo not enough for you? Of course not, we're building a robotic arm here!

In addition to transmitting an angle, we also send one number to select which servo (or gripper) to write to. Note that the code is no longer designed to receive an angle and write that angle to the servos, but is instead modified to read a number in microseconds to write to that servo. This is done because some servos do not use standard 1000uS  - 2000uS angle encoding, and it's easier to let the computer-side code sort this out and do any necessary calculations.

In code, we wait for a few more bytes in Serial.available() than before, and then use a switch statement to figure out what to do once input has been received:

switch (servoSelect) {
          case 0:
            baseRotate.writeMicroseconds(uS);
            break;
          case 1:
            bottomArm.writeMicroseconds(uS);
            break;
          case 2:
            middleArm.writeMicroseconds(uS);
            break;
          case 3:
            endArm.writeMicroseconds(uS);
            break;
          case 4:
            if(uS == 0) {digitalWrite(magnetPin, HIGH);}
            else            {digitalWrite(magnetPin, LOW);}
            break;
          case 5:
            grip.writeMicroseconds(uS);
            break;
          default:
            break;
}


Cases 0 - 3 are pretty straightforward - they individually address each of the angle-positioning servos in the arm. Case 4 is the electromagnet, which is turned on only if the microseconds input is nonzero (it's value apart from the distinction is irrelevant), and Case 5 is the end gripper.

Here is an example video of the arm under full manual command demonstrating that each of the servos responds to user input in the GUI. At the end, I run a short, preprogrammed sequence of coordinates to show that this functionality works too. Note that the arm oscillates after reaching each destination because it still has lots of left over kinetic energy from the motion. This issue is addressed in the next step.


Youtube video description:

"Testing the basic functionality of our objective-c software with the robotic arm minus gripper. The laptop communicates with an Arduino Mega via USB and sends commands to 4 servos and 1 on/off MOSFET switch the will control the gripper. The expansion board sitting on the Arduino is a shield I designed and etched with a high current voltage regulator (opamp + pass transistor) and MOSFET with UCC37322 gate driver.

We are currently working on an algorithm that will gradually slow the servos down as they approach their targets to prevent unwanted oscillations (it's like the difference between pushing a harmonic oscillator to zero with a linear motion versus decaying exponential motion, it won't want to keep going in the latter case)."

Step 12: P.3, Code: Inverse Kinematics and Other Code Bits

Short of manually trying to figure out the exact angles required to bring the arm to each location, inverse kinematics are the only way of figuring out how to position the servos to bring the arm to a desired location. The math is high school-level trigonometry, so I won't cover it here; several helpful online calculators exist.

At first, we considered including inverse kinematic calculations in our Objective-C code, but this turned out to be a bad idea because there are lots of calculations to do at initialization, and after they're done once, there's no need to repeat them again. After all, the fact that the objects don't move around is the basis of our control scheme. Instead, we hard-code angles.

One very important piece of code is a method that will slow down the arm as it approaches its destination, instead of shoving it all the way and hoping it doesn't start oscillating (maybe in an ideal world with ideal servos).

First, we pause execution for a small amount of time to allow the servo to move to the angle we give them (the first time this method is called, the servo will not yet be in motion):

[NSThread sleepForTimeInterval:0.03];

Next, we compare the servo's current angular position to the desired end position - if it's close enough (which we defined to be 2 degrees), then set the variable that stores the current angle equal to the desired end position (you'll see why this makes sense in a moment):

if(abs(targetAngle - angle) <= 2) {angle = targetAngle;}

Now, compute one tenth the difference between the current angle and the target angle - if the current angle is equal to the target angle, this will return zero:

double diff = (targetAngle - angle) * 0.1;

Now, move the servo to the current angular position plus one tenth the difference - if the current angle is equal to the target angle, this will cause the servo to move all the way to the target angle:

[self moveActualTo:(angle + diff)];

See the video description below to get a better understanding of how any why this is done. You can find this code in the calculateChange method in Motor.m, which is attached as part of a zip file in the next step.

The first version of our code only used the electromagnet (this is what we took to regionals - the video was taken around 6AM the day of, after an all-nighter getting it to work!) and looked something like this:



Youtube video description:

"This is the first full test of our robotic arm for the Massachusetts Science Olympiad. We had one of the coordinates wrong in our program (yes, it turned out to be a software problem - much better than a random "MOSFET doesn't turn on" glitch!), so it failed to pick up one of the nails, but we got it fixed in time for the regional event later that day and won first place by a landslide!

One of the troubles we had earlier (and that many of the teams had at regionals) was oscillating servos and servos that move too fast and swing the arm in unpredictable paths. To fix this, we wrote an algorithm that slows down the servos as they approach their final destinations by giving them a continuous stream of coordinates that are exponentially closer and closer to the target angle until the servo is within some delta, usually one or two degrees, of this angle and close enough to just go straight there. Each iteration is calculated by finding one tenth of the angle that the servo still needs to travel in order to complete the step. Instead of using recursion to have the angle-calculating method call itself until the step is complete, which is the obvious choice, we used an NSTimer in its own thread to avoid having to add delays to our program to keep the calculations up with the servos (the servos move much slower than the computer can spit out angles).

The reason we use exponential decay rather than just slowed down linear motion is that the arm essentially acts as a damped harmonic oscillator (if we assume the proportional term in the servo's internal PID controller dominates around the set point, which seems to fit what I observed when the arm was oscillating), so if we drive it linearly, it will start out with some initial kinetic energy once it's at the destination and oscillate around it rather than come to a stop. The only solution (if we insist on driving it linearly) is to slow the arm down to reduce the amplitude of the oscillation until we consider it acceptable, which is not desirable when one considers that this is a timed competition. Instead, if we force it to the next angle with in an exponentially decaying pattern, it should arrive there with very little kinetic energy, with error caused only by the fact that we are giving it discrete data.

Each position that the servos need to reach is calculated using inverse kinematics and then individually adjusted using our program's manual mode to be as correct as possible. One of the things we are working on for states next month is real time inverse kinematic control that will allow us to move the arm's end effector in any precise path that we choose, rather than just moving the servos to each angle one at a time like we do now.

Even though we only have an electromagnet, and not a universal gripper or claw, with which to pick up objects (thus forcing us to leave half of the game board untouched), automatic control means that this arm is able to pick up objects quickly and with no human error, so we successfully place 100% of the objects we aim to place every time we run the arm."

Step 13: P.3, Code: Complete Objective-C Software Overview

I've included code for our entire Cocoa application (credit for this goes to Tim, as he is responsible for extending the console-based servo controller into a complete application) in a .zip file - unarchive it, open with Xcode, and you're good to go!

The state diagram (you'll want to look at the full-sized file, click the i in the top left corner) I drew should explain everything that's going on in enough detail for the structure of out code to make sense. Even if you don't work in Objective-C, the diagram is a good guide.

As was discussed in previous steps, the program waits for the user to tell it to begin, then moves to the next position, applying a lowpass filter on the motor angles so the arm doesn't oscillate, then waits for the user to make corrections if necessary, and finally starts the process again for the next stored set of coordinates.

Note that stored sets of coordinates don't only include the locations of the objects and goal boxes, but also intermediate locations so that the arm picks up objects vertically, and doesn't crash into things it's not supposed to hit.

(Yes, it's supposed to be called "Roboticcccccc" - we made an error when creating the project, and never really bothered to fix it... Again, tracking down and renaming all the files you need to rename is a good exercise if you're pedantic =P)

Step 14: P.0: Ultimate BOM

Attached as a reference is a complete materials list, but hopefully not so that you go out and copy us verbatim!

Robot Challenge

Participated in the
Robot Challenge