====== Co-Axial Helicopter with IR Elevation Control Code ====== ===== Code to send IR pulses ===== #include //comment this out to see the demodulated waveform //it is useful for debugging purpose. #define MODULATED 1 const int IR_PIN = 3; const int IR_PIN2 = 4; const int IR_PIN3 = 5; const unsigned long DURATION = 180000l; const int HEADER_DURATION = 2000; const int HIGH_DURATION = 380; const int ZERO_LOW_DURATION = 220; const int ONE_LOW_DURATION = 600; const byte ROTATION_STATIONARY = 60; const byte CAL_BYTE = 52; int Throttle, LeftRight, FwdBack; void sendHeader() { #ifndef MODULATED digitalWrite(IR_PIN, HIGH); digitalWrite(IR_PIN2, HIGH); digitalWrite(IR_PIN3, HIGH); #else TCCR2A |= _BV(COM2B1); #endif delayMicroseconds(HEADER_DURATION); #ifndef MODULATED digitalWrite(IR_PIN, LOW); digitalWrite(IR_PIN2, LOW); digitalWrite(IR_PIN3, LOW); #else TCCR2A &= ~_BV(COM2B1); #endif delayMicroseconds(HEADER_DURATION); #ifndef MODULATED digitalWrite(IR_PIN, HIGH); digitalWrite(IR_PIN2, HIGH); digitalWrite(IR_PIN3, HIGH); #else TCCR2A |= _BV(COM2B1); #endif delayMicroseconds(HIGH_DURATION); #ifndef MODULATED digitalWrite(IR_PIN, LOW); digitalWrite(IR_PIN2, LOW); digitalWrite(IR_PIN3, LOW); #else TCCR2A &= ~_BV(COM2B1); #endif } void sendZero() { delayMicroseconds(ZERO_LOW_DURATION); #ifndef MODULATED digitalWrite(IR_PIN, HIGH); digitalWrite(IR_PIN2, HIGH); digitalWrite(IR_PIN3, HIGH); #else TCCR2A |= _BV(COM2B1); #endif delayMicroseconds(HIGH_DURATION); #ifndef MODULATED digitalWrite(IR_PIN, LOW); digitalWrite(IR_PIN2, LOW); digitalWrite(IR_PIN3, LOW); #else TCCR2A &= ~_BV(COM2B1); #endif } void sendOne() { delayMicroseconds(ONE_LOW_DURATION); #ifndef MODULATED digitalWrite(IR_PIN, HIGH); digitalWrite(IR_PIN2, HIGH); digitalWrite(IR_PIN3, HIGH); #else TCCR2A |= _BV(COM2B1); #endif delayMicroseconds(HIGH_DURATION); #ifndef MODULATED digitalWrite(IR_PIN, LOW); digitalWrite(IR_PIN2, LOW); digitalWrite(IR_PIN3, LOW); #else TCCR2A &= ~_BV(COM2B1); #endif } void sendCommand(int throttle, int leftRight, int forwardBackward) { byte b; sendHeader(); for (int i = 7; i >=0; i--) { b = ((ROTATION_STATIONARY + leftRight) & (1 << i)) >> i; if (b > 0) sendOne(); else sendZero(); } for (int i = 7; i >=0; i--) { b = ((63 + forwardBackward) & (1 << i)) >> i; if (b > 0) sendOne(); else sendZero(); } for (int i = 7; i >=0; i--) { b = (throttle & (1 << i)) >> i; if (b > 0) sendOne(); else sendZero(); } for (int i = 7; i >=0; i--) { b = (CAL_BYTE & (1 << i)) >> i; if (b > 0) sendOne(); else sendZero(); } } void setup() { pinMode(IR_PIN, OUTPUT); digitalWrite(IR_PIN, LOW); pinMode(IR_PIN2, OUTPUT); digitalWrite(IR_PIN2, LOW); pinMode(IR_PIN3, OUTPUT); digitalWrite(IR_PIN3, LOW); //setup interrupt interval: 180ms Timer1.initialize(DURATION); Timer1.attachInterrupt(timerISR); //setup PWM: f=38Khz PWM=0.5 byte v = 8000 / 38; TCCR2A = _BV(WGM20); TCCR2B = _BV(WGM22) | _BV(CS20); OCR2A = v; OCR2B = v / 2; } void loop() { } void timerISR() { //read control values from potentiometers Throttle = analogRead(0); LeftRight = analogRead(1); FwdBack = analogRead(2); Throttle = 100;//Throttle / 4; //convert to 0 to 255 LeftRight = 0;//LeftRight / 8 - 64; //convert to -64 to 63 FwdBack = 0;//FwdBack / 4 - 128; //convert to -128 to 127 sendCommand(Throttle, LeftRight, FwdBack); } ===== Code to get Ultrasonic readings ===== #include byte clockPin = 4; byte buf[9];//Buffer to store the received valeus byte addr = 0x02;//address 0x02 in a 8-bit context - 0x01 in a 7-bit context byte distance; void setup() { i2c_init();//I2C frequency = 11494,253Hz Serial.begin(115200); printUltrasonicCommand(0x00);//Read Version printUltrasonicCommand(0x08);//Read Product ID printUltrasonicCommand(0x10);//Read Sensor Type printUltrasonicCommand(0x14);//Read Measurement Units } void loop() { // printUltrasonicCommand(0x42);//Read Measurement Byte 0 distance = readDistance(); if(distance == 0xFF) Serial.println("Error Reading Distance"); else Serial.println(distance, DEC); } byte readDistance() { delay(100);//There has to be a delay between commands byte cmd = 0x42;//Read Measurement Byte 0 pinMode(clockPin, INPUT);//Needed for writing to work digitalWrite(clockPin, HIGH); if(i2c_start(addr+I2C_WRITE))//Check if there is an error { Serial.println("ERROR i2c_start"); i2c_stop(); return 0xFF; } if(i2c_write(cmd))//Check if there is an error { Serial.println("ERROR i2c_write"); i2c_stop(); return 0xFF; } i2c_stop(); delayMicroseconds(60);//Needed for receiving to work pinMode(clockPin, OUTPUT); digitalWrite(clockPin, LOW); delayMicroseconds(34); pinMode(clockPin, INPUT); digitalWrite(clockPin, HIGH); delayMicroseconds(60); if(i2c_rep_start(addr+I2C_READ))//Check if there is an error { Serial.println("ERROR i2c_rep_start"); i2c_stop(); return 0xFF; } for(int i = 0; i < 8; i++) buf[i] = i2c_readAck(); buf[8] = i2c_readNak(); i2c_stop(); return buf[0]; } void printUltrasonicCommand(byte cmd) { delay(100);//There has to be a delay between commands pinMode(clockPin, INPUT);//Needed for writing to work digitalWrite(clockPin, HIGH); if(i2c_start(addr+I2C_WRITE))//Check if there is an error { Serial.println("ERROR i2c_start"); i2c_stop(); return; } if(i2c_write(cmd))//Check if there is an error { Serial.println("ERROR i2c_write"); i2c_stop(); return; } i2c_stop(); delayMicroseconds(60);//Needed for receiving to work pinMode(clockPin, OUTPUT); digitalWrite(clockPin, LOW); delayMicroseconds(34); pinMode(clockPin, INPUT); digitalWrite(clockPin, HIGH); delayMicroseconds(60); if(i2c_rep_start(addr+I2C_READ))//Check if there is an error { Serial.println("ERROR i2c_rep_start"); i2c_stop(); return; } for(int i = 0; i < 8; i++) buf[i] = i2c_readAck(); buf[8] = i2c_readNak(); i2c_stop(); if(cmd == 0x00 || cmd == 0x08 || cmd == 0x10 || cmd == 0x14) { for(int i = 0; i < 9; i++) { if(buf[i] != 0xFF && buf[i] != 0x00) Serial.print(buf[i]); else break; } } else Serial.print(buf[0], DEC); Serial.println(""); } /* ' Wires on NXT jack plug. ' Wire colours may vary. Pin 1 is always end nearest latch. ' 1 White +9V ' 2 Black GND ' 3 Red GND ' 4 Green +5V ' 5 Yellow SCL - also connect clockpin to give a extra low impuls ' 6 Blue SDA ' Do not use i2c pullup resistor - already provided within sensor. */ ===== Final Code ===== #include //comment this out to see the demodulated waveform //it is useful for debugging purpose. #define MODULATED 1 //Pins const int IR_PIN = 3; //Infrared LED pin const int vIn = 8; //Green Wire of GP2D02 const int vOut = 9; //Yellow Wire of GP2D02 //For signal generation. Lengths are in microseconds. const int HEADER_DURATION = 2000; //Length of header pulse const int HIGH_DURATION = 380; //Length of high part of 0/1-pulse const int ZERO_LOW_DURATION = 220; //Length of low part of 0-pulse const int ONE_LOW_DURATION = 600; //Length of low part of 1-pulse const byte ROTATION_STATIONARY = 60; // Trim const byte CAL_BYTE = 52; //Trailing pulse signature //For fitness calculation int heightCM = 12; //Input the height you want the program to attempt to reach int heightIRvalue = 447.54*pow(heightCM,-0.407); // Conver CM to the scale that the GP2D02 outputs at int bestFitness = 1000; // starting best fitness is far from zero int currentFitness = 1000; // starting fitness is far from zero int runNum = 0; //Tracks number of runs int currentIRValue = 0; //Store GP2D02 IRValue int minIR = 0; //Minimum position IR Value int maxIR = 0; //Maximum position IR Value int lastHighThrottle = 255; // Starts last fit high throttle at max range int lastLowThrottle = 0; // Starts last low high throttle at min range int lastThrottle = 0; // The value of the throttle on the last run //For timed loop of one run int starttime = 0; int endtime = 0; //For intial SYMA 107 signal parameters int Throttle = 0; int LeftRight = 0;//-64 to 63 int FwdBack = 0;//-128 to 127 //Initialize the IR sensor GP2D02 sensor(vIn,vOut); void sendHeader() //Sends the header pulse that singals the begining of a command { #ifndef MODULATED digitalWrite(IR_PIN, HIGH); #else TCCR2A |= _BV(COM2B1); #endif delayMicroseconds(HEADER_DURATION); #ifndef MODULATED digitalWrite(IR_PIN, LOW); #else TCCR2A &= ~_BV(COM2B1); #endif delayMicroseconds(HEADER_DURATION); #ifndef MODULATED digitalWrite(IR_PIN, HIGH); #else TCCR2A |= _BV(COM2B1); #endif delayMicroseconds(HIGH_DURATION); #ifndef MODULATED digitalWrite(IR_PIN, LOW); #else TCCR2A &= ~_BV(COM2B1); #endif } void sendZero() //Sends one 0 pulse { delayMicroseconds(ZERO_LOW_DURATION); #ifndef MODULATED digitalWrite(IR_PIN, HIGH); #else TCCR2A |= _BV(COM2B1); #endif delayMicroseconds(HIGH_DURATION); #ifndef MODULATED digitalWrite(IR_PIN, LOW); #else TCCR2A &= ~_BV(COM2B1); #endif } void sendOne() //Sends one 1 pulse { delayMicroseconds(ONE_LOW_DURATION); #ifndef MODULATED digitalWrite(IR_PIN, HIGH); #else TCCR2A |= _BV(COM2B1); #endif delayMicroseconds(HIGH_DURATION); #ifndef MODULATED digitalWrite(IR_PIN, LOW); #else TCCR2A &= ~_BV(COM2B1); #endif } void sendCommand(int throttle, int leftRight, int forwardBackward) { //Converts SYMA Parameters to a signal //For loops convert decimal numbers to binary numbers //Sends a pulse for each 0 or 1. byte b; sendHeader(); for (int i = 7; i >=0; i--) { // Yaw part of signal b = ((ROTATION_STATIONARY + leftRight) & (1 << i)) >> i; if (b > 0) sendOne(); else sendZero(); } for (int i = 7; i >=0; i--) { //Pitch part of signal b = ((63 + forwardBackward) & (1 << i)) >> i; if (b > 0) sendOne(); else sendZero(); } for (int i = 7; i >=0; i--) { //Throttle part of signal b = (throttle & (1 << i)) >> i; if (b > 0) sendOne(); else sendZero(); } for (int i = 7; i >=0; i--) { //Trailing Pulses b = (CAL_BYTE & (1 << i)) >> i; if (b > 0) sendOne(); else sendZero(); } } void setup() { //Initializes the program Serial.begin(9600); //Baud rate for command line pinMode(IR_PIN, OUTPUT); //Initializes the LED pin digitalWrite(IR_PIN, LOW); //setup PWM: f=38Khz PWM=0.5 byte v = 8000 / 38; TCCR2A = _BV(WGM20); TCCR2B = _BV(WGM22) | _BV(CS20); OCR2A = v; OCR2B = v / 2; minIR = sensor.getRawRange(); //get lowest point IR reading maxIR = 3000000*pow(minIR,-2.409)+11; //Convert to centimeters and add range of height of boom in cm maxIR = 447.54*pow(maxIR,-0.407); //Convert to scaled IR value Serial.println("Program Start"); Serial.print("Height to reach: "); Serial.println(heightIRvalue); } void loop() //main program loop { randomSeed(millis()); runNum = runNum + 1; if(runNum>1){ //Runs after first Serial.println("runNum>1"); if(bestFitness>5){ //if last fitness was high then new random is a smaller number Throttle = random(lastThrottle,lastHighThrottle);//0 to 255 lastLowThrottle = lastThrottle; Serial.println("bF>5"); } else if(bestFitness<-5){ //if last fitness was low then new random is larger number Throttle = random(lastLowThrottle,lastThrottle); lastHighThrottle = lastThrottle; Serial.println("bF>5"); } else{ // 0 is the best fitness, this is the final part of the program Serial.println("\nFinal Values"); Serial.print("Throttle: "); Serial.println(lastThrottle); Serial.print("Number of Runs: "); Serial.println(runNum); while(1){ sendCommand(lastThrottle, LeftRight, FwdBack); //generates IR signal //end of program //hangs indefinately } } } else{ //Initial Run Serial.println("runNum1"); Throttle = random(255); } Serial.print("\nNumber of Runs: "); Serial.println(runNum); Serial.print("Throttle: "); Serial.println(Throttle); lastThrottle = Throttle; starttime = millis(); endtime = starttime; // do this loop for up to 5000mS while ((endtime - starttime) <=5000) { //Runs take place over a period of 5 seconds sendCommand(Throttle, LeftRight, FwdBack); //generates IR signal endtime = millis(); currentIRValue = sensor.getRawRange(); currentFitness = currentIRValue-heightIRvalue; } if(abs(currentFitness) ===== Libraries ===== * [[http://code.google.com/p/arduino-timerone/downloads/list|TimerOne.h]] * [[https://github.com/jtrollinson/ArduinoGP2D02|GP2D02.h]]