But I've been itching to do more at the faire. So here's the pitch: a 10'x10' arena where 2 Geekbots race around to collect balls. Each geekbot is piloted by a Maker Faire attendee. Here's the catch: just like Mech Warfare, the pilot can only watch the match from a camera mounted to the robot.
So begins my quest to build a 10'x10' arena. It needs to be modular and easy to install and take down. I've got multiple faires in multiple venues, so it needs to work indoors and outdoors. For the floor, Wade reccomended Interlocking EVA foam, which is working out amazingly. Its easy to lay down and take apart, and the Geekbots have no problem rolling around on it.
Since we're not using projectiles like in Mech Warfare, the arena doesn't need to be totally enclosed, but I still couldn't' decide how to do the walls. We couldn't have the Geekbots falling out of the arena now. After playing with a variety of ideas (insulation foam, vinly, PVC, plywood) I finally came to the realization that I don't actually need a full wall - just enough to keep the Geekbots from going over the edge. After a little experimentation Wade figured out how to make a 2" foam wall that keeps the Geekbots at bay. First, we're hot-gluing extra EVA foam onto the outer finished strips of the EVA foam - this make it easy to take apart and store the 'walls'. To keep the geekbots from pushing the walls right off the arena, we're using a long thin plate of ABS under the finished strip to add support. This combo keeps the geekbot in the arena and wall stays nice and in place.
There's still a lot to do. Kat is going to make some arena obstacles and we need to figure out coloring for the goals among other things, but we're well on our way.
If the DARPA Challenges can be considered the Olympics and Battlebots can be considered boxing then ultimately I want people to consider Robot Riot as Wrestlemania.
Based on the Hebocon competition, Robot Riot is a sumo style competition where 2 robots compete to push each other out of the ring - but that's where the similarities to a standard sumo competition end. First of all, pushing the competitor out of the ring does not guarantee a win - the crowd is the final kingmaker in this competition. This means that your robot needs style and needs to put on an amazing show. The Riot emphasizes artistry, grandstanding, showmanship and craziness.
I had been planning on going to The Riot all month, but I've been running around like crazy between trips and work, so I wasn't sure if I was going to try to compete or not. The Wednesday before the Riot, Wade and I decided to give it a shot and see if we could put together something functional for Saturday.
We talked about a lot of different possibilities - from a dog robot to a crawler robot.
Back when I was testing the RoboTurret, I had it accidentally fall over and start crawling away. I thought it would be funny to have a turret crawl around the ring like a snake (something I accidentally figured out you can do with a pan/tilt turret while testing some of ours at Trossen).
Obviously this would mean that Wade would be dressing up as Rick and I would be dressing up as Morty. A couple of Amazonorders and a goodwill trip later, Wade and I were ready. Special thanks to Kit for styling the Rick wig, she did an awesome job.
The robot build turned out to be pretty basic. For the mobile platform we 'borrowed' a Surveyor SRV-1 from the Trossen Museum. I made a super basic plate in Tinkercad to adapt the surveyor to a RobotGeek bracket. I also made a hole that we could put a bluetooth speaker in to give the robot some jams. (We played with the idea of adding an MP3 module right onto the robot, but ended up deciding against it for time and control constraints). The rest of the endoskeleton was 4 RobotGeek Servos (roll, tilt, 2 arms) cobbled together with C-brackets and side brackets. The arms are made out of aluminum standoffs and right angle brackets.
For electronics we've got an Arduino Pro Mini controlling everything, powered by a little 7.4 LiPo. A little dual 1A motor driver is enough to push the motors in the SRV-1. Luckily the servos and drive motors were all happy in the LiPo's 6.6-8.4 battery range. To add a little show we've got a
WS2812B RGB LED (A.K.A. Neopixel) for the robot's 'eye' and LED Driver connected to the red led on the top of the 'bot.
The mini gets its marching orders from an ArbotiX Commander via an XBee link. The commander hardware and library made it a cinch to control the robot.
The Butter Buster Firmware is pretty basic - the firmware reads from the commander to directly control the servo motors. There's a little bit of hacky drive control to let the robot get driven from a single analog (instead of tank control). The neopixel changes color as the robot moves forward/backwards/turns.
Wade used his extensive experience with EVA foam to build an awesome head for our robot that fits directly over the endoskeleton. A hole for our salvaged camera lens and some wires for the top of the head finished the look.
Butter Buster is by no means the best designed robot. The initial run actually had the power switch on the back, so it would fall over and power off. Even after that was fixed, the balance was during operation was a little tricky. To rotate without too much roughness you need to tilt the head forward just right, and falling over was still a hazard. Despite that it's a capable enough robot, and Wade even figured out some good ways to get back up from a fall with the tilt and roll servo. Really, he didn't even need to, as he could still drive around even after falling down. I think the wonky-ness was part of it's Robot Riot Charm.
The event itself was a total blast. Adrian came in an awesome referee shirt and started things off right with a Piezo Buzzer rendition of out national anthem. Other competitors included 'Ham Immanuel', a walking pig robot, and 'Knife to Meet You' a vibrating robot with a knife attached. Check out the video to see all of our fights in action. I'm hoping to get a copy of the live stream from Adrian soon.
Butter Buster performed all night admirably. In the first match we did manage to burn out our roll servo, but a pair of wire cutters and some tape got the Butter Buster back in fighting shape (without roll capabilities that is.) Before each match, Wade (our designated pilot) had to take a shot of Jägermeister, and while he was certainly drunk by the end of the night, he too did a great job, piloting the robot as effectively as he could have. We won our first 3 matches, and in true Hebocon style we attached Bowie Bot's head and limbs and 'america bot's flags to Butter Buster, upgrading him into the 'Young American'.
In the end we got pushed out of the arena by 'A Bot Named Slickback', a pencil-case bodied, 4-cell LiPo monster of a rover. This robot actually ran itself off the stage after every fight except ours. But I'm still proud of our little butter busting robot.
So what's next for the Butter Buster? Who knows, maybe we'll make the con circuit, or put him in the next Robot Riot. Until then, he sits on the shelf, watching, waiting, ready to pass the butter and bring the pain.
Well, it's been a while, but I'm back! I've had a few developments since my last blog (including new bots, a new 3D printer) but today I want to show off the next version of DynaPose.
Last year I wrote some super basic scripts that would allow you to pose an arm in discrete positions. It's handy, but a little clunky. Lat week, after seeing one of SparkFun's Video for the uArm I was inspired to make a real-time DynaPose.
The basic idea is that instead of hitting a button to record each pose, you simply move the arm to the positions you want it to go to and the ArbotiX Microcontroller automatically records positions on a timer. The upside is that the arm will playback in the same fashion that you pose it. However, this is fairly memory intensive, eating up the ArbotiX's precious SRAM.
How intensive is it? Well that depends on your number of servos and your read rate! So let's do the math. The atmega644p on the ArbotiX has 4k of SRAM. We'd have to do some digging to figure out the overhead of our default variables and the DYNAMIXEL and serial libraries, but let's just say that 3.5K was free - or 3584 bytes. Let's also target the PhantomX Pincher which has 5 servos. 3584 bytes / 5 servos gives us 716 bytes per servo. Now AX dynamixels have 10-bit positional encoders, so we're going to have to store the positional data in a 2-byte integer, so 716 / 2 gives us a total of 358 positions.
Now you've got to decide how long you want to stretch those positions. For butter smooth recording and movements, you want somewhere around 50ms between reads. and 50ms * 358 positions gives you 17,900 milliseconds, or 17.9 seconds of pose time - not a whole lot. i've found that 100ms (10 reads per second) works fairly smoothly and doubles your time to 35.8 seconds. If you don't mind some jerkiness, you could go up to 500ms for 179 seconds! But you're also bound to miss some positional data.
now of course there's ways to expand your memory. You've got another 1k of EEPROM, or you can use an external EEPROM module or other memory module. I'm also looking into using an SD card logger to handle the data and make it easy to get to your computer.
Or you could ditch the ATMega 644p for a Teensy 3.2 with 64k of ram - with that much ram you could pose a 20-servo HR-OS1 at 20hz for 161 seconds!
The code can be found here as part of the before mentioned repository. The code is a work in progress and needs some tweaking before using other robots, so drop me a line before you use it. You'll need 2 buttons (record on DIO3, play on DIO4), a buzzer on DIO2 and an analog sensor on A0 if you want to manually control a gripper. SERVOCOUNT defines your number of servos and READ_INTERVAL is that timed interval I mentioned before.
Here are some things I'm working on to make it ready for general consumption:
Better gripper options for other arms
Removing duplicate pose data (but possibly recording pause data and allowing for a headband of the 'same' pose)
We recently updated the RobotGeek Snapper Arm with a new gripper, so I've been off in documentation land, getting everything happy for the new change. This inevitable led me to doing some work on the Arm Link Software. I have a love hate relationship with my little arm link program, but it works, so why not?
So first up didn't actually have a whole lot to do with the software, but the Snapper firmware. Andrew wrote all of the IK code for the Snapper, but never implemented Cylindrical or Backhoe modes. Backhoe mode is obviously pretty easy - just map the arm link packets to the servo joints. Cylindrical wasn't bad either, as Andrew had done all the IK work (the code is very similar to the code for the Cartesian X/Y/Z IK, only you ignore the X axis). The pain was going through the code and making it ready for multiple modes. A tedious hour later, I had everything working smoothly.
On the Arm Link side, it didn't take much to get things working. I had disabled cylindrical and backhoe mode on the snapper, so I quickly re-enabled them and added in all of the limits.
Of course an update like this turns into a black hole of updates. I had to update the ArmLink reference page for the new features, commands, and limits. Then I had to add the cylindrical IK engine into the main joystick IK software. And while I was at it I added the backhoe to joystick (which had previously been its own sketch). And then I updated that documentation. It never ends.
We make binary executables available for ArmLink, so making updates can be a little bit of a pain. It's nothing herculean, but to get java embedded with the app I need to build it on each target platform (once on Mac, once on Linux, once on Windows). So I try to wrap up multiple updates in one release when possible. So I decided to move onto a couple of things I've wanted to fix/change in the software.
Too Many Updates!
There are two ways to send positional updates to the arms - you can hit the Update button to send the current values, or you can check the Auto Update box. If you check the box, the positions will automatically be sent to the arm. If you lower the transition time (the delta) then you can get the arm to react in real time with your sliders and knobs. This feature works, but I found out that under certain positions that you could start to have problems. I'll go into more details in a later post, but with our Arm Link packet, if you send the same packet multiple times, and the packet has too many '0xff'/255 bytes, it is possible to read the last half of one packet and the first half of the next as a 'valid' packet. This can lead to some bad situations like arms repeatedly pounding the table. I'm still ruminating on ways to fix this on the packet side, but I decided that an easy fix on the software side would be to only send positional packets if a position was actually going to change. So every loop I check the current values against the last values - if there's a change, I send a packet. If not, I go on with my life. Either way I store the packets away to check against next time. This has fixed most my problems, though I'm still investigating an issue where two many '0xff' can freeze the arm temporarily.
Reading Registers and More
Finally I got to add something fun that I've wanted to add for a while. For the InterbotiX arms that use DYNAMIXEL I've gotten a couple of questions about accessing the servos directly. Basically each DYNAMIXEL serveo is a smart servo with a micro controller on board. There's all sorts of data that you can poll the servo for like position, temperature torque, and more. You can also set parameters like compliance on AX servos and PID settings on MX servos. But to get at any of this you need to work at the firmware/arbotix level. After another request for the feature last week I finally decided to implement the future.
On the firmware side I added two new instructions in the inputContro.h file. The first will get data from the servo / register that you request from (instruction 0x81). The second instruction(0x82) will set data to a servo/register that you set. To pass the data I'm just using the packets normally reserved for X/Y/Z/Wrist for the parameters Id/RegisterNumber/Length/value.
So before I started integration into ArmLink, I wanted to do some testing. The easiest way would probably have been to fire up Cool Term and write out the packets to send to the arm, but I'm a masochist so I started ANOTHER project- Arm Link Barebones. Arm Link started as a basic demo both Interface wise and code wise. And while the code is readable, it jumps through a ton of hoops, so there's a lot to wade through if you're a developer and you just want the minimum example to get going. So Arm Link Barebones is just that, a really basic example of how to control the arm. There's no GUI, just some functions to talk to the arm over serial. Eventually I'll wrap it up in a nice library, but it's a decent stop gap.
Really starting Arm Link Barebones wasn't a big deal, I just ripped up a copy of Arm Link proper. So another hour later I had Arm Link Barebones sending commands to the arm. A few more functions added and there I was blinking servo LEDs and reading firmware versions from my computer. Huzzah!
When I started working on the get/set registers I didn't even plan to integrate it into Arm Link, but I took it that far, so I went just a little further. Really the biggest pain was integrating everything into the GUI. It's kinda cramped as is, and I really didn't want to re-arrange the whole gui. But after some 'creative' moving I finally got all of my fields in. I'm at home right now, and I did a lot of testing by putting some Arm firmware on a spare Geekduino, but I need to actually test it on a real arm. So keep your fingers crossed, hopefully I'll have a release tommorow.
Now keep in mind that I really want to move the Arm Link software over to a chrome app. I think for a demo that chrome apps have everything I need, are cross platform, and super easy to update/do gui stuff. Maybe next time
Just uncomment the line for your arm and you're good to go, the firmware takes care of all the work for picking the arm.
The Problem: If you try to compile the code you get a slew of unhelpful errors, starting with ...
In file included from InputControl.h:4,
Kinematics.h: In function 'uint8_t doArmIK(boolean, int, int, int, int)':
Kinematics.h:101: error: 'WristLength' was not declared in this scope
Kinematics.h:102: error: 'BaseHeight' was not declared in this scope
Kinematics.h:106: error: 'ShoulderLength' was not declared in this scope
Kinematics.h:106: error: 'ElbowLength' was not declared in this scope
Kinematics.h:143: error: 'BASE_N' was not declared in this scope
Kinematics.h:143: error: 'BASE_MIN' was not declared in this scope
Kinematics.h:143: error: 'BASE_MAX' was not declared in this scope
and going on for several dozen lines. Now if you've read the Setup guide then you should know that you have to uncomment a line for your arm. But what if you didn't? Or what if you forgot? How can we make this a better user experience?
A while back I did some searching for 'Custom Arduino Errors' and the like, but I never found much. But last month while looking at the Razor AHRS Firmware I found exactly what I needed
// Check if hardware version code is defined
// Generate compile error
#error YOU HAVE TO SELECT THE HARDWARE YOU ARE USING! See "HARDWARE OPTIONS" in "USER SETUP AREA" at top of Razor_AHRS.ino!
You see, the Razor AHRS Firmware supports a bunch of different hardware, so at the very top of the file you need to define which hardware you're using (sounds familiar, eh?). So the little block above throws an error and stops the user if the hardware wan't defined. And it's a totally custom message, so you can explicitly tell the user what the problem is. Since this code lets you throw custom errors based on pre-processor defines. So now the Arm Link code looks like
#define PINCHER 1
#define REACTOR 2
#define WIDOWX 3
//uncomment one of the following lines depending on which arm you want to use
//#define ARMTYPE PINCHER
//#define ARMTYPE REACTOR
//#define ARMTYPE WIDOWX
#error YOU HAVE TO SELECT THE ARM YOU ARE USING! Uncomment the correct line above for your arm
Later in the code we can check the type of the arm (see GlobalArm.h)
It is worth noting that the firmware should probably be doing a check against the servos that it sees and not engaging unless it sees all the servos. Though this would cause a whole different issue - code running on the robot but no good way to tell the user that servo discovery has found a problem.
But that's a quest for next time I guess.
With one of our crew out, I've been working double duty all week, so I don't have all too much to report on this week. One of the things that came up is the need for something a little more robust then the RobotGeek Gripper for our RobotGeek line. The InterbotiX line has the Parallel Gripper, and we actually made some prototypes that use that gripper with RobotGeek servos a while back, but it never really went anywhere. Upon revisiting the project with our slightly newer, slightly stronger servos, we found that it actually works out pretty well. We made a jig for drilling the extra holes needed, and made some new prototypes. Matt came up with some clever ways to mount everything and the gripper seems to do pretty well.
I toyed around a little with the 3D printer over the week, intent on making some new gripper fingers. I started of by printing the original finger file, which turned out decently. I think opening up the rails would make it move smoother, but I also had a sanded-down bottom plate it could attach to, so I forged ahead. I tried a couple of other designs.
A parallel gripper works by connecting the servo motor horn to two swings arms. The swing arms then connect to two finger pieces. The finger pieces are on a plate with parallel rails. As the servo rotate, the swings arms bring the finger plates in or push them out. This means that the maximum movement of the fingers is defined by the servo rotation and the swing arm length. So by changing the size and shape of the fingers, you can change the size of the object you can grip. But since the overall distance the arms move doesn't change, this means that you can only grip objects in a range. So If I can normally grip objects between 0 and 25mm, and I modify my fingers to be 25mm apart, I can only grip things from 25mm to 50mm. Anything below 25mm wide and I won't be able to grab them. For some tasks, this works out.
Matt is experimenting with cutting/modding the existing fingers and has had some luck. He also had the idea to mount 3D attachments to the cut-down fingers, so I printed out some fingers designed for a soda can. I didn't put much thought into the design, so it's kinda ugly. Because the gripper has such a small travel, I don't think this gripper will really work - you'd have to be super accurate or you'd be more likely to spill the can before you could pick it up
Still, there are a lot of grippers you could design that would be actually useful. We've got a couple secret designs in the work. Hopefully next week I'll be able to share some more as well as some improvements to our other 'bots.