profmason.com

May 22, 2013

Robotic Light Saber Battle using the CM900

Filed under: Daily — profmason @ 3:42 am

For makerfaire I wanted to make an impressive exhibit that kids would have a great time playing with.  After some brainstorming with a past student and one of the Robotis team, we decided to build a pair of Wii nun-chuk controlled robot arms that would wield light sabers.

A picture of the first revision is shown at right.  All parts are available from Trossen Robotics in the US or Robosavvy in the Europe.  Here is a break down of what was used in revision 1 of the build:

  • CM-900 microcontroller  $20
  • 4 AX-12+ Dynamixel Servos $180
  • 2x Bioloid Frame F8   $4
  • 2x Bioloid Frame F3  $3
  • 1x Bioloid Frame F4 $2
  • 1x Bioloid Frame F1 $2
  • 4x Bioloid Frame F10 $5
  • 1x Bioloid Frame F2 $2
  • 12″ x 12″ piece of MDF $2
  • Misc screws etc.
  • Light saber (I will look up the model but ~$20)

The entire build is about $250 in this configuration.

Click on the picture at right to see how the parts were assembled.  The light saber was held on with two zip-ties through the F1 bracket and this provided a surprisingly secure mounting.   The MDF plate was fabricated by cutting to size, rounding the edges with a belt sander and then routing a 1cm slot in the middle to serve as a wire tray. The lower F8 bracket was screwed to the MDF plate using small wood screws.  Art work was a collaboration with my nine year old daughter.    This design was tested extensively as can be seen in the video below:

While revision 1 did a good job of moving the light saber around, there were two flaws.  First the upper F8 bracket was only attached by two screws.  These worked themselves out during testing.  Second the bottom servo was carrying a tremendous amount of torque from the entire arm assembly.  Four solutions were discussed.

  1. Use double AX-12 servos to replace the single AX-12 bottom Pivot.
  2.  Reverse the geometry of the arm so that the lightsaber would be better balanced over the center of the arm.
  3. Pre-load the arm with springs.
  4. Replace the AX-12 servo with a higher end RX servo.

Due to time constraints we implemented 2 and 4.  This resulted in the final design shown at right. This design also allowed us to prove that AX and RX servos could be integrated on the same bus with the CM-900.  This integration worked flawlessly.

The lightsabers ran through two days of makerfaire with hundreds of kids having mock lightsaber battles.  A game was proposed that grew in depth as the event progressed.

Initially it was proposed that each side would have an animal army.  The light saber wielder who could knock their opponents animals to the floor while protecting their own animal army would be declared the victor.  The picture below shows a lightsaber with its animal army arrayed at the ready.

A second light saber was built up that was identical to the first and they were tested at the Robotics Society of Southern California(RSSC) meeting on Saturday,  May 11th.  Below is an excerpt from the first demo featuring a battle between two RSSC members.

Finally, we took both sabers to maker faire and let the kids at it.  Here is a short video of one of the many battles that took place over two days.

Below is the CM-900 Code for the project:

*
* Robotic Light Sabers
* http://www.profmason.com
* Be sure to pull up your two I2C ports with ~2K resistors to the 3.3V line.
 * By default using the pins 14 and 15 for SDA and SCL.
 */
#define uint8_t int
#define SHOULDERPIVOT 6  //These are the servos used in the Arm
#define SHOULDERANGLE 1
#define ELBOW 4
#define WRIST 9
#include "Wire.h"
#include "WiiChuk.h"

WiiChuck chuck = WiiChuck();

void setup() {
  SerialUSB.begin();
  chuck.begin(14,15);  //Specify SDA, SCL for this nunchuck
  chuck.update();
  chuck.calibrateJoy();
  Dxl.begin(1);
  delay(100);
  setServoPos(SHOULDERPIVOT,512,400);
  setServoPos(SHOULDERANGLE,480,400);
  setServoPos(ELBOW,312,400);
  setServoPos(WRIST,512,400);
}

void waitForComplete()
{
  while(chuck.buttonC)
  {
  chuck.update();
  delay(20);
  }

}

void slashRight()
{
  setServoPos(SHOULDERPIVOT,312,400);
  setServoPos(SHOULDERANGLE,480,400);
  setServoPos(ELBOW,312,400);
  setServoPos(WRIST,312,400);
  waitForComplete();
  setServoPos(SHOULDERPIVOT,512,400);
  setServoPos(SHOULDERANGLE,500,400);
  setServoPos(ELBOW,412,400);
  setServoPos(WRIST,512,400);
  waitForComplete();
}

void slashLeft()
{
  setServoPos(SHOULDERPIVOT,712,400);
  setServoPos(SHOULDERANGLE,480,400);
  setServoPos(ELBOW,312,400);
  setServoPos(WRIST,712,400);
  waitForComplete();
  setServoPos(SHOULDERPIVOT,512,400);
  setServoPos(SHOULDERANGLE,500,400);
  setServoPos(ELBOW,412,400);
  setServoPos(WRIST,512,400);
  waitForComplete();
}

void loop() {
  delay(20);
  chuck.update();  //Update the values from the nunchuk
  if (chuck.buttonC)  //If the top button is pressed check for a special combo move
  {
    if (chuck.readJoyX()>100)  //If the joystick is pressed to the right execute slash right combo
    {
    slashRight();
    }
    else if (chuck.readJoyX()    {
    slashLeft();
    }
  }
  else
  {
  if (chuck.buttonZ) //If the lower button is pressed, move the lower shoulder pivot
  {
    setServoPos(SHOULDERPIVOT,512+2*chuck.readJoyX(),250);
  }
  else{  //Else move the wrist pivot
    setServoPos(WRIST,512-2*chuck.readJoyX(),250);
  }
  setServoPos(ELBOW,300-chuck.readJoyY()/2,250);
  int shoulderOut = 500+chuck.readJoyY()*1.5;
  if (shoulderOut  {
  shoulderOut =400;
  }
  setServoPos(SHOULDERANGLE,shoulderOut,250);
  }
}

void setServoPos( short servo, int position, int speed ){
  Dxl.writeWord( servo, 30, position );
  Dxl.writeWord( servo, 32, speed );
}

void testNunChuk()
{
  SerialUSB.print(chuck.readJoyX());
  SerialUSB.print(", ");
  SerialUSB.print(chuck.readJoyY());
  SerialUSB.print(", ");

  if (chuck.buttonZ) {
    SerialUSB.print("1");
  }
  else  {
    SerialUSB.print("0");
  }

  SerialUSB.print(", ");

  if (chuck.buttonC) {
    SerialUSB.print("1");
  }
  else  {
    SerialUSB.print("0");
  }

  SerialUSB.println();
}

All in all this was a great project. The major problems we had were in overheating in one of the CM900 engineering sample boards.  I had used an engineering sample as it already had the header pins soldered in.  This particular board had some problems that led to intermittent problems with the I2C interface with the nunchuk.  The lightsaber built with the release board ran successfully and logged at least 8 hours of continual use driving servos in a very rigorous fashion.  The other point of failure was the upper F8 bracket which we had noticed during the design phase.  We ended up breaking two of these brackets during the competition.  We found that there were some minor servo heating issues, which required us to shutdown the arms every 10 to 15 minutes, but these were welcome breaks for the makers running the exhibit as well.
Thank you to Robotis for making this project possible!

April 28, 2013

Grippers + CM900 makes for easy integration

Filed under: Daily — profmason @ 10:25 pm

I admired the Robophilo grippers at the last robogames and ordered a pair from http://robobrothers.com/ when I arrived back in town.  They came in just a couple of days.  They screwed on to the standard Robotis brackets easily using a pair of 2mmx4mm self tapping screws.  (The hole pattern is close, but not exactly the same.)  If you have access to a drill press or dremel you will want to drill starter holes is the gripper using the Robotis bracket as a template.

The robophilo grippers use standard hobby servo grippers, but give you wrist rotation and a good range of gripping in a very small package.  Interfacing standard hobby servos with Dynamixel boards used to be a chore, but now with the CM900, life is easy.  Simply download the servo library, and connect your servos to the CM900 digital pins.

I connected the servos as follows:

  • Pin 6 Left Wrist
  • Pin 7 Left Gripper
  • Pin 8 Right Gripper
  • Pin 10 Right Right Wrist
  • 5V to Servo Power
  • Ground to Ground

To make things easier, you might want to make a little breakout board like that pictured at right.

This allows you to plug the 4 servos (2 from each arm) into the board and bring the signal pins out to the digital pins on the CM900. Using a separate board also lets you bring out Power and Ground separately.    The 5V regulator built into the CM900 board will supply 500 mA, which is enough to run one servo.  However, if you try to run multiple servos off the regulator, you will brown out the board and cause it to reset.  In addition, the poor little 78M05G is  dropping 7V at 500mA (3.5W) the thermal management on the board is not sufficient to do this for long!

To make a long story short, using an external supply for the servos is a good idea, so I used a simple LM2596 variable switch mode supply set at 6V to supply power to the servos.  I added a second ground wire in blue so that I could connect the grounds if using a completely separate supply.   I understand that Robotis used a Linear regulator instead of a switch mode on the 5 and 3V supplies to make the low price point for this board.

At right is a shot of the 4 servos, plus power and ground plugged into a very heavily used CM900 board.

Here is some quick code to open and close the Grippers.

#include <Servo.h>
#define RIGHTGRIPPEROPEN 135
#define RIGHTGRIPPERCLOSE 65
#define LEFTGRIPPEROPEN 135
#define LEFTGRIPPERCLOSE 65
Servo leftGripServo;
Servo leftWristServo;
Servo rightGripServo;
Servo rightWristServo;

void setup()
{
  leftGripServo.attach(7);  // attaches the servo on pin 20 to the servo object
  leftWristServo.attach(6);
  rightGripServo.attach(8);  // attaches the servo on pin 20 to the servo object
  rightWristServo.attach(10);
  delay(100);
  rightGripServo.write(90);
  leftGripServo.write(90);
  rightWristServo.write(80);
  leftWristServo.write(100);
}

void openRightGripper()
{
  rightGripServo.write(RIGHTGRIPPEROPEN);
}

void openLeftGripper()
{
  leftGripServo.write(LEFTGRIPPEROPEN);
}

void closeRightGripper()
{
  rightGripServo.write(RIGHTGRIPPERCLOSE);
}

void closeLeftGripper()
{
  leftGripServo.write(LEFTGRIPPERCLOSE);
}

void loop()
{
  openRightGripper();
  delay(1000);
  closeRightGripper();
  delay(1000);
  openLeftGripper();
  delay(1000);
  closeLeftGripper();
  delay(1000);
}

April 26, 2013

CM-900 Library: Ultrasonic Distance Sensor

Filed under: Daily — profmason @ 3:15 am

Starting with the Parallax Ping and MaxSonar sensor, and moving to modern inexpensive copies such as the HC-SR04, ultrasonic distance sensors have been a mainstay of personal robotics.  These sensors use time of flight calculations based on emitting a sharp ultrasonic pulse (typically at 40Khz) and timing the return pulse, very much like how a bat echo locates.   Since these pulses travel at the speed of sound (roughly 343 m/s), an object at 1m will return a reflection in 2 m / 343 m/s = 5830 microseconds.  Obtaining resolution on the order of 5ms is straightforward on modern microcontrollers which yields a resolution of better then 2 mm.   These sensors are relatively noise immune as each piezo element acts as a tight band pass filter.

A sensor is connected to the CM900 as follows:

  • Connect VCC of the sensor to 5.0V
  • Connect GND to Ground
  • Connect Trig to any digital pin (Pin 8 in the example)
  • Connect Echo to any other digital pin (Pin 7 in the example)

This library is used a follows:

#include <Ultrasonic.h>  //This includes the library and all necessary functions.

Create an instance of an ultrasonic sensor as:

Ultrasonic leftSensor(8,7); // The first number specifies the Trigger port and the second number specifies the echo pin.

Use the single method:

leftSensor.readDistance()  //This returns the distance detected by the sensor in cm.  Again do not call more then every 10ms.

Download the library here.  UltrasonicRanger

Anyone who is a c++ wizard and can fix how I hacked attaching the interrupts in the class is strongly encouraged to make changes as needed.

April 24, 2013

Using Neato LIDAR with your embedded board.

Filed under: Daily — profmason @ 4:36 am

The Neato LIDAR is the basic sensor of the NEATO XV11 and other NEATO home robotic vacuums.  These are true robots in the sense that they sense their environment and react to it.  The NEATO uses a high resolution line scanner coupled with an IR laser to generate distances based on triangulation.

First you need to interface your LIDAR to your embedded board.  You will need the following:

  • USB to TTL converter.  I recommend the CP2102
  • A clean 3V power supply.  I used an inexpensive LM2596 switch mode board.  I could power it off the 5V rail from the CP2102, but this caused substantial problems with the USB bus.  A separate power supply is recommended.   See the note about powering the board at the bottom.

Attach the wires from the 4 wire connector on your  LIDAR to the CP2102 as below:

  • 3.3V to Red
  • Ground to Black
  • RXD to Orange
  • TXD to Brown

At this point, test your connection before doing anything else.    Open up your favorite terminal program.  Create a connection at 115200 8N1 to the port that your CP2102 is plugged in to.  Now power cycle the LIDAR by plugging and unplugging the +3.3V pin.  You should observe the following.

#:)
Piccolo Laser Distance Scanner
Copyright (c) 2009-2011 Neato Robotics, Inc.
All Rights Reserved

Loader  V2.5.15295
CPU     F2802x/c001
Serial  KSH44612AA-0076598
LastCal [5371726C]
Runtime V2.6.15295
#

This means that you have a good connections to your LIDAR.  Now spin the LIDAR slowly with your finger.  You should observe “#Spin…3 ESCs or BREAK to abort…” followed by a large amount of garbage.  This means that on Spinning the LIDAR is returning data.

Now attach your 3V power supply to the two wire connector such that Red is + and Black is -.  Your LIDAR should immediately start to spin and data should fill the terminal.  This is non-human readable.

Download and unzip the python program lidar.

This program is based on the work done by Nicolas “Xevel” Saugnier.

Close the terminal and open up the Python program in IDLE.  Be sure that you have installed vpython and pyserial. To make calibration easier, place the unit in large (40cm x 40cm) box.  In the program change the com_port variable to match that of the com port of your CP2102.

Run the program.  It should report the RPM of your LIDAR (around 300) and show and image of the current environment.  A sample image of the unit in a box is shown at right.

You may need to rotate the display by pressing and holding the right mouse button while dragging.

As you zoom out (scroll wheel) you will observe the measurement shown below with the quality of the returned measure indicated as yellow dots.  The farther the yellow dot, the better the quality of the measurement.

In the program you can set Visualization to False and it will just populate the lidarData list with the current distances and qualities as a function of angle in 1 degree increments. IE lidarData[0] corresponds to the values at an angle of 0.

Note:  Powering the Neato LIDAR.  By default, the board uses a 12V pulse width modulated power supply with an approximately 25% duty cycle giving a nominal voltage of 3V.  The LIDAR will run between about 2.4V and 3.8V while providing good data.  If you have 3.3V at 200mA or so, then you can run power the LIDAR directly from that.

Notes about Range:

Based on tests performed by Mt. SAC students, the LIDAR performs reliably to 15 feet indoors and 10 feet outdoors.

 

 

CM900: Sharp GDP IR distance Sensor Library

Filed under: Daily — profmason @ 1:42 am

The Sharp GDP series of IR sensors are an easy to implement solution for distance measurement out to 1.5 meters depending on sensor selection.  The sensors emit an infrared pulse and then measure the angular deviation of the reflected pulse with a high precision linear array to determine distance. The sensors typically return an Analog Value which can be processed to return a distance.

To use:

  • Connect VCC of the Sharp GDP sensor to 5.0V
  • Connect GND to Ground
  • Connect Signal to any Analog Pin

Unzip the attached file into your Libraries director, reload your CM9 IDE and choose “Examples” -> “SharpIR” -> “SharpIRdemo”

Include the SharpIR sensor using #include <SharpIR.h>

Declare an instance of the class and specify what pin it is connected to.

SharpIR leftSensor(5)

Available Functions:

  • readDistanceMM //Returns the distance to the closest object in MM.  If there is an object closer then 8cm then the reading will be unreliable.
  • isCloser(Threshold) //Returns true if there is an object within the distance Threshold
  • isFarther(Threshold) //Return true if there is an object beyond the distance Threshold

The library is available for download here:  SharpIR

Older Posts »

Powered by WordPress