User Tools

Site Tools


Writing /public/societies/cuspaceflight/public_html/www/wiki/data/cache/a/a51f4a8fa1b70f8e49452db2d467d685.metadata failed
weasel_code
Writing /public/societies/cuspaceflight/public_html/www/wiki/data/cache/c/c28b6fe9b6d2155086f8a512615185c8.xhtml failed

**This is an old revision of the document!** ----

A PCRE internal error occured. This might be caused by a faulty plugin

====== Introduction ====== This page contains the code archive for the Weasel Project. Only the revision of the code will remain on the [[arduino_tracker|Weasel]] Page. ===== Latest BETA Arduino Code ===== This is the latest code. It uses struct for gps, so gps data can be easily accessed for use in functions. - The GPS nav mode check bug has been attempted to be fixed by re-ordering statements. - The zeros after the decimal place bug has also been fixed, by converting the gps strings into char arrays in the GPS_Coord function. As much as possible all bugs have been eliminated, but this code has not been tested on an Arduino with a fully functioning GPS. However it has been beta tested using test strings on a static arduino uno. Using this code is at your own risk, and I recommend some ground testing first. <code cpp> // This code sets a FSA03 GPS module to give gps data to a radio module to downlink to earth. //Code written by Chris Murkin, Leo, Hannah, and CU Spaceflight with FSA03 set up code from the UKHAS website //This code is written for the Cambridge University Space Flight project. //It was used for the Weasel tracker an introductory proect //The check sum code was borrowed from CUSF Ferret Tracker, written by Jon Sowman avalible from Git hub. //This should work in all parts of the world, but be careful as gps.lat_int, and gps.lon_int are always positive #include <NewSoftSerial.h> #include <stdio.h> #include <string.h> #include <util/crc16.h> //Set New soft serial to GPS NewSoftSerial nss(3, 2); //Declare Varibles ====================== char clock[8]; //The time char lat[11], lon[11]; //Lat and Long, in separated parts char no_sat[3], alt[8], a; //Various other readings int alt_count= 0; int gcount=0, comma_count=0, dot_count=0, array_count=0; //gcount is the number of chars from GPS per read int ticks; char buffer[200]; char str_out[200]; char callsign[7] = "WEASEL"; struct program_data { long clock_int; //This is the clock as an interger long hour; //Shouldn't need to be a long, but is multiplied a lot when used, so programs fails if this is an int. long minute; long second; int sat; long alt; long lat_int; //This is the latitude as an interger, in DD.MMMMMM before GPS_Coord, and DD.DDDDD after GPS_Coord NOTE always positive. long lon_int; //Longitude equvialant. char ew; //This is either E or W depending on hemisphere char ns; //This is N or S depending on hemisphere char blanks[8]; //This is used to put in the blanks for output string, do not use for any data char lat[11]; //This will be a string, with the form of a signed float so should have -52.00123 for example after GPS_Coord is called char lon[11]; } gps; //gps is the name of the varible with a structure of program_data. Refer to contents by gps.sat, gps.lat[5] etc... void setup() {//Startup loop ==================================================== // Start up serial ports nss.begin(38400); Serial.begin(115200); // used for debug ouput delay(2000); // Give the GPS time to come boot // Lower the baud rate to 9600 from 38.4k Serial.print("Setting uBlox port mode: "); uint8_t setPort[] = { 0xB5, 0x62, 0x06, 0x00, 0x14, 0x00, 0x01, 0x00, 0x00, 0x00, 0xD0, 0x08, 0x00, 0x00, 0x80, 0x25, 0x00, 0x00, 0x03, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9E, 0x95 }; sendUBX(setPort, sizeof(setPort)/sizeof(uint8_t)); // Switch baud rates on the software serial Serial.println("Switching to 9600b GPS serial"); nss.begin(9600); delay(1000); set_GPS(); ticks = 1; } //END OF SET UP LOOP void loop()//=================================================================== { //READ THE GPS AND EXTRACT THE USEFUL DATA while (a != '*' && gcount <120 && nss.available()){ a = nss.read(); //Reads the gps Serial.print(a); //Displays GPGGA (gps output string) on the USB debug if (a == ',') { //comma responce comma_count++; array_count=0; } if (a == '.') dot_count++; //dot count switch (comma_count) { //Switch command case 1: //This is the time //Serial.print(" Time "); if (dot_count ==0){ //Only work before the dot! clock[array_count]=a; if (a!= ',') array_count++; } break; case 2: // This is latitude if (a != '.'& a != ',') { lat[array_count] = a; array_count++; } break; case 3: //N/S if (a !=',') gps.ns=a; break; case 4: // This is latitude if (a != '.'& a != ',') { lon[array_count] = a; array_count++; } break; case 5: //E/W if (a !=',') gps.ew=a; break; case 7: //Stats if (a != '.'& a != ',') { no_sat[array_count] = a; array_count++; } break; case 9: //Alt if (a != '.'& a != ',') { alt[array_count] = a; array_count++; alt_count++; } break; } gcount++; } //This is the end of the loop that runs until a * is reached. //Insert stop bits on the string. clock[6]='\0'; lat[10]='\0'; lon[10]='\0'; no_sat[2]='\0'; alt[alt_count]='\0'; //INT CONVERSION gps.lon_int = atol(lon); gps.lat_int = atol(lat); gps.alt = atol(alt)/10; gps.clock_int = atol(clock); gps.sat = atoi(no_sat); //TEST CODE = MAKESURE OFF FOR LAUNCH //gps.ew='W'; //This will simulate crossing the prime meridian //gps.ns='S'; //This will simulate crossing the equator. GPS_coord(); //Convert GPS Coordinates time_split(); //Get time format ready for the radio print_debug();//This will output the data from the GPS via USB serial debugger. Can eliminate if required. //Prepare the string for transmission int a = sprintf(buffer, "$$%s,%u,%.2ld:%.2ld:%.2ld,%s,%s,%ld,%.2u\0", callsign, ticks, gps.hour, gps.minute, gps.second, gps.lat, gps.lon, gps.alt, gps.sat); //int a = sprintf(buffer, "$$%s,%l unsigned int checksum = CRC16Sum(buffer); char checksum_str[6]; sprintf(checksum_str, "*%04X\n", checksum); int b = sprintf(str_out, "%s%s\n\0", buffer, checksum_str); Serial.println(str_out); ticks++; // Iterate through the string transmitting byte-by-byte. int j=0; while(str_out[j] != 0) { rtty_50(str_out[j]); //Use 50 baud RTTY, to downlink using pin 5 as data pin j++; } delay(500); //This just adds in a delay before starting again with the next line of the code if (1.0*ticks/20 == ticks/20) set_GPS(); //This should every 20th cycle reset the GPS, ensuring that it remains in Nav Mode with all of the correct strings in place //RESET string decoder while(a != '$' && nss.available()) { //This runs through until a dollar sign is reached the start of a new part of the code. a = nss.read(); } comma_count = 0; //This initalise the varibles used in decoding a GPS string. dot_count = 0; gcount = 0; alt_count = 0; } //END OF MAIN LOOP //FUNCTIONS ================================================================================================ void rtty_50(char abit) { //This is the RTTY on pin 5 with 50 baud transmition string digitalWrite(5, LOW); // START BIT set the radio to off delay(20); // wait for 20ms for(int k = 0; k<8; k++){ //This is a loop as there are 8 bits in a byte, which is one charactor if (abit & 1){ // This will return 1 if the last bit is 1, or 0 if the last bit is 0, as 00000001 AND abcdefgh = 0000000h digitalWrite(5, HIGH); //HIGH BIT set the radio to on delay(20); // wait for 20ms } else{ digitalWrite(5, LOW); // Low BIT set the radio to off delay(20); // wait for 20ms } abit = abit >>1; //Shift bits to the right by 1 step } digitalWrite(5, HIGH); // END BIT set the radio to on delay(20); // wait for 20ms }//End of RTTY LOOP void set_GPS(){ // Set the navigation mode (Airborne, 1G) Serial.print("Setting uBlox nav mode: "); uint8_t setNav[] = { 0xB5, 0x62, 0x06, 0x24, 0x24, 0x00, 0xFF, 0xFF, 0x06, 0x03, 0x00, 0x00, 0x00, 0x00, 0x10, 0x27, 0x00, 0x00, 0x05, 0x00, 0xFA, 0x00, 0xFA, 0x00, 0x64, 0x00, 0x2C, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0xDC}; sendUBX(setNav, sizeof(setNav)/sizeof(uint8_t)); getUBX_ACK(setNav); //Switch off GLL Serial.print("Switching off NMEA GLL: "); uint8_t setGLL[] = { 0xB5, 0x62, 0x06, 0x01, 0x08, 0x00, 0xF0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x2B}; sendUBX(setGLL, sizeof(setGLL)/sizeof(uint8_t)); getUBX_ACK(setGLL); //Switch off GSA Serial.print("Switching off NMEA GSA: "); uint8_t setGSA[] = { 0xB5, 0x62, 0x06, 0x01, 0x08, 0x00, 0xF0, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x32}; sendUBX(setGSA, sizeof(setGSA)/sizeof(uint8_t)); getUBX_ACK(setGSA); // Switch off GSV Serial.print("Switching off NMEA GSV: "); uint8_t setGSV[] = { 0xB5, 0x62, 0x06, 0x01, 0x08, 0x00, 0xF0, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03, 0x39}; sendUBX(setGSV, sizeof(setGSV)/sizeof(uint8_t)); getUBX_ACK(setGSV); // Switch off RMC Serial.print("Switching off NMEA RMC: "); uint8_t setRMC[] = { 0xB5, 0x62, 0x06, 0x01, 0x08, 0x00, 0xF0, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x04, 0x40}; sendUBX(setRMC, sizeof(setRMC)/sizeof(uint8_t)); getUBX_ACK(setRMC); //Switch off VTG Serial.print("Switching off NMEA VTG (Test): "); uint8_t setVTG[] = { 0xB5, 0x62, 0x06, 0x01, 0x08, 0x00, 0xF0, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x05, 0x47}; sendUBX(setVTG, sizeof(setVTG)/sizeof(uint8_t)); getUBX_ACK(setVTG); } //END OF SET GPS void time_split(){ //This will split the clock interger to 3 components gps.hour = gps.clock_int/10000; gps.minute = (gps.clock_int - 10000*gps.hour)/100; gps.second = (gps.clock_int - 10000*gps.hour -100*gps.minute); }//End of time_split void GPS_coord() {//This will convert the Coordinate to a form to transmit //Coordinate Conversion long lat_coord_dd, lon_coord_dd; long lat_coord_mm, lon_coord_mm; int a; lat_coord_dd= (gps.lat_int/10000000); lat_coord_mm = ((gps.lat_int - (10000000*lat_coord_dd))/60); gps.lat_int = lat_coord_dd*10000000 + 100*lat_coord_mm; //This should return a coordinate as an interger using DD.DDDDD notation lon_coord_dd= (gps.lon_int/10000000); lon_coord_mm = ((gps.lon_int - (10000000*lon_coord_dd))/60); gps.lon_int = lon_coord_dd*10000000 + 100*lon_coord_mm; //This should return a coordinate as an interger using DD.DDDDD notation //Create a char array in the form of a signed float //latitude zero_lookup(lat_coord_mm); if (gps.ns == 'N'){ a = sprintf(gps.lat, "%.2ld.%s%ld\0", lat_coord_dd, gps.blanks, lat_coord_mm); } else{ a = sprintf(gps.lat, "-%.2ld.%s%ld\0", lat_coord_dd, gps.blanks, lat_coord_mm); //This is negative when in the northern hemisphere } //longitude zero_lookup(lon_coord_mm); if (gps.ew == 'E'){ a = sprintf(gps.lon, "%.2ld.%s%ld\0", lon_coord_dd, gps.blanks, lon_coord_mm); } else{ a = sprintf(gps.lon, "-%.2ld.%s%ld\0", lon_coord_dd, gps.blanks, lon_coord_mm); //This is negative when in the southern hemisphere } }//End of GPS shift void zero_lookup(long small_part){ //This will fill in zeros after the decimal point int n = 5; if (small_part == 0){ n=4; } else{ while (small_part != 0) { small_part = small_part/10; n--; } } if (n>0){ for (int i = 0; i<n; i++){ gps.blanks[i] = '0'; } } gps.blanks[n] = '\0'; }//End of zero_lookup void print_debug(){ //This will output the data from the GPS via USB serial debugger. Serial.println(" "); Serial.print("Time: "); Serial.print(gps.hour); Serial.print(":"); Serial.print(gps.minute); Serial.print(":"); Serial.println(gps.second); Serial.print("Latitude: "); Serial.println(gps.lat); Serial.print("Longitude: "); Serial.println(gps.lon); Serial.print("Number of sats: "); Serial.println(gps.sat); Serial.print("Altitude: "); Serial.println(gps.alt); }//end of Debug unsigned int CRC16Sum(char *string) { //This will find the check sum unsigned int i; unsigned int crc; crc = 0xFFFF; // Calculate the sum, ignore $ sign's for (i = 0; i < strlen(string); i++) { if (string[i] != '$') crc = _crc_xmodem_update(crc,(uint8_t)string[i]); } return crc; } //END OF CHECKSUM LOOP // Send a byte array of UBX protocol to the GPS void sendUBX(uint8_t *MSG, uint8_t len) { for(int i=0; i<len; i++) { nss.print(MSG[i], BYTE); Serial.print(MSG[i], HEX); } Serial.println(); }//END sendUBX // Calculate expected UBX ACK packet and parse UBX response from GPS boolean getUBX_ACK(uint8_t *MSG) { uint8_t b; uint8_t ackByteID = 0; uint8_t ackPacket[10]; unsigned long startTime = millis(); Serial.print(" * Reading ACK response: "); // Construct the expected ACK packet ackPacket[0] = 0xB5; // header ackPacket[1] = 0x62; // header ackPacket[2] = 0x05; // class ackPacket[3] = 0x01; // id ackPacket[4] = 0x02; // length ackPacket[5] = 0x00; ackPacket[6] = MSG[2]; // ACK class ackPacket[7] = MSG[3]; // ACK id ackPacket[8] = 0; // CK_A ackPacket[9] = 0; // CK_B // Calculate the checksums for (uint8_t i=2; i<8; i++) { ackPacket[8] = ackPacket[8] + ackPacket[i]; ackPacket[9] = ackPacket[9] + ackPacket[8]; } while (1) { // Test for success if (ackByteID > 9) { // All packets in order! Serial.println(" (SUCCESS!)"); return true; } // Timeout if no valid response in 3 seconds if (millis() - startTime > 3000) { Serial.println(" (FAILED!)"); return false; } // Make sure data is available to read if (nss.available()) { b = nss.read(); // Check that bytes arrive in sequence as per expected ACK packet if (b == ackPacket[ackByteID]) { ackByteID++; Serial.print(b, HEX); } else { ackByteID = 0; // Reset and look again, invalid order } } } }//End of getUBX_ACK </code> ===== C++ GPGGA to Char Arrays ===== This program now will read a GPGGA string, and extract all info required. It needs to be intergrated in to the arduino code, and is close to working. The program works by counting commas. Then needs converting into arduino code. <code cpp> #include <stdio.h> #include <iostream> #include <stdlib.h> using namespace std; int main() { //DECLARE Varibles char sentence []="$$GPGGA,183439.00,5211.88950,N,00007.22003,W,1,05,2.96,61.5,M,45.7,M,,*6B"; //Test String //char sentence []="$$GPGGA,183439.00,5211.88950,N,00007.22003,W,1,05(stat),2.96,61.5(alt),M,45.7,M,,*6B"; char clock[8]; //The time char lat[11], lon[11]; //Lat and Long, in separated parts char ns, ew, no_sat[3], alt[8], a; //Various other readings int alt_count= 0; int gcount=0, comma_count=0, dot_count=0, array_count=0; long int lon_int, lat_int, alt_int, clock_int; int sat; for (int i=0; i<8; i++){ clock[i]=0; } while (sentence[gcount] != '*' & gcount <100){ a=sentence[gcount]; //Active charictar cout << a ; //output a if (a == ',') { //comma responce comma_count++; array_count=0; } if (a == '.') dot_count++; //dot count switch (comma_count) { //Switch command case 1: //This is the time if (dot_count ==0){ //Only work before the dot! clock[array_count]=a; //cout<< " time " << clock[array_count] << " count " << array_count; if (a!= ',') array_count++; } break; case 2: // This is latitude if (a != '.'& a != ',') { lat[array_count] = a; array_count++; } break; case 3: //N/S if (a !=',') ns=a; break; case 4: // This is latitude if (a != '.'& a != ',') { lon[array_count] = a; array_count++; } break; case 5: //E/W if (a !=',') ew=a; break; case 7: //Stats if (a != '.'& a != ',') { no_sat[array_count] = a; array_count++; } break; case 9: //Alt if (a != '.'& a != ',') { alt[array_count] = a; array_count++; alt_count++; } break; } gcount++; } clock[6]='\0'; lat[10]='\0'; lon[10]='\0'; no_sat[2]='\0'; alt[alt_count-1]='\0'; cout<<endl; //INT CONVERSION lon_int = atol(lon); lat_int = atol(lat); alt_int = atol(alt); clock_int = atol(clock); sat = atoi(no_sat); //Coordinate Conversion int n_coor_dd, e_coor_dd; int n_coor_mm, e_coor_mm; long int n_out, e_out; n_coor_dd= (lat_int/10000000); cout << n_coor_dd<< endl; n_coor_mm = ((lat_int - (10000000*n_coor_dd))/60); n_out = n_coor_dd*10000000 + 100*n_coor_mm; cout << n_out<< endl; e_coor_dd= (lon_int/10000000); cout << e_coor_dd<< endl; e_coor_mm = ((lon_int - (10000000*e_coor_dd))/60); e_out = e_coor_dd*10000000 + 100*e_coor_mm; cout << e_out<< endl; if (ew == 'W') e_out= -e_out; if (ns == 'S') n_out = -n_out; cout<<"Finished loop"<<endl; cout<<"Time: " << clock <<endl; //for (int i=0; i<6; i++){ //cout<<clock[i]; //} //cout<<"end"; cout<<"Latitude: "<<lat<<ns<<endl; cout<<"Longitude: "<<lon<<ew<<endl; cout<<"Number of sats: "<<no_sat<<endl; cout<<"Altitude: "<<alt<<endl; //RESET comma_count = 0; dot_count =0; gcount = 0; } </code> ===== GPS String Reader ===== This will read the string, and separate out the variables for GPS, time, and altitude. This will work find in a C++ complier. Sadly doesn't work when put on the Arduino. Any ideas? <code cpp> #include <stdio.h> int main() { //Read the data_ char sentence []="$GPGGA,183439.00,5211.88950,N,00007.22003,W,1,05,2.96,61.5,M,45.7,M,,*6B"; //Test String char N_S; //N/S char E_W; // E/W float n_coord, e_coord, altitude, GPStime;//this will be north/south coordinates sscanf (sentence, "$GPGGA,%f,%f,%c,%f,%c,%*d,%*d,%*f,%f,%*c,%*f,%*c,,*%*s", &GPStime, &n_coord, &N_S,&e_coord,&E_W,&altitude); //Analysis sentence printf ("%f %c %f %c %f %f\n",GPStime, N_S, n_coord,E_W,e_coord,altitude); //Will now display the answers //convert coordinates //convert North int n_coor_dd, e_coor_dd; float n_coor_mm, e_coor_mm; float n_out, e_out; n_coor_dd= (n_coord/100); n_coor_mm = ((n_coord - (100*n_coor_dd))/60); n_out = n_coor_dd + n_coor_mm; //covert East e_coor_dd= (e_coord/100); e_coor_mm = ((e_coord - (100*e_coor_dd))/60); e_out = e_coor_dd + e_coor_mm; //make sure degrees is negative if West of Meridan char W = 'W'; char S = 'S'; if (E_W == W) e_out= -e_out; if (N_S == S) n_out = -n_out; //Convert altitude to feet altitude = 3.2808399*altitude; printf ("%f\n", n_out); printf ("%f\n", e_out); printf ("%f\n", altitude); return 0; //End of program } </code> ===== cut the cord ===== when the tracker go beyond a certain distance away from the launch site. give out a signal using an amplifier circuit and an ematch ignites explosives to cut the balloon loose. the current parameters are 60km northeast 90 southeast 200 south west 250 northwest. variable "result" stores the result of the function: 0:in range 1: out of range but cord uncut 2:successfully cut off which can be sent by radio to notify the status of the balloon ====circuit diagram==== {{https://lh5.googleusercontent.com/-_okrrjXgOkE/TfvCmscXVxI/AAAAAAAAAVU/CRUWfjwJPWQ/s400/pyro.JPG}} the transistor used http://www.fairchildsemi.com/ds/2N/2N7000.pdf but could use any enhance mode transistor. <code cpp> int explode(int X, int Y); void trigger(); int fire_pin=13; int test_pin=12; //set pins change accordingly //put the following section in the setup. void setup() { pinMode(fire_pin, OUTPUT); // initialize the digital pin as an output. pinMode(test_pin, INPUT); digitalWrite(fire_pin, LOW); //set it low so it doesn't pop when turned on. } //the following section in main loop void loop() { float X=100; //latitude float Y=100; //equate to the longitude(remenber to divide by scale factor) int result; //store the result of the calls. 0:in range 1: out of range but cord uncut 2:successfully cut off if (explode(X,Y,result))trigger(result); } //function to check weather out of range. can run at and regualr interval. maybe everytime when the navimode resets int explode(float X, float Y,int& result) { X=X/360*2*3.1415926; Y=Y/360*2*3.1415926; result=1; float cam_x = 0.0017453; float cam_y = 0.45564; float d = sqrt((X-cam_x)*(X-cam_x)+(X-cam_y)*(X-cam_y))*(6067); //perpenducular triangle if (X-cam_x>0 && Y-cam_y>0 && d>60) return (1); else if (X-cam_x>0 && Y-cam_y<0 && d>90) return(1); else if (X-cam_x<0 && Y-cam_y>0 && d>250) return(1); else if (X-cam_x<0 && Y-cam_y<0 && d>200) return(1); else {result=0; return (0);} } void trigger(int& result) { for(int n=3;n>0;n++)//try trigger 3 times { digitalWrite(fire_pin, HIGH); // set the pin hi delay(1000); //wait for a second not sure if its enough digitalWrite(fire_pin, LOW); //set it back } if(!digitalRead(test_pin))result++; //test weather successful } </code> ===== Nova 19 Arduino code ===== This is the code that was used in Nova 19. However this has 2 bugs: - Every 20 ticks it resets the GPS into Nav mode. However this causes a blip in the output data string, causing the coordinates not to update, and the altitude to become zero - If Coordinate is 0.08912, it will show as 0.89120. This is due to a bug cause by storing the part after the decimal point as a separate integer. Both these bugs are corrected in the BETA code at the bottom of the page. This BETA code is probably better, and has been tested briefly with test strings, and bug 2 is fixed. However I have not tested that code with a real GPS chip, as the original board is stuck up a tree. <code cpp> // This code sets a FSA03 GPS module to give gps data to a radio module to downlink to earth. //Code written by Chris Murkin, Leo, Hannah, and CU Spaceflight with FSA03 set up code from the UKHAS website //The check sum code was borrowed from CUSF Ferret Tracker, written by Jon Sowman avalible from Git hub. //This code will only work in the NORTHERN hemisphere, any people wishing to use this from southern hemisphere need to modify the sscanf function with a simlar //statement to the one currently used for putting the sign on EW transistion. #include <NewSoftSerial.h> #include <stdio.h> #include <string.h> #include <util/crc16.h> //Set New soft serial to GPS NewSoftSerial nss(3, 2); char clock[8]; //The time char lat[11], lon[11]; //Lat and Long, in separated parts char ns, ew, no_sat[3], alt[8], a; //Various other readings int alt_count= 0; int gcount=0, comma_count=0, dot_count=0, array_count=0; long lon_int, lat_int; long alt_int, clock_int, ticks; int sat; long lat_big, lat_small, long_big, long_small; long hour, minute, second; unsigned long chars; unsigned short sentences, failed_checksum; char buffer[200]; char str_out[200]; char callsign[7] = "WEASEL"; void setup() { // Start up serial ports nss.begin(38400); Serial.begin(115200); // used for debug ouput delay(2000); // Give the GPS time to come boot // Lower the baud rate to 9600 from 38.4k Serial.print("Setting uBlox port mode: "); uint8_t setPort[] = {0xB5, 0x62, 0x06, 0x00, 0x14, 0x00, 0x01, 0x00, 0x00, 0x00, 0xD0, 0x08, 0x00, 0x00, 0x80, 0x25, 0x00, 0x00, 0x03, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9E, 0x95}; sendUBX(setPort, sizeof(setPort)/sizeof(uint8_t)); // Switch baud rates on the software serial Serial.println("Switching to 9600b GPS serial"); nss.begin(9600); delay(1000); set_GPS(); ticks = 1; } //END OF SET UP LOOP void loop() { //READ THE GPS AND EXTRACT THE USEFUL DA while (a != '*' && gcount <120 && nss.available()){ a = nss.read(); Serial.print(a); if (a == ',') { //comma responce comma_count++; array_count=0; } if (a == '.') dot_count++; //dot count switch (comma_count) { //Switch command case 1: //This is the time //Serial.print(" Time "); if (dot_count ==0){ //Only work before the dot! clock[array_count]=a; if (a!= ',') array_count++; } break; case 2: // This is latitude if (a != '.'& a != ',') { lat[array_count] = a; array_count++; } break; case 3: //N/S if (a !=',') ns=a; break; case 4: // This is latitude if (a != '.'& a != ',') { lon[array_count] = a; array_count++; } break; case 5: //E/W if (a !=',') ew=a; break; case 7: //Stats if (a != '.'& a != ',') { no_sat[array_count] = a; array_count++; } break; case 9: //Alt if (a != '.'& a != ',') { alt[array_count] = a; array_count++; alt_count++; } break; } gcount++; } //This is the end of the loop that runs until a * is reached. //Insert stop bits on the string. clock[6]='\0'; lat[10]='\0'; lon[10]='\0'; no_sat[2]='\0'; alt[alt_count]='\0'; //INT CONVERSION lon_int = atol(lon); lat_int = atol(lat); alt_int = atol(alt)/10; clock_int = atol(clock); sat = atoi(no_sat); //TEST CODE = MAKESURE OFF FOR LAUNCH //ew='W'; //This will simulate crossing the prime meridian //GPS Coordinate preparation GPS_Cood(lon_int, lat_int, lat_big, lat_small, long_big, long_small); //This will convert to DD.DDDDD format, and will split about decimal point for transmission. //This will output the data from the GPS via USB serial debugger. Serial.println(" "); Serial.print("Time: "); Serial.println(clock_int); Serial.print("Latitude: "); Serial.print(lat_big); Serial.print("."); Serial.println(lat_small); Serial.print("Longitude: "); if (ew == 'W') Serial.print("-"); //This will put in the minus sign if West of prime meridian Serial.print(long_big); Serial.print("."); Serial.println(long_small); Serial.print("Number of sats: "); Serial.println(sat); Serial.print("Altitude: "); Serial.println(alt_int); //Get time format ready for the radio time_split(clock_int, hour, minute, second); //RESET string decoder while(a != '$') { //This runs through until a dollar sign is reached the start of a new part of the code. a = nss.read(); } comma_count = 0; dot_count =0; gcount = 0; alt_count = 0; //Prepare the string for transmission if (ew=='W'){ //Will put in the negative sign when in the Western Hemisphere. int a = sprintf(buffer, "$$%s,%ld,%.2ld:%.2ld:%.2ld,%ld.%ld,-%ld.%ld,%ld;%.2u,\0", callsign, ticks, hour, minute, second, lat_big, lat_small, long_big, long_small, alt_int, sat); } else{ int a = sprintf(buffer, "$$%s,%ld,%.2ld:%.2ld:%.2ld,%ld.%ld,%ld.%ld,%ld;%.2u,\0", callsign, ticks, hour, minute, second, lat_big, lat_small, long_big, long_small, alt_int, sat); } unsigned int checksum = CRC16Sum(buffer); char checksum_str[6]; sprintf(checksum_str, "*%04X\n", checksum); int b = sprintf(str_out, "%s%s\n\0", buffer, checksum_str); Serial.println(str_out); ticks++; //buffer="$$WEASEL,62,17:51:5249,52.19846,0.12082,0"; // Iterate through the string transmitting byte-by-byte. int j=0; while(str_out[j] != 0) { rtty_50(str_out[j]); //Use 50 baud RTTY, to downlink using pin 5 as data pin j++; } delay(500); //This just adds in a delay before starting again with the next line of the code if (1.0*ticks/10 == ticks/10) set_GPS(); //This should every tenth cycle reset the GPS, ensuring that it remains in Nav Mode with all of the correct strings in place } //END OF MAIN LOOP //FUNCTIONS void rtty_50(char abit) { //This is the RTTY on pin 5 with 50 baud transmition string digitalWrite(5, LOW); // START BIT set the radio to off delay(20); // wait for 20ms for(int k = 0; k<8; k++){ //This is a loop as there are 8 bits in a byte, which is one charactor if (abit & 1){ // This will return 1 if the last bit is 1, or 0 if the last bit is 0, as 00000001 AND abcdefgh = 0000000h digitalWrite(5, HIGH); //HIGH BIT set the radio to on delay(20); // wait for 20ms } else{ digitalWrite(5, LOW); // Low BIT set the radio to off delay(20); // wait for 20ms } abit = abit >>1; //Shift bits to the right by 1 step } digitalWrite(5, HIGH); // END BIT set the radio to on delay(20); // wait for 20ms }//End of RTTY LOOP void set_GPS(){ // Set the navigation mode (Airborne, 1G) Serial.print("Setting uBlox nav mode: "); uint8_t setNav[] = {0xB5, 0x62, 0x06, 0x24, 0x24, 0x00, 0xFF, 0xFF, 0x06, 0x03, 0x00, 0x00, 0x00, 0x00, 0x10, 0x27, 0x00, 0x00, 0x05, 0x00, 0xFA, 0x00, 0xFA, 0x00, 0x64, 0x00, 0x2C, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0xDC}; sendUBX(setNav, sizeof(setNav)/sizeof(uint8_t)); getUBX_ACK(setNav); //Switch off GLL Serial.print("Switching off NMEA GLL: "); uint8_t setGLL[] = { 0xB5, 0x62, 0x06, 0x01, 0x08, 0x00, 0xF0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x2B }; sendUBX(setGLL, sizeof(setGLL)/sizeof(uint8_t)); getUBX_ACK(setGLL); //Switch off GSA Serial.print("Switching off NMEA GSA: "); uint8_t setGSA[] = { 0xB5, 0x62, 0x06, 0x01, 0x08, 0x00, 0xF0, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x32 }; sendUBX(setGSA, sizeof(setGSA)/sizeof(uint8_t)); getUBX_ACK(setGSA); // Switch off GSV Serial.print("Switching off NMEA GSV: "); uint8_t setGSV[] = { 0xB5, 0x62, 0x06, 0x01, 0x08, 0x00, 0xF0, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03, 0x39 }; sendUBX(setGSV, sizeof(setGSV)/sizeof(uint8_t)); getUBX_ACK(setGSV); // Switch off RMC Serial.print("Switching off NMEA RMC: "); uint8_t setRMC[] = { 0xB5, 0x62, 0x06, 0x01, 0x08, 0x00, 0xF0, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x04, 0x40 }; sendUBX(setRMC, sizeof(setRMC)/sizeof(uint8_t)); getUBX_ACK(setRMC); //Switch off VTG Serial.print("Switching off NMEA VTG (Test): "); uint8_t setVTG[] = { 0xB5, 0x62, 0x06, 0x01, 0x08, 0x00, 0xF0, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x05, 0x47 }; sendUBX(setVTG, sizeof(setVTG)/sizeof(uint8_t)); getUBX_ACK(setVTG); } //END OF SET GPS void time_split(long clock_int, long &hour, long &minute, long &second){ //This will split the clock interger to 3 components hour = clock_int/10000; minute = (clock_int - 10000*hour)/100; second = (clock_int - 10000*hour -100*minute); }//End of time_split void GPS_Cood(long lon_int, long lat_int, long &lat_big, long &lat_small, long &long_big, long &long_small) {//This will convert the Coordinate to a form to transmit //Coordinate Conversion long n_coor_dd, e_coor_dd; long n_coor_mm, e_coor_mm; long n_out, e_out; n_coor_dd= (lon_int/10000000); n_coor_mm = ((lon_int - (10000000*n_coor_dd))/60); n_out = n_coor_dd*10000000 + 100*n_coor_mm; e_coor_dd= (lat_int/10000000); e_coor_mm = ((lat_int - (10000000*e_coor_dd))/60); e_out = e_coor_dd*10000000 + 100*e_coor_mm; //Get gps cooridinates ready for transmission lat_big = e_out/10000000; lat_small = e_out - 10000000*lat_big; long_big = n_out/10000000; long_small = n_out-10000000*long_big; }//End of GPS shift unsigned int CRC16Sum(char *string) { //This will find the check sum unsigned int i; unsigned int crc; crc = 0xFFFF; // Calculate the sum, ignore $ sign's for (i = 0; i < strlen(string); i++) { if (string[i] != '$') crc = _crc_xmodem_update(crc,(uint8_t)string[i]); } return crc; } //END OF CHECKSUM LOOP // Send a byte array of UBX protocol to the GPS void sendUBX(uint8_t *MSG, uint8_t len) { for(int i=0; i<len; i++) { nss.print(MSG[i], BYTE); Serial.print(MSG[i], HEX); } Serial.println(); } // Calculate expected UBX ACK packet and parse UBX response from GPS boolean getUBX_ACK(uint8_t *MSG) { uint8_t b; uint8_t ackByteID = 0; uint8_t ackPacket[10]; unsigned long startTime = millis(); Serial.print(" * Reading ACK response: "); // Construct the expected ACK packet ackPacket[0] = 0xB5; // header ackPacket[1] = 0x62; // header ackPacket[2] = 0x05; // class ackPacket[3] = 0x01; // id ackPacket[4] = 0x02; // length ackPacket[5] = 0x00; ackPacket[6] = MSG[2]; // ACK class ackPacket[7] = MSG[3]; // ACK id ackPacket[8] = 0; // CK_A ackPacket[9] = 0; // CK_B // Calculate the checksums for (uint8_t i=2; i<8; i++) { ackPacket[8] = ackPacket[8] + ackPacket[i]; ackPacket[9] = ackPacket[9] + ackPacket[8]; } while (1) { // Test for success if (ackByteID > 9) { // All packets in order! Serial.println(" (SUCCESS!)"); return true; } // Timeout if no valid response in 3 seconds if (millis() - startTime > 3000) { Serial.println(" (FAILED!)"); return false; } // Make sure data is available to read if (nss.available()) { b = nss.read(); // Check that bytes arrive in sequence as per expected ACK packet if (b == ackPacket[ackByteID]) { ackByteID++; Serial.print(b, HEX); } else { ackByteID = 0; // Reset and look again, invalid order } } } } </code>

weasel_code.1310912400.txt.gz · Last modified: 2011/07/17 15:20 by chrism