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
