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();
        }
}


_______________________________________________ ERPS-list mailing list [EMAIL PROTECTED] http://lists.erps.org/mailman/listinfo/erps-list

Reply via email to