Showing posts with label robotics. Show all posts
Showing posts with label robotics. Show all posts

Tuesday, 9 August 2011

Python and Tkinter: wonderful

Having time on my hands at the moment, and no work commitments - that's another story though - I decided to start taking a new look at the robotics stuff I was playing with a year or so ago.

I'd written nearly all of the code to make a six-legged robot - a hexapod - walk with various different gaits and postures - the so-called inverse kinematics. It was in straight C, since I intended it run on a little embedded CPU which had no support for C++, nor floating point for that matter. And I'd built a development environment, including visualisation for the leg movements, using Visual Studio.

Things have moved on since then, though. For one thing I've pretty much switched to Linux for my computing environment. For another, the Roboard has really become the obvious onboard computer - it is now available with Linux, and it offers a full-function x86 including floating point, in a tiny size that will fit in my fairly small hexapod. And since it supports full GCC, I can write the code in C++. The C code is just so cluttered - I can't for the life of me imagine why anyone would prefer to code in C. It's full of irrelevant details that make it hard to read and even harder to get it to work. So, a rewrite is called for.

The only problem, is the GUI that I'd painfully created using the Visual Studio tools. Painful because there are 6 legs, and each has numerous parameters and state variables. I'd created the dialog box from hell. Every tiny change meant nudging numerous components around to get it to look right. What a pain. But it was done, for now anyway.

That was when I thought about Tkinter, which I've never used before. I've become a huge fan of Python in the last couple of years, using it for anything where performance is not a big deal. I also wrote a very powerful Python-based scripting system for my now-defunct employer, using Boost Python. So using Python and Tkinter for the GUI was kind of an obvious thing to do.

Somewhere in the mists of history I acquired Python and Tkinter Programming, which I think is the definitive book on the topic. I skimmed that, and with frequent help from Google - especially this site - started putting my new GUI together.

What a pleasure! Tkinter automatically takes care of making a reasonable layout, given some general guidance through the pack and grid functions. You no longer have to think about the minutiae of positioning, or spend ages getting boxes to line up with each other. I just couldn't help putting together a bit of infrastructure for collections of config variables, so they are now super-easy - just a list of names and default values and Python and Tkinter take care of everything.

In total it has probably taken me about 6 hours to get everything together - but that included learning Tkinter from scratch and writing quite a bit of infrastructure. And now I have everything I need to control my inverse kinematics, and have an animated visualisation of what it's doing.

I'll never do GUIs any other way now. Tkinter is wonderful!

Sunday, 21 March 2010

Robots: Pololu 3pi

In the last couple of months I began to get a bit frustrated, technically speaking. The big programming project that I've been working on for the last year has finally come to an end - now we need to find some customers for it before we decide what to do next. So I scratched my head and decided that maybe it would be interesting to find out more about robotics.

A week later I'd read a lot and decided what I wanted to do to get started. I sent off an order to Trossen Robotics (there are of course quite a few suppliers, but these people seem to have a very good range) for a few bits and pieces from the Phidgets range, which are a great way to do robotics direct from a regular PC. I also ordered a Pololu 3pi, to get some quick experience with embedded programming. The 3pi is a small, round (10 cm across) robot made for following lines, with two independently-powered driving wheels, some infra-red sensors to see the lines, a microcontroller, some buttons and LEDs, and a tiny display.

I was amazed by how easy it is to work with the 3pi. I've never done anything with tiny microcontrollers before - my day job involves embedded programming too, but with a 400 MHz PPC with 1GB of memory, comparable to a PC. The 3pi has an Atmel 328p, which has 2 KBytes of DRAM and 32 KB of flash to hold the program. Compared to the PDP-8 I worked on in 1973, this is luxury. But when you're used to writing complex frameworks in C++ with Boost, it takes a bit of a mental gear-change.

Atmel provides a really excellent C compiler, actually GCC, and an IDE, loosely based on Visual Studio. It takes less than half an hour to download and install them, download the examples from the Pololu site, and be up and running. Then it was off to Office Depot (which I hate - never shop anywhere with "Depot" in the name - but they are just around the corner) for some paste board and black tape. Within a couple of hours I had my 3pi running round mazes, using the sample code.

"Every schoolboy knows" that if a maze has no loops in it, you can solve it by just turning left (or right) at every opportunity, until you reach the goal. So the interesting challenge is to solve mazes that do contain loops. The wall-hugging strategy will never actually get stuck in a loop, but it won't find the goal either, except by chance. (Actually it does kind of loop, because eventually it gets back to the start of the maze, and since it can't recognize that, it just starts over).

Solving looped mazes requires knowledge of absolute position. (If you have a useful upper bound on the size of the maze, I believe you can do it without such knowledge, but it's a lot harder to figure out how, and will take a lot longer to find a solution). If you know where you are, then you know when you reach an intersection you have already been to, assuming you have enough memory to keep track. (Remember, only 2 Kbytes of DRAM). The 3pi has no explicit position measurement, not even encoders on the motor shafts. The only way to track position is to integrate the motor speeds. It took me about a week to come up with working code to do this. It would be much easier to do in floating point - but the cost in both code space and computation time is unacceptable. I absolutely hate doing scaled integer math, it's a constant trap of overflows and underflows and just plain getting it wrong. But it's the only way.

Once I eventually got the code to work, I was surprised by how little of the available compute power it took. According to the simulator that comes with the Atmel IDE, keeping track of position every 10 mS takes about 0.5mS, i.e. 5% of the CPU. That's good, because it leaves plenty for doing other things, such as following a line, and keeping track of the maze structure.

Although the IDE includes a simulator, in the end I had to get the code working with Visual Studio as well, so I could get a "brain dump" of the computations at every 10 mS interval without having to step through them with the debugger. It's very easy to do this - just create Visual Studio and Atmel IDE projects in the same directory, and they work off the same source files. Of course a few #ifdefs are required to get things to compile in both environments.

One complication I ran into is that the motor speed response is not linear with the applied voltage - which is not a surprise. At lower voltages, a greater proportion of the power is used to overcome friction. Also, the two motors are not absolutely identical, so if you apply the same voltage to both of them, the 3pi gradually curves around. I wrote some code to calibrate the motors, which for the moment is a manual process although it would be a lot better to automate it. With the motors calibrated, it looks as though it should be possible to get a position estimate that is reliable to within about 1%. That should be good enough for mazes up to a couple of meters across.

That's about as far as I've got, at the moment. I'm now in the middle of writing the code to actually solve the maze. This is logically tricky but at least it doesn't involve any fixed-point math. More on that later, if and when I get the whole system to work.