BrainProg Programming Language
BrainProg is a graphical programming language for programming the BrainiBrick (or similar). The BrainiBrick is a programmable controller and is described elsewhere.
The BrainiBrick has 16 I/O "Ports" each of which has a 4-pin socket: two Input/Output bits, power and ground.
Everything described in this document has been implemented. However there is little user documentation.
The BrainProg compiler produces native code which runs on a PIC processor (typically the PIC16F877).
An explanation of the relationship between BrainProg and Subsumption can be viewed here.
The compiler and IDE for Brainprog can be downloaded.
A description of the Brainibrick that runs the BrainProg programming language can be viewed here.
The User Interface
The BrainProg main window displays one of several pages. Each page contains a "behaviour". There are three kinds of behaviour:
Here is a typical view of a Dataflow behaviour:
The main pane shows several executable behaviours making up a larger behaviour called "Main". The "Main" tab is ticked to show that this is the main behaviour.
The behaviours can be dragged around and connections can be dragged from the output of one behviour to the input of another. Behaviours can also be abutted to form connections. If several connections converge onto one input then they are prioritised in the way prescibed by Subsumption Architecture.
All behaviours run in parallel. Several copies of a single behaviour can be placed in a Dataflow behaviour. A Dataflow behaviour can contain other Dataflow behaviours (e.g. the Wheels behaviour is a Dataflow behaviour). Right-click on a behaviour to customise it.
Behaviours communicate by publishing data at their outputs. Connections do not pass "messages". An output variable can be read at any time by the behaviours to which it is connected. Executable behaviours run asynchronously in parallel.
Light Magenta connections specify the flow of byte values in the range 0 to 254. The number 255 is reserved and means that the connection is inactive. (i.e. "can be subsumed"). Dark Magenta connections specify the flow of boolean values (converging connections can be ANDed or ORed together). Right-click on a connection to change its priority.
Selecting the IO command displays the I/O dialog:
This shows a stylised representation of the BrainiBrick. Each of the buttons represents a Port. Click on the button until the peripheral you have plugged into that port appears. Alternatively, right-click on a button to see a list. The Motor peripherals can be customised (to set the "forward" direction) and so have a small button next to their name.
Here is quite a complicated Executable behaviour (it's the Brighter behaviour):
All Executable behaviours run in parallel. Rodney Brookes says we should think of them as finite state machines "augmented" with varaibles. That makes them into ordinary programs with a few odd features. In particular, notice that two of the "if stacks" do not have a "down" exit.
This behaviour has one input byte variable and one output byte variable. Input/output variables appear on the boundary of the behaviour. They are shown when the behaiour is placed in a Dataflow behaviour.
It also has one internal variable: 'P'.
Executable Behaviours are created by plugging executable "Blocks" together. When blocks are abutted, execution flows from right to left and from top to bottom. Red connections specify that execution flows from the output of one block (the right or bottom) to the input of another (the left or top).
The yellow and red circles show the start of the whole behaviour and jumps back to the start:
The pale yellow blocks perform assignments:
An If..then..else branch is performed by an IfComparison block:
Each Executable behaviour contains one Timer. The Timer counts "Ticks". One Ticks is 1/10th of a second.
The timer can be reset and the program can wait until the timer equals or exceeds a given value. A single block can do either of both:
An IfComparison block can test the timer:
If a stack of IfComparison blocks has no down exit then the behaviour waits until one of the comparisons becomes true:
The Reset-timer only occurs once when the stack is first entered.
If a then go to the right else go down
Wait until a then go to the right
Wait until a or b
if an If doesn't have an Else then the Else is "goto start of If-stack" and there will be a "yield" before the start of If-stack
Wait until (a and b) or c
Wait until (80 ticks and Light > P) or c
If you GoTo the start of an If-stack and the If-stack doesn't have an Else then the GoTo goes to the "yield" before the If-stack
When does Yield occur:
If an IF block has a downward exit then that is the ELSE. If it does not then the thread waits until the condition is true. For instance:
I/O Behaviours and Peripherals
An I/O behaviour is used to hide the details of interfacing to a particular kind of peripheral. It has the same function as a device driver in a conventional operating system.
All the information needed to create an I/O behaviour will be published. It is not expected that casual users will create I/O behaviours (or Text behaviours) - they are difficult to write and debug. Text and I/O behaviours are usually "hidden" from the user.
To be able to write Text and I/O behaviours, you must first understand how the memory is laid-out in the PIC and what code is generated by the BrainProg programming language. You must also be familiar with PIC16F877 programming.
Two of the banks of the PIC16F877 are filled with the "operating system" and libraries of useful code. Two banks can be filled with user programs and peripheral I/O code. The BrainiBrick compiler only links-in code for the peripherals that the user has selected.
The filename of an I/O Behaviour corresponds to the name of the kind of peripheral. For instance, the Motor I/O behaviour controls a motor attached to a port. Its text is held in Motor.bbo. Several files are associated with an I/O behaviour:
The BrainProg.exe program knows to present the Motor behaviour as a port option because it has found the Motor.bbo in the same directory as BrainProg.exe. You don't have to 'install' a bbo file - just copy it into the same directory as BrainProg.exe and (re)start BrainProg.
The bbo file specifies
Each Port (two bits) can be connected to "periperal": a sensor or effector. The connector is a 4-pin 0.1" Molex:
Each peripheral is self-contained. For instance, the motor-driver transistors are on a small pcb fastened to the back of the motor.
A peripheral can be as simple as a pair of on/off switches (e.g. bump sensors or antennae) or a pair of LEDs. It can contain extra hardware to drive an effector, e.g. an H-bridge for a motor.
More complex peripherals can include their own processing chips. For instance, an ultrasonic sonar peripheral would contain all the intelligence needed to emit and detect ultrasonic pulses and convert them into a distance measurement.
A protocol has been developed to simplify communications between the central BrainiBrick and an intelligent peripheral. It is a synchronous serial protocol which allows a rendezvous between the two processors. Both processors can spend most of their time doing other things but occasionally they will rendezvous and exchange a few bytes. (A simple serial protocol such as RS232 or I2C is unsuitable as such a receiver has to be capable of receiving at any time; it must contain a hardware UART or similar.)
The protocol will be published and sample peripheral PIC code will be made freely available. Developers do not have to use the BrainiBrick peripheral protocol but writing an I/O behaviour that uses the protocol is much simpler: the code is already in the BrainiBrick.
Questions or comments ? E-mail me at email@example.com
No part of this web page may be reproduced in any form or by any means, including photocopying and recording, for any purpose without the express written permission of Analogue Information Systems Ltd.
This web page is copyright © 2008 Analogue Information Systems Ltd., 1 Warrender Park Crescent, Edinburgh EH9 1DX, Scotland, UK, Tel: +44 (0) 131 228 6008. All Rights Reserved