Capstone project for Bachelor's in Mechanical Engineering 2011
Dependencies: FatFileSystem MAX3100 MODGPS MODSERIAL SDFileSystem mbed
main.cpp
- Committer:
- lhiggs
- Date:
- 2013-05-29
- Revision:
- 0:0529d2d7762f
File content as of revision 0:0529d2d7762f:
#include "mbed.h" // MBED LIBRARY #include "SerialRPCInterface.h" // MBED RPC LIBRARY (FOR LABVIEW CONTROL OF PROGRAM FUNCTIONS AND VARIABLES) #include "GPS.h" // MBED GPS LIBRARY #include "MODSERIAL.h" // MBED BUFFERED SERIAL #include "SDFileSystem.h" // MBED SD LIBRARY #include "UM6_usart.h" // UM6 USART HEADER #include "UM6_config.h" // UM6 CONFIG HEADER #include "MAX3100.h" // MAX3100 SPI to UART CHIP DRIVER LIBRARY #include "math.h" ///////////////////////////////////////////////////////////////////////////////////////////// // Program Name: main.cpp // Description: This is the main program for an autonomous parafoil undergraduate capstone // project in Mechanical Engineering at the California Maritime Academy, Vallejo // CA, Spring 2011. As of yet there is no autonomous functionality. However, all // hardware has proven functional. The hardware that this program was written for // consists of an mbed LPC1768 microcontroller, cool components mbed breakout board // with 1GB microSD card, GM862-GPS combined cellular and gps module, DNT900P // 900Mhz 1Watt RF modem utilized as a transparent serial link to the application, // Hitec HS-785 Winch Servos, Firgelli PQ12 linear actuator with limit switches, // and last but by no means least a CH Robotics UM6 IMU/AHRS. // Author: Logan Higgs, (portions of UM6 interface adapted from open source UM6 code by CH // robotics} // Date: 04/2011 // Special Thanks to Andy Kirkham from mbed who wrote most of the mbed libraries that this // program utilizes, and more importantly even edited his MODGPS library to support VTG GPS // data specifically from my request. ///////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////// // THIS IS FOR RECIEVED DATA COUNTING AND BOOLING GOT NEW DATA FLAGS ///////////////////////////////////////////////////////////////////////////////////////////// static uint8_t got_data_counter = 0; volatile bool got_data = false; volatile bool GOT_UM6 = false; ///////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////// // THIS IS FOR ATTEMPT TO MAKE UM6 DATA ARRAYS FOR LETTING microSD CARD // DATA WRITING ONLY ONCE A SECOND, INSTEAD OF EVERY TIME A UM6 DATA // SET IS RECIEVED ///////////////////////////////////////////////////////////////////////////////////////////// int UM6_data_counter = 0; // Counter for SD data logging int16_t MY_DATA_GYRO_PROC_X; int16_t MY_DATA_GYRO_PROC_Y; int16_t MY_DATA_GYRO_PROC_Z; int16_t MY_DATA_ACCEL_PROC_X; int16_t MY_DATA_ACCEL_PROC_Y; int16_t MY_DATA_ACCEL_PROC_Z; int16_t MY_DATA_MAG_PROC_X; int16_t MY_DATA_MAG_PROC_Y; int16_t MY_DATA_MAG_PROC_Z; int16_t MY_DATA_EULER_PHI; int16_t MY_DATA_EULER_THETA; int16_t MY_DATA_EULER_PSI; ///////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////// // SETUP (ASSIGN) SERIAL COMMUNICATION PINS ON MBED ///////////////////////////////////////////////////////////////////////////////////////////// //MODSERIAL pc(USBTX, USBRX); // PC SERIAL OVER USB PORT ON MBED //Create the interface on the USB Serial Port //SerialRPCInterface SerialInterface(USBTX, USBRX); SerialRPCInterface SerialInterface(p28, p27); MODSERIAL uart(p26, p25); // UM6 SERIAL OVER UART PINS 28 & 27 // SETUP DNT900P RF MODEM SERIAL //MODSERIAL DNT900P(p28, p27); // SETUP GM862-GPS MODEM SERIAL PORT THRU MAX3100 SPI to UART IC MAX3100 max(p11, p12, p13, p14,p15); // SETUP GM862-GPS GPS SERIAL PORT // Serial gps_uart(p9, p10); // Create an instance of the GPS object for MODGPS library GPS gps(NC, p10); //////////////////////////////////////////////////////////////////////////////////////////////// // SETUP (ASSIGN) SPI COMMUNICATION PINS ON MBED FOR SD CARD ON COOLCOMPONENTS WORKSHOP BOARD //////////////////////////////////////////////////////////////////////////////////////////////// SDFileSystem sd(p5, p6, p7, p8, "sd"); // the pinout on the mbed Cool Components workshop board //////////////////////////////////////////////////////////////////////////////////////////////// // SETUP (ASSIGN) WINCH SERVO#1 (STBD) & WINCH SERVO#2 (PORT) //////////////////////////////////////////////////////////////////////////////////////////////// PwmOut servo1(p23); PwmOut servo2(p24); //////////////////////////////////////////////////////////////////////////////////////////////// // SETUP (ASSIGN) DIGITAL OUTPUTS FOR H-BRIDGE ACTUATOR DRIVER FOR PARAFOIL DEPLOYMENT //////////////////////////////////////////////////////////////////////////////////////////////// DigitalOut red(p16); DigitalOut EN(p17); DigitalOut blue(p18); //////////////////////////////////////////////////////////////////////////////////////////////// // SETUP (ASSIGN) MBED LED (1 thru 3) FOR VISUAL DEBUGGING ON MBED //////////////////////////////////////////////////////////////////////////////////////////////// DigitalOut pc_activity(LED1); // LED1 = PC SERIAL DigitalOut uart_activity(LED2); // LED2 = UM6 SERIAL DigitalOut sd_activity(LED3); // LED3 = SD CARD // CREATE FLOAT VARIABLES FOR LABVIEW REMOTE CONTROL OF PROGRAM float servo1_pw = 0.0015; float servo2_pw = 0.0015; float Actuator_CMD = 1; float Latitude = 0; float Longitude = 0; float Altitude = 0; float Roll = 0; float Pitch = 0; float Yaw = 0; float Control_Mode = 0; float CMD_Latitude = 0; float CMD_Longitude = 0; float CALC_Heading = 0; float CMD_Heading = 0; // FROM UM6 FIRMWARE SOURCE // Flag for storing the current USART state uint8_t gUSART_State = USART_STATE_WAIT; /******************************************************************************* * Function Name : ComputeChecksum * Input : USARTPacket* new_packet * Output : None * Return : uint16_t * Description : Returns the two byte sum of all the individual bytes in the given packet. *******************************************************************************/ uint16_t ComputeChecksum( USARTPacket* new_packet ) { int32_t index; uint16_t checksum = 0x73 + 0x6E + 0x70 + new_packet->PT + new_packet->address; for ( index = 0; index < new_packet->data_length; index++ ) { checksum += new_packet->packet_data[index]; } return checksum; } ////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////// // MODSERIAL INTERUPT FUNCTION AND MODSERIAL OVERFLOW INTERUPT FUNCTION FOR DEBUGGING ///////////////////////////////////////////////////////////////////////////////////////////// // MBED MODSERIAL INTERUPT FUNCTION // This function is called when a character goes into the RX buffer. //void rxCallback(void) { // if (uart.rxBufferGetCount() > MAX_PACKET_DATA & got_data == false) { // got_data = true; // uart_activity = !uart_activity; // Lights LED when uart RxBuff has > 40 bytes // } //} void rxOvflow(void) { error("Ouch, overflowed"); } //SDFileSystem *sd; /////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////// int main() { /////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////// //Make these variables accessible over RPC by attaching them to an RPCVariable RPCVariable<float> RPCservo1_pw(&servo1_pw, "servo1_pw"); RPCVariable<float> RPCservo2_pw(&servo2_pw, "servo2_pw"); RPCVariable<float> RPCActuator_CMD(&Actuator_CMD, "Actuator_CMD"); RPCVariable<float> RPCLatitude(&Latitude, "Latitude"); RPCVariable<float> RPCLongitude(&Longitude, "Longitude"); RPCVariable<float> RPCAltitude(&Altitude, "Altitude"); RPCVariable<float> RPCRoll(&Roll, "Roll"); RPCVariable<float> RPCPitch(&Pitch, "Pitch"); RPCVariable<float> RPCYaw(&Yaw, "Yaw"); RPCVariable<float> RPCControl_Mode(&Control_Mode, "Control_Mode"); RPCVariable<float> RPCCMD_Latitude(&CMD_Latitude, "CMD_Latitude"); RPCVariable<float> RPCCMD_Longitude(&CMD_Longitude, "CMD_Lognitude"); RPCVariable<float> RPCCALC_Heading(&CALC_Heading, "CALC_Heading"); RPCVariable<float> RPCCMD_Heading(&CMD_Heading, "CMD_Heading"); /////////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////// GPS_Time q1; GPS_VTG v1; ////////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////// // WINCH SERVO INITIALIZATION ////////////////////////////////////////////////////////////////////////////////////////////////////// servo1.period(0.020); // servos requires a 20ms period servo2.period(0.020); // initialize servo to center (neutral position) servo1.pulsewidth(0.0015); servo2.pulsewidth(0.0015); //servo_neutral_activity = !servo_neutral_activity; /////////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////// // THIS MAKES A DIRECTORY ON THE microSD CARD FOR DATA LOGGING ////////////////////////////////////////////////////////////////////////////////////////////////////// // SD DATA LOGGING // mkdir("/sd/", 0777); // sd_activity = !sd_activity; ////////////////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////////////// // SET SERIAL UART BAUD RATES ///////////////////////////////////////////////////////////////////////////////////////////////////// // set UM6 serial uart baud 115200 uart.baud(9600); // pc bauds for usb virtual serial port on mbed for ground use only. // pc.baud(9600); // pc baud for GM862-GPS modem to pc interface // pc.baud(9600); // pc baud for UM6 to pc interface // set DNT900P baud 9600 // DNT900P.baud(9600); // set gps baud 4800 gps.baud(4800); gps.format(8, GPS::None, 1); // enable max3100 interupts for GM862-GPS modem uart thru spi to uart ic max.enableRxIrq(); max.enableTxIrq(); ////////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////// // THIS WAS FOR DEBUGGING MODSERIAL AND SD CARD, STILL USEFUL FOR CHECKING FOR OVERFLOW OF MODSERIAL // CIRCULAR BUFFER ///////////////////////////////////////////////////////////////////////////////////////////////////// // In main after setting the uart baud rate and before attaching your rxCallback function add:- uart.attach(&rxOvflow, MODSERIAL::RxOvIrq); // Setup the uart serial port, then... // sd = new SDFileSystem(p5, p6, p7, p8, "sd"); // attach interupt function to uart // uart.attach(&rxCallback, MODSERIAL::RxIrq); ////////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////// while (1) { ///////////////////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////////////////// // GPS AUTOMATIC DATA PARSING WITH MODGPS LIBRARY // Demonstrate how to find out the GPS location co-ords. // pc.printf("Lat = %.4f ", gps.latitude()); // pc.printf("Lon = %.4f ", gps.longitude()); // pc.printf("Alt = %.4f ", gps.altitude()); // Gran a snapshot of the current time. gps.timeNow(&q1); // pc.printf("%02d:%02d:%02d %02d/%02d/%04d\r\n", // q1.hour, q1.minute, q1.second, q1.day, q1.month, q1.year); gps.vtg(&v1); // pc.printf("Method 1. Vector data, Speed (knots):%lf, Speed(kph):%lf, Track(true):%lf, Track(mag)%lf\r\n", // v1.velocity_knots(), v1.velocity_kph(), v1.track_true(), v1.track_mag()); // ////////////////////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////////////////// // THIS IS A SERIAL PASS THRU BETWEEN THE GM862-GPS MODEM SERIAL PORT AND THE PC USB VIRTUAL SERIAL PORT. // IT ISN'T INTENDED TO BE USED DURING FLIGHT, BUT RATHER FOR CONFIGURATION OF THE GM862-GPS WHILE ON // THE GROUND. ///////////////////////////////////////////////////////////////////////////////////////////////////////// // if (pc.readable()) { // int c = pc.getc(); // max.putc(c); // } // if (max.readable()) { // pc.putc( max.getc() ); // } ///////////////////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////////////////// // THIS IS A SERIAL PASS THRU FOR THE UM6 AHRS/IMU TO THE PC FOR USING THE CH ROBOTICS SERIAL INTERFACE // PC SOFTWARE FOR CALIBRATING AND VIEWING DATA FROM THE UM6. DEFAULT PC BAUD 115200 // if (pc.readable()) { // int c = pc.getc(); // uart.putc(c); // } // if (uart.readable()) { // pc.putc( uart.getc() ); // } ///////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////// // THIS IS FOR THE UM6 IMU/AHRS SERIAL COMMUNICATIONS, IT REALLY SHOULD BE PUT INTO AT LEAST ITS OWN // FUNCTIONS, OR EVEN A UM6 CLASS AND LIBRARY. /////////////////////////////////////////////////////////////////////////////////////////////////////// if (uart.rxBufferGetCount() > MAX_PACKET_DATA) { uart_activity = !uart_activity; // Lights LED when uart RxBuff has > 40 bytes // UM6 Firmware Source Function ProcessNextCharacter() //void ProcessNextCharacter( ) { static uint8_t data_counter = 0; static USARTPacket new_packet; // The next action should depend on the USART state. switch ( gUSART_State ) { // USART in the WAIT state. In this state, the USART is waiting to see the sequence of bytes // that signals a new incoming packet. case USART_STATE_WAIT: if ( data_counter == 0 ) { // Waiting on 's' character if ( uart.getc() == 's' ) { data_counter++; } else { data_counter = 0; } } else if ( data_counter == 1 ) { // Waiting on 'n' character if ( uart.getc() == 'n' ) { data_counter++; } else { data_counter = 0; } } else if ( data_counter == 2 ) { // Waiting on 'p' character if ( uart.getc() == 'p' ) { // The full 'snp' sequence was received. Reset data_counter (it will be used again // later) and transition to the next state. data_counter = 0; gUSART_State = USART_STATE_TYPE; } else { data_counter = 0; } } break; // USART in the TYPE state. In this state, the USART has just received the sequence of bytes that // indicates a new packet is about to arrive. Now, the USART expects to see the packet type. case USART_STATE_TYPE: new_packet.PT = uart.getc(); gUSART_State = USART_STATE_ADDRESS; break; // USART in the ADDRESS state. In this state, the USART expects to receive a single byte indicating // the address that the packet applies to case USART_STATE_ADDRESS: new_packet.address = uart.getc(); // pc.putc(new_packet.address); // For convenience, identify the type of packet this is and copy to the packet structure // (this will be used by the packet handler later) if ( (new_packet.address >= CONFIG_REG_START_ADDRESS) && (new_packet.address < DATA_REG_START_ADDRESS) ) { new_packet.address_type = ADDRESS_TYPE_CONFIG; } else if ( (new_packet.address >= DATA_REG_START_ADDRESS) && (new_packet.address < COMMAND_START_ADDRESS) ) { new_packet.address_type = ADDRESS_TYPE_DATA; } else { new_packet.address_type = ADDRESS_TYPE_COMMAND; } // Identify the type of communication this is (whether reading or writing to a data or configuration register, or sending a command) // If this is a read operation, jump directly to the USART_STATE_CHECKSUM state - there is no more data in the packet if ( (new_packet.PT & PACKET_HAS_DATA) == 0 ) { gUSART_State = USART_STATE_CHECKSUM; } // If this is a write operation, go to the USART_STATE_DATA state to read in the relevant data else { gUSART_State = USART_STATE_DATA; // Determine the expected number of bytes in this data packet based on the packet type. A write operation // consists of 4 bytes unless it is a batch operation, in which case the number of bytes equals 4*batch_size, // where the batch size is also given in the packet type byte. if ( new_packet.PT & PACKET_IS_BATCH ) { new_packet.data_length = 4*((new_packet.PT >> 2) & PACKET_BATCH_LENGTH_MASK); } else { new_packet.data_length = 4; } } break; // USART in the DATA state. In this state, the USART expects to receive new_packet.length bytes of // data. case USART_STATE_DATA: new_packet.packet_data[data_counter] = uart.getc(); data_counter++; // If the expected number of bytes has been received, transition to the CHECKSUM state. if ( data_counter == new_packet.data_length ) { // Reset data_counter, since it will be used in the CHECKSUM state. data_counter = 0; gUSART_State = USART_STATE_CHECKSUM; } break; // USART in CHECKSUM state. In this state, the entire packet has been received, with the exception // of the 16-bit checksum. case USART_STATE_CHECKSUM: // Get the highest-order byte if ( data_counter == 0 ) { // uint8_t Temp_Packet = uart.getc(); new_packet.checksum = ((uint16_t)uart.getc() << 8); data_counter++; } else { // ( data_counter == 1 ) // Get lower-order byte new_packet.checksum = new_packet.checksum | ((uint16_t)uart.getc() & 0x0FF); // Both checksum bytes have been received. Make sure that the checksum is valid. uint16_t checksum = ComputeChecksum( &new_packet ); // If checksum does not match, send a BAD_CHECKSUM packet if ( checksum != new_packet.checksum ) { got_data = false; } else { // Packet was received correctly. //----------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------- // // ADDED: CHECKSUM WAS GOOD SO GET ARE DATA!!!!!!!!!!!! // IF DATA ADDRESS if (new_packet.address_type == ADDRESS_TYPE_DATA) { //------------------------------------------------------------ // UM6_GYRO_PROC_XY (0x5C) // To convert the register data from 16-bit 2's complement integers to actual angular rates in degrees // per second, the data should be multiplied by the scale factor 0.0610352 as shown below // angular_rate = register_data*0.0610352 if (new_packet.address == UM6_GYRO_PROC_XY) { // GYRO_PROC_X MY_DATA_GYRO_PROC_X = (int16_t)new_packet.packet_data[0]<<8; //bitshift it MY_DATA_GYRO_PROC_X |= new_packet.packet_data[1]; // pc.printf( "GPx %f deg/s\n",MY_DATA_GYRO_PROC_X*0.0610352); MY_DATA_GYRO_PROC_Y = (int16_t)new_packet.packet_data[2]<<8; //bitshift it MY_DATA_GYRO_PROC_Y |= new_packet.packet_data[3]; // pc.printf( "GPy %f d/s\n",MY_DATA_GYRO_PROC_Y*0.0610352); //------------------------------------------------------------ //------------------------------------------------------------ // UM6_GYRO_PROC_Z (0x5D) // To convert the register data from a 16-bit 2's complement integer to the actual angular rate in // degrees per second, the data should be multiplied by the scale factor 0.0610352 as shown below. // GYRO_PROC_Z MY_DATA_GYRO_PROC_Z = (int16_t)new_packet.packet_data[4]<<8; //bitshift it MY_DATA_GYRO_PROC_Z |= new_packet.packet_data[5]; //pc.printf( "GPz %f deg/s\n",MY_DATA_GYRO_PROC_Z*0.0610352); } //------------------------------------------------------------ //------------------------------------------------------------ // UM6_ACCEL_PROC_XY (0x5E) // To convert the register data from 16-bit 2's complement integers to actual acceleration in gravities, // the data should be multiplied by the scale factor 0.000183105 as shown below. // acceleration = register_data* 0.000183105 if (new_packet.address == UM6_ACCEL_PROC_XY) { // ACCEL_PROC_X MY_DATA_ACCEL_PROC_X = (int16_t)new_packet.packet_data[0]<<8; //bitshift it MY_DATA_ACCEL_PROC_X |= new_packet.packet_data[1]; // pc.printf( "Apx %f g \n",MY_DATA_ACCEL_PROC_X*0.000183105); // ACCEL_PROC_Y MY_DATA_ACCEL_PROC_Y = (int16_t)new_packet.packet_data[2]<<8; //bitshift it MY_DATA_ACCEL_PROC_Y |= new_packet.packet_data[3]; // pc.printf( "Apy %f g \n",MY_DATA_ACCEL_PROC_Y*0.000183105); //------------------------------------------------------------ //------------------------------------------------------------ // UM6_ACCEL_PROC_Z (0x5F) // To convert the register data from a 16-bit 2's complement integer to the actual acceleration in // gravities, the data should be multiplied by the scale factor 0.000183105 as shown below. // ACCEL_PROC_Z MY_DATA_ACCEL_PROC_Z = (int16_t)new_packet.packet_data[4]<<8; //bitshift it MY_DATA_ACCEL_PROC_Z |= new_packet.packet_data[5]; // pc.printf( "Apz %f g \n",MY_DATA_ACCEL_PROC_Z*0.000183105); } //------------------------------------------------------------ //------------------------------------------------------------ // UM6_MAG_PROC_XY (0x60) // To convert the register data from 16-bit 2's complement integers to a unit-norm (assuming proper // calibration) magnetic-field vector, the data should be multiplied by the scale factor 0.000305176 as // shown below. // magnetic field = register_data* 0.000305176 if (new_packet.address == UM6_MAG_PROC_XY) { // MAG_PROC_X MY_DATA_MAG_PROC_X = (int16_t)new_packet.packet_data[0]<<8; //bitshift it MY_DATA_MAG_PROC_X |= new_packet.packet_data[1]; // pc.printf( "Mpx %f \n",MY_DATA_MAG_PROC_X*0.000305176); // MAG_PROC_Y MY_DATA_MAG_PROC_Y = (int16_t)new_packet.packet_data[2]<<8; //bitshift it MY_DATA_MAG_PROC_Y |= new_packet.packet_data[3]; // pc.printf( "Mpy %f \n",MY_DATA_MAG_PROC_Y*0.000305176); //------------------------------------------------------------ //------------------------------------------------------------ // UM6_MAG_PROC_Z (0x61) // To convert the register data from 16-bit 2's complement integers to a unit-norm (assuming proper // calibration) magnetic-field vector, the data should be multiplied by the scale factor 0.000305176 as // shown below. // magnetic field = register_data*0.000305176 // MAG_PROC_Z MY_DATA_MAG_PROC_Z = (int16_t)new_packet.packet_data[4]<<8; //bitshift it MY_DATA_MAG_PROC_Z |= new_packet.packet_data[5]; // pc.printf( "Mpz %f \n",MY_DATA_MAG_PROC_Z*0.000305176); } //------------------------------------------------------------ //------------------------------------------------------------ // UM6_EULER_PHI_THETA (0x62) // Stores the most recently computed roll (phi) and pitch (theta) angle estimates. The angle // estimates are stored as 16-bit 2's complement integers. To obtain the actual angle estimate in // degrees, the register data should be multiplied by the scale factor 0.0109863 as shown below // angle estimate = register_data* 0.0109863 if (new_packet.address == UM6_EULER_PHI_THETA) { // EULER_PHI (ROLL) MY_DATA_EULER_PHI = (int16_t)new_packet.packet_data[0]<<8; //bitshift it MY_DATA_EULER_PHI |= new_packet.packet_data[1]; // pc.printf( "PHI %f deg , ",MY_DATA_EULER_PHI*0.0109863); // EULER_THETA (PITCH) MY_DATA_EULER_THETA = (int16_t)new_packet.packet_data[2]<<8; //bitshift it MY_DATA_EULER_THETA |= new_packet.packet_data[3]; // printf( "THETA %f deg , ",MY_DATA_EULER_THETA*0.0109863); //------------------------------------------------------------ //------------------------------------------------------------ // UM6_EULER_PSI (0x63) (YAW) // Stores the most recently computed yaw (psi) angle estimate. The angle estimate is stored as a 16- // bit 2's complement integer. To obtain the actual angle estimate in degrees, the register data // should be multiplied by the scale factor 0.0109863 as shown below MY_DATA_EULER_PSI = (int16_t)new_packet.packet_data[4]<<8; //bitshift it MY_DATA_EULER_PSI |= new_packet.packet_data[5]; // pc.printf( "PSI %f deg \r\n",MY_DATA_EULER_PSI*0.0109863); GOT_UM6 = true; UM6_data_counter++; } //------------------------------------------------------------ } // A full packet has been received. // Put the USART back into the WAIT state and reset // the data_counter variable so that it can be used to receive the next packet. data_counter = 0; gUSART_State = USART_STATE_WAIT; // ADDED: This is a counter for the SD data logging got_data_counter ++; got_data = false; } } break; } } ///////////////////////////////////////////////////////////////////////////////////////////////////////// // LABVIEW REMOTE CONTROL ENABLE if (Control_Mode >= 0.5) { ///////////////////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////////////////// // LABVIEW REMOTE CONTROL OF SERVOS AND ACTUATOR servo1.pulsewidth(servo1_pw); // Turn STBD servo2.pulsewidth(servo2_pw); // ACTUATOR RETRACT if (Actuator_CMD < 0.5) { red = 1; EN = 1; blue = 0; } // ACTUATOR EXTEND if (Actuator_CMD >= 0.5) { red = 0; EN = 1; blue = 1; } } ////////////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////////// // THIS IS A SIMPLE TEST FOR CONTROLLING THE WINCH SERVOS FROM THE FLIGHT YAW ANGLE ESTIMATED FROM THE // ONBOARD UM6 IMU/AHRS. ////////////////////////////////////////////////////////////////////////////////////////////////////////// if (GOT_UM6 == true) { // if (MY_DATA_EULER_PSI*0.0109863 < 5 && MY_DATA_EULER_PSI*0.0109863 > -5) { if (MY_DATA_EULER_PSI*0.0109863 < CALC_Heading+5 && MY_DATA_EULER_PSI*0.0109863 > CALC_Heading-5) { servo1.pulsewidth(0.0015); // NEUTRAL STBD servo2.pulsewidth(0.0015); // NEUTRAL PORT } if (MY_DATA_EULER_PSI*0.0109863 <= CALC_Heading-5 && MY_DATA_EULER_PSI*0.0109863 >= -135) { servo1.pulsewidth(0.0015 + 0.0002); // Turn STBD servo2.pulsewidth(0.0015); // servo1.pulsewidth(0.0011); // servo2.pulsewidth(0.0015 + 0.0002); //servo_cw_activity = !servo_cw_activity; } if (MY_DATA_EULER_PSI*0.0109863 >= CALC_Heading+5 && MY_DATA_EULER_PSI*0.0109863 <= 135) { servo1.pulsewidth(0.0015); servo2.pulsewidth(0.0015 - 0.0002); // Turn PORT //servo_ccw_activity = !servo_ccw_activity; } ////////////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////////// // DEPLOY PARAFOIL (RETRACT ACTUATOR FOR DEMONSTRATION PURPOSES ONLY WHEN PITCH ABOVE 85 AND BELOW 95 DEG. if (MY_DATA_EULER_THETA*0.0109863 > 75 ) { red = 1; // RETRACTS DEPLOYMENT ACTUATOR EN = 1; blue = 0; } if (MY_DATA_EULER_THETA*0.0109863 <= -75) { red = 0; // RETRACTS DEPLOYMENT ACTUATOR EN = 1; blue = 1; } //////////////////////////////////////////////////////////////////////////////////////////////////////////// GOT_UM6 = false; } // end if for GOT_EULER == true ///////////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////////// // THIS IS A SIMPLE DATA OUTPUT USED TO TEST BASIC FUNCTIONALITY OF RF MODEM ///////////////////////////////////////////////////////////////////////////////////////////////// if (UM6_data_counter >= 20) { UM6_data_counter = 0; Roll = MY_DATA_EULER_PHI*0.0109863; Pitch = MY_DATA_EULER_THETA*0.0109863; Yaw = MY_DATA_EULER_PSI*0.0109863; Latitude = gps.latitude(); Longitude = gps.longitude(); Altitude = gps.altitude(); CALC_Heading = atan2 (cos(Latitude)*sin(CMD_Latitude)-sin(Latitude)*cos(CMD_Latitude)*cos(CMD_Longitude-CMD_Longitude),sin(CMD_Longitude-Longitude)*cos(CMD_Latitude)) * 180 / 3.14159265; ////////////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////////// // THIS IS FOR microSD CARD FLIGHT DATA LOGGING, NEEDS TO BE OPTIMIZED AND EXPANDED TO LOG ALL DATA AND // RECIEVED FLIGHT COMMANDS. ////////////////////////////////////////////////////////////////////////////////////////////////////////// // FILE *fp = fopen("/sd/UM6_DATA_GROUND.txt", "a"); // if (fp == NULL) { // error("Could not open file for write\n"); // } // fprintf(fp,"%02d:%02d:%02d %02d/%02d/%04d,%f,%f,%f,%f,%f,%f,%f,%f,%f,%f,%f,%f,%f,%f,%f,%f,%f \n", // q1.hour, q1.minute,q1.second,q1.month,q1.day,q1.year, // gps.latitude(),gps.longitude(),gps.altitude(), // v1.velocity_knots(),v1.track_true(), // MY_DATA_GYRO_PROC_X*0.0610352,MY_DATA_GYRO_PROC_Y*0.0610352,MY_DATA_GYRO_PROC_Z*0.0610352, // MY_DATA_ACCEL_PROC_X*0.000183105,MY_DATA_ACCEL_PROC_Y*0.000183105,MY_DATA_ACCEL_PROC_Z*0.000183105, // MY_DATA_MAG_PROC_X*0.000305176,MY_DATA_MAG_PROC_Y*0.000305176,MY_DATA_MAG_PROC_Z*0.000305176, // MY_DATA_EULER_PHI*0.0109863,MY_DATA_EULER_THETA*0.0109863,MY_DATA_EULER_PSI*0.0109863); // fclose(fp); sd_activity = !sd_activity; /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // This sends the GPS:lat,long,alt telemetery to the ground base station // with the DNT900 900Mhz 1Watt RF modem. // DNT900P.printf("%02d:%02d:%02d %02d/%02d/%04d,\r\nLat %f,Long %f,Alt %f,Roll %f,Pitch %f,Yaw %f \n\r", // q1.hour, q1.minute,q1.second,q1.month,q1.day,q1.year, // gps.latitude(),gps.longitude(),gps.altitude(), // MY_DATA_EULER_PHI*0.0109863,MY_DATA_EULER_THETA*0.0109863,MY_DATA_EULER_PSI*0.0109863); // DNT900P.printf("%02d:%02d:%02d %02d/%02d/%04d,%f,%f,%f,%f,%f,%f,%f,%f,%f,%f,%f,%f,%f,%f,%f,%f,%f \n", // q1.hour, q1.minute,q1.second,q1.month,q1.day,q1.year, // gps.latitude(),gps.longitude(),gps.altitude(), // v1.velocity_knots(),v1.track_true(), // MY_DATA_GYRO_PROC_X*0.0610352,MY_DATA_GYRO_PROC_Y*0.0610352,MY_DATA_GYRO_PROC_Z*0.0610352, // MY_DATA_ACCEL_PROC_X*0.000183105,MY_DATA_ACCEL_PROC_Y*0.000183105,MY_DATA_ACCEL_PROC_Z*0.000183105, // MY_DATA_MAG_PROC_X*0.000305176,MY_DATA_MAG_PROC_Y*0.000305176,MY_DATA_MAG_PROC_Z*0.000305176, // MY_DATA_EULER_PHI*0.0109863,MY_DATA_EULER_THETA*0.0109863,MY_DATA_EULER_PSI*0.0109863); } // end UM6_data_counter >= 20 if statement ///////////////////////////////////////////////////////////////////////////////////////////////// } // end while(1) loop } // end main()