Pretty frickin’ amazing considering that this was a big software development conference with lots of super-experienced developers competing, and our robot was mostly built by two kids – David and Jenny Kniberg (11yrs and 10yrs old) – the only kids at the conference. Their robot didn’t just win once – it outmaneuvered and outwrestled the competing robots in every match!
Here’s the final, Robit to the left:
So how could a newbie team win the competition so decisively?
Was it our robot-building skills? Definitely not. We build mindstorm stuff maybe 1-2 hours per YEAR. We are newbies.
Was it our coding skills? Probably not. We do have experience coding. But very little in Mindstorms. And this was a professional software development conference, so we definitely didn’t have the upper hand on coding skills.
Was it luck? Nope, blind luck wouldn’t help us win every match in such a decisive way.
Was it because we (the adults) work at Lego? Nope. Didn’t use any special parts, didn’t consult with any experts.
So what was it then?
A clear goal, a bit of research, and lots of integration testing!
First we set a goal. I wasn’t too optimistic – we’ve never done anything like this before, and I expected tough competition. So my suggestion was “Let’s built a robot that at least can stay in the ring and put up a fight!” So if/when we lose, it should not be because our robot ran itself out of the ring. Kids didn’t accept that – they said “No way. We’re gonna WIN!”.
Nevertheless, I convinced them to start in small steps. “How about you START by building a Minimum Viable Robot – one that can just move around the ring without falling out. Then keep testing and improving from there”. Agile, anyone?
We knew nothing about these kind of competitions so we started by looking at some youtube clips to see what kind of designs and strategies people were using. That gave us some ideas.
Dave invented his own robot from scratch and figured out how to program it to stay inside the ring. We weren’t sure how good it was at fighting though, so Jenny built us a second robot to use as sparring partner, the mindstorms base robot from the building instructions.
Upon integration testing in a makeshift ring, it became apparent that our first robot can’t win. It could navigate the ring beautifully, but it was simply too weak physically to budge the other robot.
So now we had a SmartBot (smart but weak) and a ToughBot (strong but stupid). We figured it’s easier to make the ToughBot smarter than to make the SmartBot tougher (because of the base construction). Plus we really are newbies at building these things, so we figured we’re best off using the default mindstorms bot as a base.
After installing some sensors and porting some of the code from SmartBot, our ToughBot was becoming a ToughSmartBot! We had our candidate! Robit was born! Time to train him up. The original SmartBot was gradually stripped of sensors and stuff and became DummyBot – our training dummy.
We gave ourselves a very concrete challenge – Robit must learn to beat DummyBot! Not just once, but repeatedly. Because if Robit can’t beat a weak stripped down half-broken robot that stands still or roams around randomly, how could it have a chance in the competition? So we went through a bunch of cycles of integration testing and tweaking the hardware and software. We kept failing over and over (often in funny ways), but every iteration we got a bit closer to winning. It was 100% learning by experimenting.
One interesting thing happened along the way. We noticed on the youtube clips that many robots tried to lift and topple their enemies. So Dave built a pretty elaborate construction for that, and I helped write the code to control the lifter. Upon integration testing though, to our surprise, it turned out that the lifter wasn’t strong enough to lift the DummyBot under any circumstances. We would need another motor to strengthen it and we didn’t have the patience to figure out how. Bummer!
So with some regret we removed all hardware and code related to that. In theory it was awesome, in practice it was useless. We wanted to keep Robit simple and focused on one thing – putting up a proper fight!
I hate to admit it, but I really didn’t think we would stand a chance at winning the competition, so my ambition level was really just to have a robot that would put up a fight before losing. I didn’t want to ruin the kids hope though, so I kind of kept that to myself.
After dumping the lifter, Jenny built a simpler solution based on a pic we found online – a simple static bulldozer-like slope at the front of the bot. We figured that would help us get under the wheels and push or topple the opponent. Nothing unique, most robots have something like that in the front.
More integration testing. Started working pretty nice, Robit could now push the DummyBot around! However it was hard to get the right angle of attack. So the software needed some work.
After lots of iterating, Robit ended up with the following winning formula:
- Start by driving forward and right for 2 seconds. That takes me a bit away from the line of sight of the other robot, and protects me from blind stupid robots that just charge without looking. Also gives me a better attack angle towards the side and rear of the opponent.
- Main loop (the proactive “win the game” loop)
- Turn clockwise until I see the opponent
- Attack as long as I see the opponent! The attack sequence is “move forward 3 seconds, then move back 1 second”.
- Secondary loop (the reactive “get me out of trouble” loop)
- Am I at the edge of the ring (color sensor sees white/blue ground)? If so interrupt the main loop and BACK UP!
- Is someone pushing me from behind (button sensors on my butt)? If so interrupt the main loop and BACK UP!
That’s it. A simple algorithm that turned out to generate a pretty advanced behaviour! During the actual competition, Robit managed to outmaneuver most opponents and keep hitting them from the side, and thereby avoid their weaponry. The “backup 1 second” part of the attack sequence was important because robots often get stuck in a deadlock while wrestling. By backing up and getting reoriented, Robit could turn and attack again and again, with new momentum each time. Once it even flipped a much heavier opponent on it’s head!
Here’s another example of a match – took about 10 seconds to outmaneuver and push out the opponent!
We were four people in the team – Dave and Jenny, me, and Lars. Although both Lars and I work at Lego (he is an employee and I am a part-time consultant), both of use are Mindstorm rookies. Due to time constraints Lars wasn’t able to participate in building or programming the robot, but during the competition he discovered that Robit had been damaged. If he hadn’t noticed and fixed that, we definitely wouldn’t have won.
As for my role, well, it was mostly coaching. I did end up writing most of the code, but that was in tight collaboration with the kids. Plus it wasn’t really that much code, once we figured out a good algorithm.
The big learning for me is how incredibly important and powerful it is to iterate fast! And to do end-to-end integration testing early and often. The usual agile stuff in other words.
We ended up with a robot that was mechanically one of the most simple ones in the tournament, and software that was also pretty simple but very well tested. So when Robit entered the arena he was already an experienced battle-scarred combatant! Robit kicked butt!
Here’s the source code – or “Robit’s Brain”
Initially I was hesitant to give it away, since we might compete again. But giving it away forces us to improve! So if we build another robot, it’s qualification test is if it can beat Robit in the test ring