Tuesday, July 8, 2008

How it's all supposed to work...

I've now reached the point in programming the robot where I have to commit to two very important things; a language to write in and a formal structure for development.

The first part is easy; I have fallen for the charms of Python, and whilst I am not a veteran explorer of its abilities, I am progressing very quickly and I have not - yet - hit any brick walls!

The second part is not so easy. I had to come up with a framework for testing out a multitude of ideas that did not just result in a longer and longer .py file. This lead me into the depths of Python's Modules, Classes and Threads. Thankfully, Python - from what I have played with so far - seems to have a very elegant interface for developing and using these elements.

To create an expandable and flexible development platform, I have decided to use an adaptation a few of Rodney Brooks' ideas on Subsumption Architecture. Generalising, the resultant behaviour of a Subsumption Architecture comes from basic interactions between separate and prioritised behavioural layers. Higher priority behaviours can overrule lower priority behaviours, allowing for a "don't hit the wall" behaviour to overrule a "find the ball" behaviour when needed. This approach tends to create very complex emergent behaviours from very basic underpinnings.

Now, here is the problem. For my robot, I wanted to have both the prioritised behaviours and the ability to sequence behaviours. This would allow for the development and refinement of areas of a behaviour independently - in a series of different classes. An example of this might be (The numbers indicate the priorities for the behaviours).

1. Don't hit stuff
2. Centre robot on a coloured target
3. Plan a path towards the target
4. Drive to the target
5. Play a tune of celebration
6. Stop

Looking at this, a problem arises. Obviously "Don't hit stuff" should overrule all the other behaviours at any point, but the rest of the behaviours should only happen once before handing control over to the next behaviour. I could solve this by combining the behaviours 2-6 into one behavioural layer, but there is a decent chance that this will evolve into a obscenely large .py file. What I really wanted was a series of sequential "one-shot" behaviours working in parallel with a collection of "full-time" behaviours for accident avoidance etc.

To solve this problem, I have decided on the following framework:
  • Each behaviour will be implemented as a Python thread. There will also be a motor-driver thread. All threads are loaded and started at program initialisation. All threads will have a given priority.
  • All behaviours will transmit movement commands to a common Queue (the recommended way for Python inter-thread communications) along with that behaviour's priority.
  • Periodically, the motor-driving thread will read the highest priority command from the Queue, acting on it and clearing the Queue.
  • Any "one-shot" threads simply stop adding commands once their goal is achieved, possibly even exiting to save memory/processor overhead.
There is more to it than that, but that is the general idea. I have converted most of my existing code to a series of Classes in Modules, and have successfully got them working as Threads. Currently I am testing out the inter-thread communications via the Queue, and I will post code shortly.

Finally, on a completely different note, I have convinced my University to allow me to do a 4th-year Engineering subject, Intelligent Systems, as a 3rd-year elective in my 3-year Bachelor of Computing. This starts next Monday, and I am absolutely pumped!