Saturday, August 25, 2012

Drew's Rostock: Drive Axis

The Rostock style 3D printer differs from more conventional designs in having three identical drive axis, all moving in the Z direction, which move the print head with a complex 6-bar linkage.  Instead of three independent axis for X, Y, and Z movement, the required movements of the 3 axis in the Rostock design to achieve the desired X/Y/Z position are calculated as needed by the controller. This makes the mechanical design in some ways much simpler - there are still 3 drive axis to build, but they are all identical.  None of the drive motors move, which simplifies wiring, and the actual moving mass is kept very low, which in theory translates to higher print speeds.  The cost comes in the complexity of the 6 bar linkage, with a dozen universal joints, and a greater overhead in software.

The standard Rostock design uses 6 smooth rods and linear bearing slides for the three drive axis.  What I'm building is a bit different, using Makerslide rail and carriages riding on V-groove bearings instead.  This is mostly due to cost and availability of materials.  I found a pile of roller bearings cheap at a local junkyard, and a single 2000mm length of Makerslide was much cheaper than sourcing the smooth rod and linear bearings required.  The Makerslide rail also makes for a slightly cleaner design - I can use the rail itself as a structural element to support the top end of the printer, and it has a channel inside which can be used to hide the wiring to top end.

For motors, I chose these large NEMA 17 motors from Phidgets.  The torque requirement was set by the direct-drive extruder design I wanted to use, and the motor required for that was cheap enough to use for the drive axis as well.

The standard Rostock design needs six 762mm smooth rods, and has a 400mm high print volume.  To keep costs down I bought a single 2000mm rail and cut it into three 666mm long pieces.  For this printer I'm only aiming for a 200mm high print area, so I don't need quite as much height on the rails.  The reduced height also let me use readily available 1164mm GT2 timing belts and pulleys

There are four sets here, I only needed three.  I bought these early on, before I had decided on the Rostock design.  Now I have a spare set.  I had been considering Synchromesh cable and printing my own pulleys, but decided that timing belts and premade pulleys would probably make for better precision in the moving parts.

The drive motors and pulleys are in the base of the printer, at the bottom end of the rails.  At the top end is an idler pulley.  These I decided to try and print myself.  The idler pulleys are printed in two halves.  Using the old Makerbot at work, I print the first half of the pulley.

While the plastic is still hot, I pressed a 625 bearing into the bearing half.

Once fully cooled, I remove that from the bed, and then print an identical pulley half.  The first pulley half and bearing is then pressed into that while still hot, making a complete idler pulley.

I'm not completely satisfied with how these run - the surface is a little uneven, there's a noticable irregularity with how the pulley runs with a belt tightly pulling on it.  I might try a different solution later.

To anchor the idler pulley and motor to the Makerslide rail, I decided to drill holes through the extrusion rather than attempt to clamp to it with T-nuts.  I haven't found a convenient source for the 5mm T-nuts that you're supposed to use to attach to the Makerslide rail, and I don't really trust a friction grip type connection to hold belt tension anyway.

Each 666mm length of Makerslide rail has two 5mm holes drilled, one near each end.  Andrew Terranova of Let's Make Robots was nice enough to let me use his saw and drill press to do this part.  I realized after cutting and drilling these that one of them has the inner groove in a reverse orientation to the others, but it doesn't really matter as I'm not anchoring anything to them.

The idler pulley goes at the top end of each rail.  The pulley itself is held in place by a 5mm machine screw threaded through the hole in the rail.  I designed a printed a plastic block that secures the pulley in place, has a flat surface and screw holes to attach to the upper structural plate, and has mounting holes for the upper mechanical limit switch.  I also have the option to use two T-nuts on each side to further anchor the block to the rail.

The motor and drive pulley are at the bottom end of each rail.  The lower assembly is made up of two blocks.  The smaller block to the left is anchored directly to the rail with another 5mm screw.  The larger block which holds the motor and drive pulley is free to slide along the rail.. I use two screws to attach the motor block to the anchor, and can adjust the tension in the drive pulley by tightening or loosening the screws.

To anchor the moving carriage piece to the belt, I use a modified version of the trick that's used on the original Rostock design, to pinch the belt in a groove on the carriage.  This sacrifices a little belt length for a secure grip with no additional hardware.

Four small V-groove roller bearings are attached to each carriage to let it roll smoothly on the rail.  In theory I could have gotten away with only using 3 bearings, and might change the design to reduce the weight in the future.  Other than the belt clamp and mounting holes for the roller bearings, the design of this part is the same as the original Rostock.

Now I have three essentially identical drive axis built up.  The next step will be to finish the wiring of the controller so I can test them, then getting the plywood cut so I can build up the frame.

Tuesday, August 21, 2012

The next big project

The little walking robot I bring to conventions wasn't well-prepared for GenCon 2012.  Leading up to the convention, I was mostly working on a completely new project instead.  My experience with the Makerbot Thingomatic at work has convinced me that I need to have a 3D printer of my own for home use.  Rather than buying a commercial kit, I'm building one from scratch of my own design.

I have spent months researching the design.  Initially, I was going to build a Pursa Mendel, with some modifications to use some scrap aluminum I have on hand to replace some of the threaded rods.  I wasn't happy with the way the design was looking, and kept trying to figure out ways to redesign it for faster speed and better rigidity.  For a while I was looking at building something more similar to a Ultimaker printer, but I wasn't happy with the overall mechanical complexity instead.  Then I came across the Rostock Delta 3D printer design, and fell in love.

My printer will be based on the Rostock design, but with a few key variations.  I'll be using Makerslide rail and V-groove bearings instead of smooth rod and linear bearings.  In theory, Makerslide should make the frame more rigid, and has a hollow channel through the center that can be used to route wires.  I will also be making a number of changes to the overall design, to accommodate found materials I'll be using, and to make the overall design cleaner and more compact.

Parts I have gathered so far include:

An Arduino MEGA 2560 controller, courtesy of the Sparkfun 2012 Free Day
A 480W PC power supply, recycled from my wife's old computer
A pile of V-groove roller bearings from a local scrap yard
Heated Bed and Borosilicate glass plate from Lulzbot
Drive belts and pulleys also from Lulzbot
Ramps DIY Complete kit with extra limit switches from Ultimachine
SDcard reader from
A single 2000mm Makerslide rail from Inventibles (sadly out of stock now)
MK7 drive gear from Makerbot
4 drive motors from Phidgets
Ten 625 bearings, polyamide tape, a 20x4 LCD, and a click encoder from Ebay
Some PTFE tubing, and a whole lot of nut, screws, and washers from Mcmaster
A Mini J-head, custom-machined for 1.75mm filament, from
Lots of scrap metal, plywood, hardware, tubing, wiring, and other bits from local suppliers and my scrap pile.

So far, all I have is a pile of parts gradually taking over the living room.  I hope to being actual assembly of the mechanical and electrical parts later this week, and to have the printer working a few weeks after that.

Gencon - event reviews

TDA1235549: Giants' Travail

This year True Dungeon had a new space in one of the giant convention halls in the ICC, rather than the ballroom of the Marriott as in previous years.  They used the new space to add extra features - crafting vendors, a tavern and dining area, even some side quests - to turn True Dungeon into a full MMORPG type experience.  I wasn't interested enough to try any of the side stuff, being only there for the main dungeon runs.  The best thing about the new location for me was being conveniently located near the boardgame area and dealer's halls.  The only complaint I have is that it was very dimly lit, even the dining and meeting areas - I almost couldn't find the friend I'd arranged to do the run with.

I did this run with a friend of my wife's who had purchased some large number of token packs in advance.  She gave me a full set of rare tokens, nowhere near as nice as the ultra-rare set she had but far better than the gear I came with.  She also took over as leader of the party, which helped - one very important factor in a True Dungeon run is having a unified party with a single person giving the orders!  The adventure itself was a nice mix of puzzles and combat.  We failed one room, a puzzle where we had to arrange the party in a line and pass clues from one end of the line to another by whispering from person to person.  Other than that we passed every room, and a good time was had by all.
BGM1233056: RoboRally: Time Twonky

A custom RoboRally game, this one having a setup where the game was run on three boards simultaneously and the robots could choose which board to run on at the start of each turn.  The main effect was to allow a robot in trouble to easily jump to a quieter map to shut down and recover.  A fun game, although a bit light on new mechanics.

RPG1231651: NASCRAG Charity Event

Scheduling this event was a mistake.  It's not that I have anything against the NASCRAG event, which was well-written and funny.  I'm glad I had a chance to try a NASCRAG event.  The mistake was in scheduling this event - a 4 hour long event involving roleplay and improv and other things I find mentally challenging - immediately following the 4 hour RoboRally event - which was also mentally challenging.  At about the third hour of the event I was mentally and physically exhausted and had a headache developing, and had to withdraw from the event.  I wasn't the only one, either - another player had to drop out and leave before I did due to exhaustion.  So, fun event, but I would have enjoyed it more if I'd been well rested going into it.

BGM1231471: Super Robo Rally

This was a large-scale RoboRally event, with board and robots made from Lego mindstorms robotics.  Everything was automated and computerized - the players used cards with RFID tags embedded, that were fed into an automatic card reader, and the robots then ran through the entire turn on their own according to the programmed cards.  It wasn't much of a Roboralley game - the effective board size was small, the event was only an hour long, and the rules were a limited subset of the normal Roboralley rules.  It was interesting more for the novelty of it working at all rather than for the game itself.  I probably won't do this again if they're back next year, but I'm glad to have tried it once.

It did give me some ideas for a different type of automated Roboralley setup that I might build some year.

BGM1233064: Dragon Dimension/Big Bang

Two experimental games being tested.  Big Bang was a very short and simple game, the result of a contest to design a game using only six cards and one die.  A fun ten-minute experience, the kind of thing you could play while waiting for pizza to be delivered.  Dragon Dimension was a significantly more complicated event, involving moving pieces around a map, summoning dragons, destroying helpless villages, and fighting other dragons.  The optimal strategy was a little hard to figure out beforehand.

CGM1233707: XXXenophile

The same game mechanics as Girl Genius, but with R-rated artwork and occasional instructions to remove clothing or perform various physical acts.  The group I was playing with ignored those instructions.  I suspect the game would have been more fun played with the right group of friends and all optional instructions followed.

BGM1233048: Turtle Soup

Another experimental game being tested.  In this one the players attempt to guild groups of baby turtles past various hazards to reach the open ocean.  The main failing of this game was the lack of meaningful strategic interaction between the players - we might as well have been each playing the game solo.  The one thing the players could do to deliberately affect other players was to shuffle terrain tiles around to make or break paths to the ocean, but that permitted little strategic choice as those changes usually helped or hurt all players equally.  I had a chat with the GM afterwards about ways to improve the game design.

TDA1235937: Draco-Lich Undone (puzzle-oriented)

I picked the puzzle-oriented version of this run because I didn't think I had good enough gear to do well on the combat side.  Of course, that was before I knew my wife's friend was going to equip me with her cast-off rares.  There was only one room with required combat on this run, and we aced it easily.  We did fairly well on the puzzles too, only failing one room that required us to use long wooden poles to carry buckets from one side of the room to another.  We knew what we had to do, but were too clumsy and spilled the buckets.  We solved the rest of the rooms, although I don't know how much of that was due to cleverness on our part versus people knowing the answers going in due to word of mouth or having done the puzzles earlier in the weekend.

Overall I thought the quality of the actual adventure runs at TD were better this year.  After the 2011 events I had been considering not returning for 2012, but after 2012 I have no such considerations about 2013.  The one thing that was lacking this year was additional lore and videos.  There was no preview video, no video at the end describing the state of the story, no clues on the TD forums beforehand, and no closure other than the end room GM telling us "Yep, Smoak's defeated for good now.".  I understand that they were a bit busy ramping everything up for the new event space, and TD isn't really a roleplay-focused event, but I did feel the immersion was lacking this year.

BGM1233058: RoboRally: 3D

This was the final event I registered for at this year's convention.  A RoboRally game on an initially empty board, with rules mechanics that permitted players to drop, pick up, or move blocks and ramps to change the playing field each turn.  I had a great time in this one.  This is the type of RoboRally event I like - where new game mechanics are added that give an additional level of strategic choices to the players.  It was reminiscent of the "Planet Robo" event run some years back by the same people, where the players could drop board elements (conveyors, bridges, pits, etc) before or behind their robots as they moved.

A common problem with RoboRally games is the tendency for a robot which manages to get ahead of the pack to stay ahead of the pack.  The biggest impediment to a robot is the other robots, so any robot who gets away has an advantage and tends to stay in front.  The custom rules in this event unfortunately tended to make this effect worse - robots could only drop blocks nearby and couldn't pick up blocks near other robots.  A robot ahead of the pack could drop blocks to make it go faster (conveyors and such) and barriers behind to slow down the others, while the rest of the pack would be unable to stop it and instead would be slowing each other down.  Halfway through the game, at the third flag, I managed to get ahead of the rest of the players, with a few lucky card draws and well-placed blocks, and from there was able to race ahead untouched and maintained a clear lead until the end.  I think the rules for where and when robots could drop and pick up blocks could have used some tweaking, but this remains my favorite event at this year's GenCon.

Gencon - post-event report

GenCon 2012 is over, and we're back home.  I had an amazing time - mostly due to the events I was in, as I scheduled too many gaming events and didn't have time for much else.

The convention was, as usual, crazily crowded.  The sprawl of the convention - including the convention center itself and the attached hotels - seems to expand every year.  This year I didn't even get to many of the outlying hotels, as nearly everything I had to do was in the main convention center and I didn't have much time to explore.  The nearby restaurants seemed crowded, at least what I could see of them - there was actually a line to get into the Old Spaghetti Factory for lunch on Friday!  There was a biker event in town Friday and Saturday, and I think a concert or two as well, which just added to the crowds and noise.

I was not able to spent much time showing off the robot for people.  The battery pack in the robot has been losing capacity for a while.  I knew it was happening, but didn't realize how bad it was getting until this weekend, when attempting multiple full charge-discharge cycles revealed how bad the problem had become.  By Friday night, the battery would no longer take any significant charge, and I retired the robot for the weekend.  Time to buy a new battery pack - and this time, I think I may buy several and design to be able to swap them out easily.

The Towardpro MG996r servos I had been using since last year were pretty badly worn - despite the unexpected inclusion of brass bosses around the gear shafts, there was significant wear and damage to the servo cases.  My usual supplier of these servos was out of stock, so I ordered a batch from an Ebay retailer.  Big mistake - the servos I received were labeled the same, but not built nearly as well internally!  It appears that even cheap knockoff brands have their own cheaper imitators.  I ended up using a mixed batch of the better of the old and new servos, including at least one servo made from the case of one of the original batch and the gears of one of the newer ones.  The servos held up well for the convention, but they weren't run very hard due to the battery problems.  I'll have to order a complete replacement set - from a reputable dealer - before the next big event.

Or, I might just design something completely new for next year.  Having access to a 3D printer opens all sorts of options for new designs.

Monday, August 13, 2012

Drew's Gencon Schedule

 This year I was highly successful in getting events for GenCon.  I used my GenCon planning software to chose an optimal schedule of events, and then when event registration opened I got a very good queue position.  (This wasn't entirely due to luck.  There are some tricks that still work for getting a good position in the registration queue.)  I managed to get tickets for every one of my highest-priority events - a big difference from last year, in which I didn't manage to get any of my top choices.

Of course, this means that I've scheduled so many gaming events I'm not sure if I'm going to have time to eat or tour the dealer's room this year.  I'll try to get some demo time in with the robot, but it's not going to be my top priority this year.


TDA1235549: Giants' Travail
BGM1233056: RoboRally: Time Twonky
RPG1231651: NASCRAG Charity Event

SEM1235222: Archaeology Vs Pseudo-Archaeology

BGM1231471: Super Robo Rally
BGM1233064: Dragon Dimension/Big Bang

SEM1229856: Women and Gaming

CGM1233707: XXXenophile

BGM1233048: Turtle Soup
TDA1235937: Draco-Lich Undone
BGM1233058: RoboRally: 3D

Little Walking Robot - Arduio Sketch

The software which runs on the Arduino in the transmitter is actually fairly simple.  The robot is essentially just a wireless puppet - movement of the joysticks is translated directly to movement of the legs.  All the fancy moves the robot does - walking, posing, waving at people, rolling over - is performed by the operator, moving the robot's joysticks and changing the mixing algorithm with the mode select buttons.  The software simply samples the mode buttons and analog inputs from the joysticks, performs some simple digital debouncing and filtering, calculates the desired position of each servo, and transmits the servo position commands out on the serial port.

In the robot,the serial output from the receiving XBee module is fed to the serial input of an 8-channel Pololu Serial Servo Controller.  The controller has some configuration settings that let you adjust the center points and ranges on each servo, but I'm bypassing those and setting the position directly with the Set Position, Absolute command.  I prefer to do those calculations in the transmitter.

int stickX = 0;
int stickY = 0;
int stickX2 = 0;
int stickY2 = 0;

long avgtemp = 0L;  //teprary long for digital filtering

//for all servos, 3000 is center

int servoFRX = 3000; 
int servoFLX = 3000; 
int servoRRX = 3000; 
int servoRLX = 3000; 
int servoFRY = 3000; 
int servoFLY = 3000; 
int servoRRY = 3000; 
int servoRLY = 3000; 

int outputFRX;
int outputFLX;
int outputRRX;
int outputRLX;
int outputFRY;
int outputFLY;
int outputRRY;
int outputRLY;

//trim the center points on each servo
//require because the MG996R servos are so damn inaccurate

#define trimFLY 0     //plus is ccw (down),        minus is cw (up)
#define trimFLX 0     //plus is ccw (back/left),   minus is cw (front/right)
#define trimRLY -100  //plus is ccw (down),        minus is cw (up)
#define trimRLX 0     //plus is ccw (back/right),  minus is cw (front/left)
#define trimRRX 30    //plus is ccw (front/right), minus is cw (back/left)
#define trimRRY 0     //plus is ccw (up),          minus is cw (down)
#define trimFRX -10   //plus is ccw (front/left),  minus is cw (back/right)
#define trimFRY 150   //plus is ccw (up),          minus is cw (down)

int mode = 0;  //miximg mode

byte button0 = 0;
byte button1 = 0;
byte button2 = 0;
byte button3 = 0;

byte button0oldstat = 0;
byte button1oldstat = 0;
byte button2oldstat = 0;
byte button3oldstat = 0;

byte buttoncount = 0;
byte invertmode = 0;

void setup()                    // run once, when the sketch starts
  ADMUX &= 0x3F;                // use 3.3V supply as AREF
  delay(500);  //give the radio time to start working

void loop()                     // run over and over again

  button0 = digitalRead(2);  //D2 - brown wire
  button1 = digitalRead(3);  //D3 - green wire
  button2 = digitalRead(4);  //D4 - yellow wire
  button3 = digitalRead(5);  //D5 - orange wire
  //check to see if the button inputs have changed
  //we use a timer variable for digital debouncing
  if (  (button0oldstat != button0)||
        (button1oldstat != button1)||
        (button2oldstat != button2)||
        (button3oldstat != button3)||
        ((button0 == 1)&&
         (button1 == 1)&&
         (button2 == 1)&&
         (button3 == 1))) {
      buttoncount = 0;
  else {
    if (buttoncount == 20) {
      if ((button0 == 0)&&
         (button1 == 1)&&
         (button2 == 1)&&
         (button3 == 1)) {
           invertmode = 1 - invertmode;
      else if (button0 == 1) {
             mode = (1 - button1) + (1 - button2) * 2 + (1 - button3) * 4;
    if (buttoncount < 21) {
      buttoncount = buttoncount + 1;
  button0oldstat = button0;
  button1oldstat = button1;
  button2oldstat = button2;
  button3oldstat = button3;
  //read analog inputs
  //we do some digital noise filtering here

  avgtemp = stickX * 3L + (analogRead(0) - 512) * 256L;  //A0 - right X - orange wire
  stickX = avgtemp / 4; // right joystick x

  avgtemp = stickY * 3L - (analogRead(1) - 512) * 256L;  //A1 - right Y - yellow wire
  stickY = avgtemp / 4; // right joystick y

  avgtemp = stickX2 * 3L + (analogRead(2) - 512) * 256L;  //A2 - left X - green wire
  stickX2 = avgtemp / 4; // left joystick x

  avgtemp = stickY2 * 3L + (analogRead(3) - 512) * 256L;  //A3 - left Y - brown wire
  stickY2 = avgtemp / 4; // left joystick y
  //determine the servo positions based on the joystick inputs
  //there is no sequencing here, it's all just direct one-to-one mapping of joystick inputs
  //to servo outputs, with the mode variable controlling which mixing algorithm to use.
  switch (mode) {
    case 1:  //basic walk algorithm
      servoFRY = 2000 - (stickY / 32);
      servoRRY = 2000 + (stickY / 32);
      servoFLY = 4000 - (stickY / 32);
      servoRLY = 4000 + (stickY / 32);
      servoFRX = 3000 - (stickX / 24) - (stickY2 / 30) - (stickX2 / 30);
      servoRRX = 3000 + (stickX / 24) + (stickY2 / 30) - (stickX2 / 30);
      servoFLX = 3000 + (stickX / 24) - (stickY2 / 30) + (stickX2 / 30);
      servoRLX = 3000 - (stickX / 24) + (stickY2 / 30) + (stickX2 / 30);
    case 2:  //wave front legs
      servoFRY = 2500 + (stickY / 16);
      servoFLY = 3500 + (stickY2 / 16);
      servoFRX = 3000 + (stickX / 24);
      servoFLX = 3000 + (stickX2 / 24);
      servoRRY = 2000;  //down
      servoRLY = 4000;  //down
      servoRLX = 4375;  //forward/left
      servoRRX = 1625;  //forward/right
    case 3:  //all servos center - used for alignment checks
      servoFRY = 3000;
      servoFLY = 3000;
      servoFRX = 3000;
      servoFLX = 3000;
      servoRRY = 3000;
      servoRLY = 3000;
      servoRRX = 3000;
      servoRLX = 3000;
    case 4:  //body lean/shift/dance
      servoFRY = 2000 + (stickY / 32) + (stickX / 32);
      servoRRY = 2000 - (stickY / 32) + (stickX / 32);
      servoFLY = 4000 - (stickY / 32) + (stickX / 32);
      servoRLY = 4000 + (stickY / 32) + (stickX / 32);
      servoFRX = 3000 + (stickY2 / 32) + (stickX2 / 32);
      servoRRX = 3000 + (stickY2 / 32) - (stickX2 / 32);
      servoFLX = 3000 - (stickY2 / 32) + (stickX2 / 32);
      servoRLX = 3000 - (stickY2 / 32) - (stickX2 / 32);
  if (invertmode == 1) {  //inverted?
    outputRRY = servoRLY;
    outputRLY = servoRRY;
    outputFRY = servoFLY;
    outputFLY = servoFRY;
    outputRRX = servoRLX;
    outputRLX = servoRRX;
    outputFRX = servoFLX;
    outputFLX = servoFRX;
  else {
    outputFRX = 6000 - servoFRX;
    outputFLX = 6000 - servoFLX;
    outputRRX = 6000 - servoRRX;
    outputRLX = 6000 - servoRLX;
    outputFRY = servoFRY;
    outputFLY = servoFLY;
    outputRRY = servoRRY;
    outputRLY = servoRLY;
  //tweak nonzero servo centerpoints
  outputFRX = outputFRX + trimFRX;
  outputFLX = outputFLX + trimFLX;
  outputRRX = outputRRX + trimRRX;
  outputRLX = outputRLX + trimRLX;
  outputFRY = outputFRY + trimFRY;
  outputFLY = outputFLY + trimFLY;
  outputRRY = outputRRY + trimRRY;
  outputRLY = outputRLY + trimRLY;
  //constrain to actual servo travel limits
  outputFRY = constrain(outputFRY,1000,5000);
  outputRRY = constrain(outputRRY,1000,5000);
  outputFLY = constrain(outputFLY,1000,5000);
  outputRLY = constrain(outputRLY,1000,5000);
  outputFRX = constrain(outputFRX,1000,5000);
  outputRRX = constrain(outputRRX,1000,5000);
  outputFLX = constrain(outputFLX,1000,5000);
  outputRLX = constrain(outputRLX,1000,5000);
  //transmit to robot
  Serial.write((byte)(outputFRY / 128));
  Serial.write((byte)(outputFRY % 128));
  Serial.write((byte)(outputFRX / 128));
  Serial.write((byte)(outputFRX % 128));
  Serial.write((byte)(outputRRY / 128));
  Serial.write((byte)(outputRRY % 128));
  Serial.write((byte)(outputRRX / 128));
  Serial.write((byte)(outputRRX % 128));
  Serial.write((byte)(outputRLX / 128));
  Serial.write((byte)(outputRLX % 128));
  Serial.write((byte)(outputRLY / 128));
  Serial.write((byte)(outputRLY % 128));
  Serial.write((byte)(outputFLX / 128));
  Serial.write((byte)(outputFLX % 128));
  Serial.write((byte)(outputFLY / 128));
  Serial.write((byte)(outputFLY % 128));

Sunday, August 12, 2012

Little Walking Robot: Controller Rebuild

 The little walking robot is getting a rebuild in preparation for GenCon 2012 - only days away as I write this.  I haven't actually changed much on the robot itself.  It worked well at last year's convention, so the main changes I made to it were to replace broken parts.  The big change I've made this year is completely rebuilding the transmitter.

Last year's transmitter was built around a FunnelIO board.  This is an Arduino clone with a socket for a XBee radio module and a USB-powered LiPoly battery charger on the board.  This was nearly everything needed for the transmitter function on one board, and it worked well for that version of the transmitter.  What I didn't like about the FunnelIO was the size.  It was too large to fit cleanly in the transmitter cases I built, sticking out one side awkwardly.  It was also awkward to program.  The USB port on the FunnelIO was only usable for battery charging.  To program the controller, I needed to remove the XBee module and plug in a FTDI serial converter with a handmade adapter cable.

The redesign started with Sparkfun's Free Day 2012, back in January.  The previous two years I'd been unable to win anything through it.  This year I was persistent and lucky, and managed to get among other parts three parts for a new robot controller:  an Arduino Pro Mini, an Xbee breakout board, and a Li-poly battery charger.  These three parts, along with the Xbee module I already had, would make the core of a new controller.

 One goal I had for the new controller was to be able to program it without disassembling it, through the same USB port used to charge the controller battery.  This would be challenging, both mechanically and electrically.  I had a FTDI UBS-to-serial converter board I'd been using for programming in the past, but it had the wrong connector type, a type A (computer side) plug, rather than the mini-B I'd like to use.  The battery charger board had a mini-B connector, but no easy access to the data pins.  I ended up removing the type A connector from the FTDI board, then  very carefully soldering tiny wire-wrapping wires onto the mini-B connector on the battery charger, and running them to the pads where the connector on the USB-to-serial converter board had been.

Now I had a single port that would simultaneously connect both the battery charger and the USB-to-serial converter.  Now the challenge was the electrical integration.  The Arduino board only has a single serial port which is used for both programming and to transmit data to the XBee module. I needed to be able to program the board through this port while it was connected to my laptop, and then have it work normally as a transmitter, the two functions not interfering with each other, without having to plug or unplug modules.  I also needed to be able to plug the transmitter into my laptop with the Arduino and XBee powered off so I could just leave the battery to charge.

I ended up connecting the USB-to-serial board to the Arduino pro with a rats-nest of resistors and diodes.  When the USB connector is unplugged, the battery charger and serial converter board are unpowered.  The diode on the Arduino TXD line prevents the shut-down converter board from interfering with the communications between the Arduino and the XBee module.  When the USB connector is plugged in, the USB-to-serial converter board can drive the serial and reset lines as needed to program the Arduino.  And when the transmitter is switched off, only the battery charger and serial converter are powered by the USB connection, with the diode on the arduino RXD line preventing the Arduino from being possibly damaged by having its serial input driven while the board is unpowered.

The three boards - the Arduino Pro Mini, the USB-to-serial converter, and the USB battery charger - are tightly sandwiched together.  I didn't get a good picture of that assembly, but it's hard to see what's going on anyway.  The following schematic shows the connections, as well as how the joysticks and mode select buttons are connected.

Many of the parts are recycled from the previous version of the controller.  The joysticks are the same old RC airplane controller sticks, and the mode select buttons are the same pushbuttons on a PCB assembly.  I'm also still using the same grossly over-powered 1000mAh lipoly battery.

Since the start of this year I've had access to a 3D printer at work.  I wasn't initially confident enough in the strength of the printed parts to use them for the robot, but I decided to see if I could make a new transmitter housing, something to replace the old plywood frame I'd been using.  The big advantage of the 3Dprinted housing was the ability to make it in any arbitrary shape.  I decided to keep the overall outline the same as I had with the plywood housing, but was able to design pockets and channels internally to hold all the components and wires.

The basic form would be the same as the last one, with right-hand and left-hand controllers connected by a cable.  Each controller would be made up of two pieces, a larger 'front' piece that held the joysticks and most of the components, and a mostly-flat 'rear' panel.  Here's one of the rear panels being printed.  These parts are big, near the maximum size that could fit on the Makerbot Thing-O-Matic build platform.

A test-fit of the rear panel of the right-hand controller.  The Xbee radio module fits into a slot, with a channel to route the antenna wire to the antenna connector set into the back.  I was also experimenting with a smaller battery, shown here, but ended up going with the larger battery I'd used in previous years instead.

The completed left-hand controller!  The RC airplane joystick fits flush into the front-side housing.  You can see the to center adjust trims sticking out through the front face as well.  I ended up attaching guards around these to make it impossible to knock them out of position by accident.

The left-hand controller, opened up.  The joystick assembly occupies nearly the entire interior.  There's just enough room for the battery, which is the black oblong object above the joystick.

The right-hand controller has a bit more going on.  The four mode-control buttons are placed where I can easily press them with my fingers while working the joystick with my thumb.  The USB charging/programming port is visible, right above the Arduino reset button.  This side also has the radio transmitter and antenna, and the main power switch.

The right side controller opened up.  It's a bit hard to see what's going on - the modules are fairly tightly installed and obscured by wiring.  As with the left-hand controller, the joystick takes up most of the interior.  The Xbee radio module is at the bottom of the controller in this photo, and the Arduino/battery charger/serial converter assembly is just to the left of it.

Closeup on the control boards.  XBee carrier is on the left, with the wiring bundle to the mode select buttons snaking around it.  The Tantalum capacitor soldered across the XBee power terminals seems to be vital, I couldn't keep a reliable radio link without it.  The barely-visible control board is to the right.

Viewed from the opposite angle.  You can see the mode select buttons to the right, and the controller module to the left.  Admittedly it's hard to see how they're connected in this shot. The schematic posted above should make it clear.

All buttoned up, and ready to go to the convention!

On the robot itself, the biggest change has been replacing some of the steel parts of all four legs with printed parts.

After building the transmitter case, and some other test parts, I was confident enough in the strength of the 3D-printed parts to use them for the leg structure.  They seem to be holding up so far.  We'll see if any break over the convention weekend.