Team Members:
- Joseph Kopacz
- Brian Bybee
- Ryan Clouse
- Corey Barringer
- CSU Space Grant:
http://spacegrant.engr.
colostate.edu/ - Colorado Space Grant Consortium:
http://spacegrant.colorado.
edu/
Technical Details:
- Thrust Fans
- 3.3 Volts
- 1.3 Amps Peak
- 8300 RPM
- 3x3 Two-Blade Propeller
- Battery
- 11.1 Volts
- 6600 mAh
- ~11lb
- Electronics
- Xbee (wireless communication)
- 300ft (line of sight)
- 3.3 Volts
- 50 mA
- Compass
- 5 Volts
- 1 mA
- .5 Degree Resolution
- GPS
- 3.3 Volts
- 41 mA
- 66 Channels
- Humidity Sensor
- 5 Volts
- 200 uA
- Analog Output
- Temperature and Pressure Sensor
- 3.3 Volts
- 200 uA
- I2C Protocol
- Arduino
- Atmel Processor
- 1 Hardware Serial Port
- Multiple Digital and Analog Ports
- I2C Capable
Video:
Pictures:
Interactive GUI
Power Management Circuit
Controls Circuit
Arduino Source Code:
#include <Wire.h>
#include <BMP085.h>
#include <NewSoftSerial.h> #include <TinyGPS.h> #include <PID_v1.h> #include <avr/pgmspace.h> //Global Vars int HMC6352SlaveAddress = 0x42; int HMC6352ReadAddress = 0x41; //"A" in hex, A command is: BMP085 dps = BMP085(); long Temperature = 0, Pressure = 0, Altitude = 0; #define line 1 #define no_line 0 //speak function prog_char string_0[] PROGMEM = "Finished Initializing Ready for commands"; // "String 0" etc are strings to store - change to suit. prog_char string_1[] PROGMEM = "Temp(C):"; prog_char string_2[] PROGMEM = "Pressure(Pa):"; prog_char string_3[] PROGMEM = "Humidity "; prog_char string_4[] PROGMEM = "Compass Heading = "; prog_char string_5[] PROGMEM = " degrees"; prog_char string_6[] PROGMEM = "Please Enter New Values for Kp,Ki,Kd"; prog_char string_7[] PROGMEM = "60.0,20.0,30.0"; prog_char string_8[] PROGMEM = "Kp = "; prog_char string_9[] PROGMEM = "Ki = "; prog_char string_10[] PROGMEM = "Kd = "; prog_char string_11[] PROGMEM = "Enter Heading"; prog_char string_12[] PROGMEM = "The Desired Heading is "; prog_char string_13[] PROGMEM = "Enter motor power"; prog_char string_14[] PROGMEM = "Motor Power Set: "; prog_char string_15[] PROGMEM = "Enter Gps Coordinates"; prog_char string_16[] PROGMEM = "Format - (LAT),(LON) "; prog_char string_17[] PROGMEM = "/"; prog_char string_18[] PROGMEM = "Maintaining Straight Course"; prog_char string_19[] PROGMEM = "Turning Left 45 Degrees"; prog_char string_20[] PROGMEM = "Turning Right 45 Degrees"; prog_char string_21[] PROGMEM = "Kill Motors"; prog_char string_22[] PROGMEM = "Flip 180 Degrees"; prog_char string_23[] PROGMEM = "Information Page (Manual)"; prog_char string_24[] PROGMEM = "v - Display Temp, Pressure, Humidity, Heading"; prog_char string_25[] PROGMEM = "c - Enter New PID Constants"; prog_char string_26[] PROGMEM = "p - Adjust Motor Power"; prog_char string_27[] PROGMEM = "h - Enter Heading Menu"; prog_char string_28[] PROGMEM = "g - Enter GPS Heading Menu"; prog_char string_29[] PROGMEM = "w,a,d,s - Manual controls"; prog_char string_30[] PROGMEM = "q - Kill All Motors"; PROGMEM const char *string_table[] = // change "string_table" name to suit { string_0, string_1, string_2, string_3, string_4, string_5, string_6, string_7, string_8, string_9, string_10, string_11, string_12, string_13, string_14, string_15, string_16, string_17, string_18, string_19, string_20, string_21, string_22, string_23, string_24, string_25, string_26, string_27, string_28, string_29, string_30, }; //Initialize GPS NewSoftSerial nss(2, 3); TinyGPS gps; //Initialize PID double Setpoint, Input, Output; PID myPID(&Input, &Output, &Setpoint,30,0,30, DIRECT); float Ki = 30, Kp = 0, Kd = 30; //Motor Power setting float motor_power = .40; void setup() { pinMode(7, OUTPUT); digitalWrite(7, HIGH); HMC6352SlaveAddress = HMC6352SlaveAddress >> 1; Serial.begin(9600); Wire.begin(); delay(1000); //initialize gps soft serial nss.begin(57600); //Initialize temp and pressure sensor dps.init(); //Initialize PID myPID.SetMode(AUTOMATIC); //Show finished initialization speak(0,line); digitalWrite(7, LOW); delay(300); digitalWrite(7, HIGH); delay(300); digitalWrite(7, LOW); delay(300); digitalWrite(7, HIGH); } void loop() // run over and over again { //Control Vars char var; #define motor_left 10 #define motor_right 11 //Humidity Vars int val = 0, humidity = 0; float realhumidity; //PID char buffer_const[14]; //Heading vars int i = 0; char buffer[3]; float current_heading, desired_heading = 0; //GPS long lat_gps, lon_gps,lat_head, lon_head, lat, lon; unsigned long age_gps; char buffer_gps[17]; //Stabalize craft while not doing anything analogWrite(motor_left, 0); analogWrite(motor_right, 255 * .26); if (Serial.available()) { var = Serial.read(); delay(6); } switch (var) { case 'v': Serial.print("Avalible memory "); Serial.println(availableMemory()); //read and print temp and pressure dps.getTemperature(&Temperature); dps.getPressure(&Pressure); Serial.println(); speak(1,no_line); Temperature = Temperature * .1; Serial.println(Temperature); speak(2,no_line); Serial.println(Pressure); // read and print humidity val = analogRead(0); humidity = val*0.157380254-25.8; //Decimal from 161/1023 realhumidity =humidity/(1.0546-.0026*Temperature); speak(3,no_line); Serial.print(realhumidity); Serial.println("%"); //read and print compass heading desired_heading = Heading(); speak(4,no_line); Serial.print(desired_heading); speak(5,no_line); break; case 'c': //Adjust PID Constants Serial.println(); speak(6,line); speak(7,line); while(Serial.available() < 14) //Wait for 14 bytes to be availible { delay(5); } while(Serial.available()) //Read `4 bytes into array { for(i=0; i<14; i++) { buffer_const[i] = Serial.read(); } } Kp = atof(strtok(buffer_const, ",")); Ki = atof(strtok (NULL, ",")); Kd = atof(strtok (NULL, ",")); myPID.SetTunings(Kp, Ki, Kd); speak(8,no_line); Serial.println(Kp); speak(9,no_line); Serial.println(Ki); speak(10,no_line); Serial.println(Kd); break; case 'h': Serial.println(); speak(11,line); while(Serial.available() < 3) //Wait for three bytes to be availible { delay(5); } while(Serial.available()) //Read 3 bytes into array { for(i=0; i<3; i++) { buffer[i] = Serial.read(); } } desired_heading = atoi(buffer); //convert array into int Serial.println(); speak(12,no_line); Serial.println(desired_heading); while(Serial.available()==0) //while there are no other commands maintain entered heading { motor_control(desired_heading); } break; case 'p': Serial.println(); speak(13,line); while(Serial.available() < 3) //Wait for three bytes to be availible { delay(5); } while(Serial.available()) //Read 3 bytes into array { for(i=0; i<3; i++) { buffer[i] = Serial.read(); } } motor_power = atof(buffer); //convert array into int speak(14,no_line); Serial.println(motor_power); break; case 'g': Serial.println(); speak(15,line); speak(16,line); while(Serial.available() < 17) //Wait for 17 bytes to be availible { delay(5); } while(Serial.available()) //Read 17 bytes into array { for(i=0; i<17; i++) { buffer_gps[i] = Serial.read(); } } lat = atol(strtok(buffer_gps, ",")); lon = atol(strtok (NULL, ",")); while(Serial.available()==0) //while there are no other commands maintain entered heading { //Get data from GPS while (nss.available()) { gps.encode(nss.read()); } gps.get_position(&lat_gps, &lon_gps, &age_gps); desired_heading = atan2(lon-lon_gps,lat-lat_gps); desired_heading = (desired_heading*(180.0/3.14)-360.0); desired_heading = ((int)desired_heading)% 360; desired_heading = desired_heading * -1; motor_control(desired_heading); current_heading = Heading(); Serial.print(current_heading); val = analogRead(0); humidity = val*0.157380254-25.8; //Decimal from 161/1023 realhumidity = humidity/(1.0546-.0026*Temperature); speak(17,no_line); Serial.print(realhumidity); dps.getTemperature(&Temperature); dps.getPressure(&Pressure); dps.getAltitude(&Altitude); Temperature = Temperature * .1; speak(17,no_line); Serial.print(Temperature); speak(17,no_line); Serial.print(Pressure); speak(17,no_line); Serial.print(lat_gps); speak(17,no_line); Serial.println(lon_gps); } break; case 'w': //maintain straight course Serial.println(); speak(18,line); desired_heading = Heading(); while(Serial.available()==0) //while there are no other commands maintain entered heading { motor_control(desired_heading); } break; case 'a': //Turn left 45 degrees Serial.println(); speak(19,line); desired_heading = Heading(); desired_heading = desired_heading + 45.0; if (desired_heading > 360) { desired_heading = desired_heading - 360; } while(Serial.available()==0) //while there are no other commands maintain entered heading { motor_control(desired_heading); } break; case 'd': //Turn right 45 degrees Serial.println(); speak(20,line); desired_heading = Heading(); desired_heading = desired_heading - 45.0; if (desired_heading < 0) { desired_heading = desired_heading + 360; } while(Serial.available()==0) //while there are no other commands maintain entered heading { motor_control(desired_heading); } break; case 'q': Serial.println(); speak(21,line); analogWrite(motor_left,0); analogWrite(motor_right,0); break; case 's': Serial.println(); speak(22,line); desired_heading = Heading(); desired_heading = desired_heading + 180; if (desired_heading > 360) { desired_heading = desired_heading - 360; } while(Serial.available()==0) //while there are no other commands maintain entered heading { motor_control(desired_heading); } break; case 'm': Serial.println(); speak(23,line); speak(24,line); speak(25,line); speak(26,line); speak(27,line); speak(28,line); speak(29,line); speak(30,line); break; } } float Heading() { //Compass Vars byte MSB; byte LSB; float headingSum; float headingInt; //read and send compass heading Wire.beginTransmission(HMC6352SlaveAddress); Wire.send(HMC6352ReadAddress); // The "Get Data" command Wire.endTransmission(); //time delays required by HMC6352 upon receipt of the command delay(6); Wire.requestFrom(HMC6352SlaveAddress, 2); //get the two data bytes, MSB and LSB //"The heading output data will be the value in tenths of degrees from zero to 3599 and provided in binary format over the two bytes." MSB = Wire.receive(); LSB = Wire.receive(); headingSum = (MSB << 8) + LSB; //(MSB / LSB sum) headingInt = headingSum / 10; return headingInt; } void motor_control(float desired_heading) { float current_heading; int output; current_heading = Heading(); Setpoint = 0; if ((current_heading - desired_heading) > 180) { Input = ((360-current_heading)+desired_heading)*-1; } if((current_heading - desired_heading) < -180) { Input = (360-desired_heading)+current_heading; } if((current_heading - desired_heading)> -180 && (current_heading - desired_heading) < 180) { Input = current_heading - desired_heading; } myPID.Compute(); //Works to maintain heading if (Output > 0) { if (Output + (255*motor_power) >= 255) { output=255; } else { output = Output +(255*motor_power); } analogWrite(10,255*motor_power); analogWrite(11,output); } if (Output < 0) { if (Output - (255*motor_power) <= -255) { output=-255; } else { output = Output -(255*motor_power); } analogWrite(11,255*motor_power); analogWrite(10, (output * -1)); } } int availableMemory() { int size = 1024; // Use 2048 with ATmega328 byte *buf; while ((buf = (byte *) malloc(--size)) == NULL) ; free(buf); return size; } void speak(int string_num, int ln) { char write_buffer[44]; strcpy_P(write_buffer, (char *)pgm_read_word(string_table + string_num)); if (ln == 1) { Serial.println(write_buffer); } if (ln == 0) { Serial.print(write_buffer); } }
No comments:
Post a Comment