Re: Gizmo hardware problems

John Carmack <[email protected]>
Newsgroups gmane.technology.erps
Message-ID <[email protected]>
At 09:57 PM 7/26/2004 -0700, you wrote:
>Well, I wrote the flight control code. I have no idea if it works.
>
>We went to test it, but it didn't initialize the IMU correctly. So I
>went back to the imutest code and tried that. Works great from my laptop
>and the build server, but not from the PC/104. We checked everything we
>could think of, even brought out the O-scope to look at what was being
>sent to the IMU. The only difference between serial signals from my
>laptop and the PC/104 is the PC/104 is running +/-9V the laptop +/-5V.
>The build server runs +/-12V.  Unfortunately we didn't have a breakout
>box to see both sides of the serial at the same time.
>
>Dave

Are you absolutely sure the flight computer is initializing the serial port 
correctly?  Have you had it talking to a laptop over a null modem 
cable?  Are you sure it isn't something silly like having an unkeyed 10 pin 
ribbon connector on upside down to the CPU board?  Make sure you can cat 
junk to /dev/ttyS0 and see it on a laptop hyperterminal session.

I don't have a recent version of my flight computer code on this computer, 
but here is a couple-year-old version of my xbow code for linux.  This is 
the previous generation FOG, things changed a bit in the updated one, and 
I'm sure your version is somewhat different.  The baud rate change 
complicates things, and there is certainly no need to do that on the low 
bandwidth MEMS gyros you have.

Every sensor and actuator I use has built in test-on-port functionality in 
the flight computer executable that is separate from the normal flightcode, 
which is very useful when you are reconfiguring your flight systems.  Just 
a few hours ago, I was using the -testIgnition function to work on a balky 
ignition system that we changed around, for instance.

Out of curiosity, do you treat your flight computer like a traditional 
embedded system that you cross compile for, or do you have a full 
development environment on it?  I really like doing my builds and debugging 
directly on the flight computer, but I don't use a linux laptop like some 
of the ERPS folks do.

John Carmack



/*
====================
OpenSerialPort

Opens a com port

PortNumber is 1 based, ie COM1, COM2 == /dev/ttyS0, /dev/ttyS1

Returns the file descriptor, or exits with an error
====================
*/
int OpenSerialPort( int portNumber, int cflag, int iflag, int oflag, int 
lflag  ) {
         struct termios ios;
         struct serial_struct serinfo;
         char    filename[1024];
         int     fd;

         sprintf( filename, "/dev/ttyS%i", portNumber-1 );

         // O_NOCTTY prevents ^c from interrupting
         fd = open( filename, O_RDWR | O_NOCTTY );
         if ( fd == -1 ) {
                 perror( "com port open " );
                 ExitFlightcom();
         }

         // set low latency mode, so we don't get 10msec scheduling 
granularity
         // this is the same as 'setserial /dev/ttyS0 low_latency',
         // but it won't complete if we aren't root
         if ( ioctl( fd, TIOCGSERIAL, &serinfo ) < 0 ) {
                 perror( "Cannot get serial info " );
                 ExitFlightcom();
         }
         serinfo.flags |= ASYNC_LOW_LATENCY;
         if ( ioctl( fd, TIOCSSERIAL, &serinfo ) < 0 ) {
                 perror(" Cannot set serial info " );
                 ExitFlightcom();
         }

         // set the baud rate
         memset( &ios, 0, sizeof( ios ) );

         // CLOCAL : no modem control
         // CREAD : enable reading
         ios.c_cflag = cflag | CLOCAL | CREAD;

         // IGNBRK : ignore serial breaks
         // IGNPAR : ignore bytes with parity errors
         ios.c_iflag = iflag | IGNBRK | IGNPAR;

         // raw output
         ios.c_oflag = oflag;

         // ICANON : cannonical input processing
         ios.c_lflag = lflag; /* ICANON; */

         // dump anything in the buffer
         tcflush( fd, TCIFLUSH );

         // set the new data
         tcsetattr( fd, TCSANOW, &ios );

         // dump anything in the buffer after the change
         tcflush( fd, TCIFLUSH );

         return fd;
}



#include "flightcom.h"

static int              crossbowHandle;

#define DATA_MASK       1023

static unsigned char    data[DATA_MASK+1];
static int              dataHead;
static int              dataTail;
static int              isSynced;
static int              lastPacketDataTail;

#define PACKET_LENGTH   18
// including header and checksum

xbow_t  xbow;

static int              highRate = 1;
static int              BaudRate = B57600;

/*
==============
SetHighBaud
==============
*/
static void SetHighBaud( void ) {
         struct termios ios;

         // set the baud rate
         memset( &ios, 0, sizeof( ios ) );

         // CLOCAL : no modem control
         // CREAD : enable reading
         ios.c_cflag = BaudRate | CS8 | CLOCAL | CREAD;

         // IGNBRK : ignore serial breaks
         // IGNPAR : ignore bytes with parity errors
         ios.c_iflag = 0 | IGNBRK | IGNPAR;

         // raw output
         ios.c_oflag = 0;

         // ICANON : cannonical input processing
         ios.c_lflag = 0; /* ICANON; */

         // dump anything in the buffer
         tcflush( crossbowHandle, TCIFLUSH );

         // set the new data
         tcsetattr( crossbowHandle, TCSANOW, &ios );

         // dump anything in the buffer after the change
         tcflush( crossbowHandle, TCIFLUSH );

         sleep( 1 );
}

/*
==============
ReadResponseWithTimeout
==============
*/
static int ReadResponseWithTimeout( int msec ) {
         unsigned char   c;
         int             ioCount;
         int             start, now;

         c = 0;
         start = Milliseconds();
         while( 1 ) {
                 ioCount = read( crossbowHandle, &c, sizeof(c) );
                 if ( ioCount == 1 ) {
                         break;
                 }
                 now = Milliseconds();
                 if ( now - start > msec ) {
                         printf( "timeout.\n" );
                         return -1;
                 }
         }

         return c;
}

/*
==============
InitCrossbow
==============
*/
void OpenCrossbow( int portNumber ) {
         char    cmd[2];
         unsigned char   c;
         unsigned char   junk[4096];
         int             start, now;

         printf( "OpenCrossbow on port %i\n", portNumber );

         crossbowHandle = OpenSerialPort( portNumber,
                 B38400 | CS8,   // cflag
                 0,                              // iflag
                 0,                              // oflag
                 0 );                    // lflag (raw mode)

         printf( "Trying reset at normal baud rate\n" );

         // send a blind reset
         cmd[0] = 'R';
         write( crossbowHandle, cmd, 1 );
         sleep( 1 );

         // dump any buffered junk
         read( crossbowHandle, &junk, sizeof(junk) );

         // now send a reset that we expect to get the proper response for
         cmd[0] = 'R';
         write( crossbowHandle, cmd, 1 );
         c = ReadResponseWithTimeout( 1000 );
         if ( c != 'H' ) {
                 printf( "bad response\n" );

                 if ( highRate ) {
                         printf( "Trying reset at high baud rate\n" );
                         SetHighBaud();

                         // send a blind reset
                         cmd[0] = 'R';
                         write( crossbowHandle, cmd, 1 );
                         sleep( 1 );

                         // dump any buffered junk
                         read( crossbowHandle, &junk, sizeof(junk) );

                         // now send a reset that we expect to get the 
proper response for
                         cmd[0] = 'R';
                         write( crossbowHandle, cmd, 1 );
                         c = ReadResponseWithTimeout( 1000 );
                         if ( c != 'H' ) {
                                 printf( "bad response.\n" );
                                 exit( 1 );
                         }
                 } else {
                         exit( 1 );
                 }
         } else if ( highRate ) {
                 // change baud rate
                 printf( "changing baud rate\n" );
                 cmd[0] = 'b';
                 write( crossbowHandle, cmd, 1 );

                 sleep( 1 );

                 SetHighBaud();

                 cmd[0] = 'a';
                 write( crossbowHandle, cmd, 1 );
                 c = ReadResponseWithTimeout( 1000 );
                 if ( c != 'A' ) {
                         printf( "bad response\n" );
                         exit( 1 );
                 }
         }

         // zero gyro bias
         cmd[0] = 'z';
         cmd[1] = (char)200;     // samples to average (*10)
         write( crossbowHandle, cmd, 2 );

         printf( "zeroing gyro bias...\n" );
         c = ReadResponseWithTimeout( 10000 );
         if ( c != 'Z' ) {
                 printf( "bad response\n" );
                 exit( 1 );
         }

         // program it for scaled data output
         cmd[0] = 'c';
         write( crossbowHandle, cmd, 1 );
         c = ReadResponseWithTimeout( 100 );
         if ( c != 'C' ) {
                 printf( "bad response\n" );
                 exit( 1 );
         }

         // program it for continuous data output
         cmd[0] = 'C';
         write( crossbowHandle, cmd, 1 );

         // we must find a packet break
         isSynced = 0;
         memset( &xbow, 0, sizeof( xbow ) );
         data[dataHead & DATA_MASK ] = 123;      // fail first checksum

         // get the first packet
         printf( "getting first packet.\n" );
         start = Milliseconds();
         while( !UpdateCrossbow() ) {
                 now = Milliseconds();
                 if ( now - start > 1000 ) {
                         printf( "timeout.\n" );
                         exit( 1 );
                 }
         }
         printf( "Crossbow initialization complete\n" );

}

/*
==============
PacketChecksums
==============
*/
static int PacketChecksums( void ) {
         int             check;
         int             i;

         check = 0;
         for ( i = 0 ; i < 16 ; i++ ) {
                 check += data[ ( dataTail - 17 + i ) & DATA_MASK ];
         }
         check &= 255;

         if ( check != data[ ( dataTail - 1 ) & DATA_MASK ] ) {
                 return 0;
         }
         return 1;
}

/*
==============
UpdateCrossbow
==============
*/
int UpdateCrossbow( void ) {
         int             i;
         int             ioCount;
         unsigned char   c;
         unsigned char   readData[PACKET_LENGTH];

         // see if we have a complete packet ready to return
         while( 1 ) {
                 while( dataTail < dataHead ) {
                         dataTail++;
                         c = data[ dataTail & DATA_MASK ];

                         // if we are synced, only check for packet breaks 
where
                         // we expect them
                         if ( isSynced ) {
                                 if ( dataTail != lastPacketDataTail + 
PACKET_LENGTH ) {
                                         continue;
                                 }
                                 // if this isn't a new packet, we lost sync
                                 if ( c != 0xff ) {
                                         printf( "UpdateCrossbow: lost 
sync\n" );
//                      exit( 1 );
                                         isSynced = 0;
                                         continue;
                                 }
                                 if ( !PacketChecksums() ) {
                                         printf( "UpdateCrossbow: failed 
checksum\n" );
//                      exit( 1 );
                                         isSynced = 0;
                                         continue;
                                 }
                         } else {
                                 // see if this is a valid packet
                                 if ( c  != 0xff ) {
                                         continue;
                                 }
                                 if ( !PacketChecksums() ) {
                                         continue;
                                 }

                                 // this seems to be good, so we will be 
synced now
                                 isSynced = 1;
                         }

                         // we have a packet
                         lastPacketDataTail = dataTail;

                         xbow.updateNumber++;
                         xbow.updateTime = currentTime;

                         // byte swap
                         for ( i = 0 ; i < 8 ; i++ ) {
                                 ((char *)xbow.rate)[i*2+0] = data[ ( 
dataTail - 17 + i * 2 + 1 ) & DATA_MASK ];
                                 ((char *)xbow.rate)[i*2+1] = data[ ( 
dataTail - 17 + i * 2 + 0 ) & DATA_MASK ];
                         }

                         // scale to engineering units
                         #define RAW_TO_RATE ((260*1.5)/32768)
                         #define RAW_TO_ACCEL ((10*1.5)/32768)

                         xbow.scaledRate[0] = -xbow.rate[2] * RAW_TO_RATE;
                         xbow.scaledRate[1] = xbow.rate[0] * RAW_TO_RATE;
                         xbow.scaledRate[2] = -xbow.rate[1] * RAW_TO_RATE;

                         xbow.scaledAccel[0] = -xbow.accel[2] * RAW_TO_ACCEL;
                         xbow.scaledAccel[1] = xbow.accel[0] * RAW_TO_ACCEL;
                         xbow.scaledAccel[2] = -xbow.accel[1] * RAW_TO_ACCEL;

                         return 1;
                 }

                 // try to read more data from the serial port
                 ioCount = read( crossbowHandle, &readData, sizeof(readData) );

                 // if we can't read anything, return with no update
                 if ( ioCount == 0 ) {
                         return 0;
                 }

                 // copy the data into the circular buffer
                 for ( i = 0 ; i < ioCount ; i++ ) {
                         dataHead++;
                         data[dataHead & DATA_MASK] = readData[i];
                 }

                 // see if we have a valid packet now
         }


         return 0;
}

/*
==============
PrintCrossbow
==============
*/
void PrintCrossbow( void ) {
         printf( "%i\t:\t%i\t%i\t%i\t%i\t%i\t%i\t%i\t%i\n",
                 xbow.updateNumber,
                 xbow.rate[0], xbow.rate[1], xbow.rate[2],
                 xbow.accel[0], xbow.accel[1], xbow.accel[2],
                 xbow.temp, xbow.time );
}

/*
==============
TestCrossbow

==============
*/
void    TestCrossbow( int portNumber ) {
         OpenCrossbow( portNumber );

         // read the port until aborted
         printf( "reading data, press a key to abort\n" );

         while( 1 ) {
                 CheckAbort();
                 if ( !UpdateCrossbow() ) {
                         continue;
                 }
                 PrintCrossbow();
         }
}
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.