Recent Changes - Search:

Tracking

Hardware

Software

Mega Plan

Etc.

Brainstem

The Brainstem can be controlled in three basic ways:

  • Via I2C
  • Via its Serial Port (which routes incoming information to I2C internally)
  • Via small downloaded programs written in a subset of C called "TEA"

We take advantage of all three of these options. Using I2C or Serial, the Gumstix will query the Brainstem's current sensor values or command it to move its servos. Additionally we download a TEA program onto the Brainstem which maintains a current count of incoming encoder values which we can query and reset from the Gumstix.

Provided Acroname Software

All you need to know about Brainstem can be found on Acroname's Brainstem reference page. Additionally, the following software utilities are available from Acroname for Windows, WinCE, MacOS X, PalmOS and Linux.

The GP application provided in Acroname's Brainstem software distribution allows the user to view readings from the various inputs such as analog output, digital outputs, and servo readings. With the sliders the GP GUI provides, the user can also adjust servo inputs and other related servo configuration such as range, etc. Whatever changes are made in the GP GUI session with the Brainstem can ultimately be saved to the Brainstem permanently by clicking the Commit to EEPROM button in the GP GUI. Playing with the GP GUI and your robot's servos and sensors can help you get an understanding of what kind of values you should be sending or receiving from them.

The Console is a text-based GUI that allows the user to send Brainstem commands, compile TEA programs, test TEA programs, and make permanent changes to the Brainstem EEPROM. From the Console the user can send sequences of numbers which represent commands to the Brainstem.

The user can compile TEA programs, with the steep command, from the Console into native assembly language for the Brainstem microprocessor. If there are any errors in the TEA code, the Brainstem console will report them to the user via the GUI. The Console will print to the screen whatever commands are sent to it from the Brainstem. When running, this can include debug statements placed in the TEA program. A TEA program is essentially a C program that can make TEA Language calls on the Brainstem. A TEA program may also include assembly language for the Brainstem, known as TEAvm, to perform absolute lowest level instructions on the Brainstem.

To compile a TEA program from the Console the user must place a copy of the TEA program in the aUser directory of the installed Brainstem software distribution, preferably with an extension of .tea. Then start up the console and type in steep <filename> which assumes a .tea extension to the program. If there are any errors during the compilation phase they will be reported on the Console GUI. The user can then correct the errors and try compiling again. If the compilation is successful the resulting object code to be eventually loaded and launched on the Brainstem will be placed in the aObject directory of the installed Brainstem software distribution with an extension of .cup.

After compiling, a user can load compiled TEA programs into job slots on the Brainstem processor and then launch those programs and even pass in simple command line arguments to the programs when launching from the GUI.

Setting up Software

You set up the Console and GP programs by placing in their respective directories a filed called Console.config or GP.config which contains a single line of text:

portname = serialDevice

where serialDevice is your device (like 'COM1').

Note: If you are using the popular Keyspan USB Serial Interface, it installs as follows:

  • On OS X, it installs a device in /dev/ called tty.USA19H181P1.1 or tty.USA19H181P2.1, depending on which USB port it's plugged into.
  • On Linux, In Linux it installs on /dev/ttyUSB0.
  • On Windows, it configures as COM3, COM4 or COM5, but can be changed in the Hardware Manager.

Note: To do the Java drivers, you need Sun's javax.comm library installed. OS X binaries for this can be found here.

Windows The Windows (win32) GP Program and Console works adequately. The biggest problem you're likely to encounter is COM port identification. Since the GP console and the demo look for COM1 by default they give you message saying unknown serial port if you're only connection is COM2. Check out your hardware configuration for this. Another problem is that the java comm api had instructions for where to put the comm.jar file and javax.comm.properties, but this wasn't enough. It worked for us after copying these files to lib and ext files in the java directory. My machine needed the files in 4 places. After these issues got worked out everything worked fine.

OS X On OS X, there's a bug in Acroname's Console and GP programs. They're looking for a library called IO.framework and expect it to be in a directory called /Users/acroname/host/aDebug/aMac/. Otherwise they won't start up. You will need to link the directory holding the IO.framework library to that path to trick them.

Another workaround for this bug is to place the *.framework directories in ~/Library/Frameworks, where ~ is the root of your group's home directory. It's working fine on a system where /Users/acroname/ doesn't even exist.

Linux There is no linux build of the GP application. However, the win32 version runs under wine by mapping /dev/ttyUSB0 to com1 if you are using the Keyspan USB to Serial adapters. You can do this by issuing the following command logged in as the user that will be running the GP or console program (Note: com1 must be in lowercase):

ln -s /dev/ttyUSB0 ~/.wine/dosdevices/com1

The only catch is that you have to turn the robot on first, otherwise the GP may not get a link. The console application works fine under wine as well with the same com1 -> /dev/ttyUSB0 mapping described above for the GP application.

On Linux, it's slightly more complicated than on OS X to get your programs compiled and linking properly with the brainstem C dev kit. Here's a quick guide on how to set your projects up so that they'll compile correctly.

  1. Download the Acroname Brainstem C Development Kit from Acroname. Then decompress it. This will give you a folder called "brainstem" where you will work out of.
  2. Do an initial "make" on the root of "brainstem". Just type "make" to compile the C libraries.
  3. Make a folder hierarchy to work out of. Follow the instructions below to create a folder hierarchy to store and compile your project - replace "programname" with your program name
 cd brainstem/
 # create folders for your project
 mkdir projects
 mkdir projects/programname
 # note: this last folder *must* be named aUnix
 mkdir projects/programname/aUnix

Create your program This file must be named unix_programname.c where programname is your program name, and placed in the aUnix folder you just created. Here's an example to get started:

 /* brainstem/projects/programname/aUnix/unix_programname.c  Hello World */
 #include "aStem.h"      /* stem library header   */
 #include "aServo.h"     /* servo control routines */
 #include "aDigital.h"   /* digital I/O routines */
 #include "aAnalog.h"

 int main(int argc, char* argv[]) {
         printf("Hello World!\n"); return 0;
 }

Create the precompiler headers. Yes, you MUST do this. Again, replace "programname" with your program name. Here are the examples:

 /* brainstem/projects/programname/aUnix/unix_programname_pfxd.h */
 #define aDEBUG
 #define aUNIX 

/* brainstem/projects/programname/aUnix/unix_programname_pfx.h */

 #define aUNIX 

Create your makefile now. NOTE: Again, you have to replace all places where it says "programname" with your program name, including the place where it says unix_programname.c. You also have to modify other variables in here for your own ARCH / CC / SHELL locations.

 # brainstem/projects/programname/makefile
 SHELL=/bin/sh
 CC=arm-linux-gcc
 ARCH=ARM
 PLATFORM=Linux

 ROOT = ../../
 PROGNAME = programname

 INCLUDES = -IaCommon -IaUnix -I../../aCommon -I../../aUnix \ 
-I../../aIO/aCommon -I../../aIO/aUnix -I../../aStem/aCommon \
-I../../aStem/aUnix -I../../aTEAvm/aCommon \
-I../../aTEAvm/aUnix -I../../aDebug/aSystem LIBRARIES = -lm -laIO -laStem VPATH = ./aCommon:./aUnix:../../aCommon:../../aDebug/aUnix/$(ARCH)/ SOURCES = aAssert.c aMemHandleDebug.c aUtil.c aStemCore.c aServo.c \
aDigital.c aAnalog.c unix_$(PROGNAME).c include $(ROOT)make_program.Linux

You can now just type:

 make 

Running your program. The first thing you'll wonder the first time you compile is a large stream of errors, because it can't find a bunch of stuff. No worries, the make process should make the stuff it needs for later. It should compile on subsequent runs without error. The second thing you will wonder is... "where's my program?" The answer is in: brainstem/aRelease/aUnix/i686. You have to run your program like this:

 ./run programname 

Software Libraries

Acroname provides four main software libraries for use with the Brainstem:

TEA and TEAVM TEA is essentially C. TEA is the language that Acroname provides a compiler for, called steep, to change TEA code into runnable code on the Brainstem. Similar to C, in TEA an asm block contains assembly language commands to be compiled into the runnable code and in this case Acroname calls the assembly used for the Brainstem, TEAvm. TEAvm is just the set of processor level instructions and parameters the Brainstem processor supports. Writing code in TEAvm is how to code at the lowest level on the Brainstem. One thing to keep in mind about compiled TEA code with or without TEAvm assembly in it is that the maximum space a program has to run on the Brainstem is 1K per program. Several programs can be run at the same time on the Brainstem but the 1K limitation holds for each individual process. Obviously, complicated code will not fit on the Brainstem so use TEA programs for low level chores that make sense to run on the Brainstem such as the wheel encoding that was used in this project. The good news is the steep compiler will tell you how big the image is on a successful compile. However, don't push it past 512 bytes (0.5Kb) if it can be helped because this does not include space for the stack each program needs to run on the Brainstem with.

Java library The java distribution provided should be installed in the aJava directory in the home of wherever the user installs the Brainstem software. acroname.jar is the main jar file provided by Acroname which encapsulates sending and receiving various commands to the Brainstem from a remote Java application located on another processor such as a client PC, Mac, or embedded processor such as the Gumstix. There is a java file named gp_example.java provided by Acroname which demonstrates using the acroname.jar API in Java. Also, Acroname provides the source code to their acroname.jar library in the aJava/acroname folder so you can both modify their library code and more importantly understand how to communicate with the Brainstem using the Java Serial classes.

C library similar to the Java library but for the C language and again this allows remote C programs located on another processor to send and receive commands from the Brainstem.

Changing the I2C Address on the Brainstem

If you're going to command the Brainstem via I2C from the Gumstix rather than via the Serial port, you'll need to change the Brainstem's I2C address because it conflicts with the Gumstix's address.

I2C addresses are 7 bits. The Brainstem stores these in the upper 7 bits of a byte, which is why they only allow even addresses. To determine the real I2C bus address, divide the Brainstem address by 2. The default address is 2, which corresponds to a bus address of 1. That's the same address which is used by the Gumstix, so we're going to change it on the Brainstem.

Power up the Brainstem (by connecting it to the battery or by plugging in a 5-7V power supply). Connect your computer to the Brainstem over its serial port. Launch the Brainstem Console application (you can get this from Acroname.

  1. Type 173 to view the current address. It should reply "< 02:".
  2. Type 2 18 0 4 to change the address to 4 (I2C bus address 2).
  3. Type 173 to view the current address. It should now reply "< 04:".
  4. Type 4 18 1 2 to change the router address to 2.
  5. Type 4 18 5 1 to switch to internal heartbeat.
  6. Type 4 19 to save the changes to EEPROM

Turn the power to the Brainstem off, and then back on again. Verify that the address is 4 by typing 173 in the Console application.

To use the serial port again you will need to switch the Brainstem's address back to normal so its on-board serial port router can find it again. The sequence of commands to do this is:

  1. Type 173 to view the current address. It should reply "< 04:".
  2. Type 4 18 1 4 to switch the router address to 4 (the Brainstem)
  3. Type 4 18 5 0 to switch to external heartbeat
  4. Type 4 19 to save the changes to EEPROM

Quadrature Wheel Encoder using TEA

The Wheel watcher software uses quadrature encoding to determine the number of gradations your wheel has passed, and thus, your wheel speed. Quadrature Encoding means the watcher software can determine your direction (forward of backward) in addition to velocity.

The quadAandB program assume that left and right counters will be stored in scratch pads 28 and 30 respectively with reset pads at 24 and 26 respectively. It also assumes that channel A and B for the left encoder will be plugged into digital ports 0 and 1 respectively, and that the channel A and B for the right encoder will be plugged into digital ports 2 and 3 respectively. If for some reason, you do need to change these constants you can modify the #define's at the top of quadAandB.tea, recompile in the console with the steep command mentioned above and it will use the new constants.

The resolution provided by this scheme is 128 per revolution. Since the quad encoder software is looking at both channel A and B it can also determine the direction the wheel has rotated and this is indicated by the counter incrementing or decrementing.

Also, the range of the scratch pads allows for a range between -16384 and 16383 I believe. Therefore, if users of this software do not keep an eye on the current counts they can overflow or underflow so it is important to reset the counters if necessary. I tested this with the servo going full blast in one direction and it lasted a little over 2 minutes for it to encounter this scenario.

Encoder Code Installation

The code is available for download here and is listed further down in this page for your perusal. There are to two required programs and a test program:

  • "quadAandB.tea" -- The actual program to count wheel ticks using channel A and B from the encoder.
  • "launch_quadAandB.tea" -- The program run at Brainstem boot to load the watcher program.
  • "test_quadAandB.tea" -- Used to verify, on the Brainstem, that the counting is working right.

To install and run the software, do the following:

  1. Copy launch_quadAandB.tea and quadAandB.tea to the aUser directory for the Console software provided by Acroname
  2. Start the Console
  3. steep "quadAandB"
  4. steep "launch_quadAandB"
  5. load "quadAandB" 2 1
  6. load "launch_quadAandB" 2 0
  7. launch 2 0

The quadAandB program is now running and keeping counts of how far the wheel(s) turn.

The test application can verify that the installation was successful and the wheel watcher is running. The test program checks the right wheel and assumes the A and B channels from your right wheel and plugged into digital port 2 and 3, respectively. To run this test program do the following:

  1. Copy test_quadAandB.tea to the aUser directory for the Console software provided by Acroname
  2. Start the Console
  3. steep "test_quadAandB"
  4. load "test_quadAandB" 2 2
  5. launch 2 2

After you have the quad encoding TEA programs loaded you can do the following to make them bootstrap programs, which means they will automatically start the next time we reset the Brainstem. Just type these two lines at the Console after you have loaded the TEA programs onto the Brainstem:

2 18 15 0

2 19

If you turn the brainstem off, the next time you turn it back on the Brainstem will launch the launch program which will kick off the encoder and it will be running immediately. You can test this again by loading and launching the test_quadAandB program and seeing the counters and reset working correctly.

The Encoder Code Listings

(For your reading enjoyment. A small portion of the code is copyright by Acroname and is distributed with their permission.)

quadAandB.tea
 #include <aMulti.tea>

 #define AWWDEFS_LMO_CHA 0 
 #define AWWDEFS_LMO_CHB 1  
 #define AWWDEFS_RMO_CHA 2  
 #define AWWDEFS_RMO_CHB 3  
 #define AWWDEFS_QUADCT_AB 2  
 #define AWWDEFS_B_AND_DIR 1  
 #define AWWDEFS_A_AND_B 0  
 #define AWWDEFS_LMO_ENC_RESET 24  
 #define AWWDEFS_LMO_ENC 28  
 #define AWWDEFS_RMO_ENC_RESET 26 
 #define AWWDEFS_RMO_ENC 30  
 #define AWWDEFS_LMO_DIR 1  
 #define AWWDEFS_RMO_DIR 3

 /* quad count lookup table */ 
 char b0000 = 0; 
 char b0001 = -1; 
 char b0010 = 1; 
 char b0011 = 0; 
 char b0100 = 1; 
 char b0101 = 0; 
 char b0110 = 0; 
 char b0111 = -1; 
 char b1000 = -1; 
 char b1001 = 0; 
 char b1010 = 0; 
 char b1011 = 1; 
 char b1100 = 0; 
 char b1101 = 1; 
 char b1110 = -1; 
 char b1111 = 0;

 void main(char callingProc) {
   char preR = 0;
   char preL = 0;
   char tempR = 0;
   char tempL = 0;
   aMulti_Wait();

   while (1) {

     if(aPad_ReadInt(AWWDEFS_LMO_ENC_RESET) == 1)
     {
       aPad_WriteInt(AWWDEFS_LMO_ENC, 0);
       aPad_WriteInt(AWWDEFS_LMO_ENC_RESET, 0);
     }

     /* check left encoder */
     asm {

       pushmb    aPortDigital
                 + AWWDEFS_LMO_CHA * aPortDigitalBlockSize
                 + aOffsetDigitalIO
       pushmb    aPortDigital
                 + AWWDEFS_LMO_CHB * aPortDigitalBlockSize
                 + aOffsetDigitalIO
       pushlb    1
       rlb
       orb               /* s = ((B << 1) | A), offset = 1 */
       pushsb    1
       popbs     2       /* tempL = s */
       pushlb    2
       rlb               /* s <<= 2 */
       pushsb    4
       orb               /* s |= preL */
       convbs
       incs      2       /* offset to start of array */
       pushsbax
       convbs
       pushms    aPortScratch + AWWDEFS_LMO_ENC
       adds
       popsm     aPortScratch + AWWDEFS_LMO_ENC
       pushsb    1
       popbs     3       /* preL = s */
     }

     /* check right encoder */

     if(aPad_ReadInt(AWWDEFS_RMO_ENC_RESET) == 1)
     {
       aPad_WriteInt(AWWDEFS_RMO_ENC, 0);
       aPad_WriteInt(AWWDEFS_RMO_ENC_RESET, 0);
     }

     asm {

       pushmb    aPortDigital
                 + AWWDEFS_RMO_CHA * aPortDigitalBlockSize
                 + aOffsetDigitalIO
       pushmb    aPortDigital
                 + AWWDEFS_RMO_CHB * aPortDigitalBlockSize
                 + aOffsetDigitalIO
       pushlb    1
       rlb
       orb               /* s = ((B << 1) | A), offset = 1 */
       pushsb    1
       popbs     3       /* tempR = s */
       pushlb    2
       rlb               /* s <<= 2 */
       pushsb    5
       orb               /* s |= preR */
       convbs
       incs      2       /* offset to start of array */
       pushsbax
       convbs
       pushms    aPortScratch + AWWDEFS_RMO_ENC
       adds
       popsm     aPortScratch + AWWDEFS_RMO_ENC
       pushsb    2
       popbs     4       /* preR = s */
     }
   }
 } 
launch_quadAandB.tea
 /* Launches the wheel watcher encoder quad A and B TEA program */

 #include <aMulti.tea>

 void main()
 {
   /* launch wheel watcher encoder TEA program */
   /* (program 1 in process slot 3) */

   aMulti_Spawn(1,3);
   aMulti_Signal(3, 0);
 }
test_quadAandB.tea
 #include <aCore.tea>
 #include <aMulti.tea> 
 #include <aPrint.tea> 
 #include <aServo.tea> 
 #include <aWWDefs.tea> 


 void main() {

   /* launch Wheel Watcher task */
   /* (program 1 in process slot 3) */

   int j=0;
   int Iterations = 0;

   /* 
   aMulti_Spawn(1,3);
   aMulti_Signal(3,AWWDEFS_QUADCT_AB);
   */

   /* start servo  stop position is 122 for now*/
   aServo_SetAbsolute(3, (unsigned char)122);

   /* show encoder counts */
   while (1) {

     Iterations++;

     aPrint_IntDec(aPad_ReadInt(AWWDEFS_RMO_ENC));
     aPrint_Char(',');
     aPrint_IntDec(Iterations);
     aPrint_Char('\n');
     aCore_Sleep(3000);
     if (Iterations == 29)
       aPad_WriteInt(26, 1);
     else if (Iterations == 41)
       aPad_WriteInt(26, 1);
     else if (Iterations == 49)
       aServo_SetAbsolute(3, (unsigned char) 135);
     else if (Iterations == 58)
       aPad_WriteInt(26, 1);
     else if (Iterations == 65)
       aServo_SetAbsolute(3, (unsigned char) 250);
     else if(Iterations == 92)
       aPad_WriteInt(26, 1);
     else if (Iterations == 189)
     break;
   }

 aServo_SetAbsolute(3, (unsigned char) 135);

 }
Edit - History - Print - Recent Changes - Search
Page last modified on June 18, 2005, at 02:19 PM