//Daniel Elias Bermudez(deb48) //Rebecca Slovak (ras94) //Matt Meister (mrm58) #include #include #include #include #include #define NeuronNum 8 //eight neurons #define IndividualNum 10 //ten individuals in each set #define SensorNum 1 #define limit 150 //potentiometer value at the limit angle #define goal 95 //potentiometer value at the goal angle #define floor 80 //potentiometer value #define t1 2 //task timers #define t2 50 #define t3 10 #define t4 28000 #define t5 30000 //function declarations void task1(void); void task2(void); void task3(void); void task4(void); void task5(void); void initialize(void); //variable declarations unsigned long time1, time2, time3, time4, time5; //task timers unsigned char neuronconn[IndividualNum][NeuronNum]; //connections between the different neurons(1 for a connection, 0 for no connection) unsigned char sensorconn[IndividualNum]; //connections between the 1 sensor and the neurons (1 for a connection, 0 for no connection) unsigned char signs[IndividualNum]; //holds the signs for the neurons(1 is a positive connection, 0 is a negative connection) unsigned char threshold[NeuronNum]; //holds the thresholds for the neurons signed int memb[NeuronNum]; //membrane potential for the networks unsigned int minimum; //minimum membrane potential unsigned char neuronoutput; //output of the neurons of the current individual (spike pattern) unsigned char sensoroutput; //output for the sensor (spike pattern) unsigned char individual; //number of the current individual unsigned char leakage; //leakage value to subtract from membrane potential int randint; //variable for a random number int fitness[IndividualNum]; //fitnesses for each individual int newfitness; //calculated fitness of current individual int resetvalue; //value to reset OCR0 to int sideMotorSpeed; //speed of side motor unsigned char worst; //index of the worst individual (worst fitness) unsigned char randn; //random number used to make mutations unsigned char oldsigns; //temp variables -- copies before you overwrite them unsigned char oldneuronconn[NeuronNum]; unsigned int oldsensorconn[NeuronNum]; unsigned int oldthreshold; unsigned char evolveflag; unsigned int Ain; // Current A to D converter input unsigned char crash; //indicates whether the helicopter has gone beyond limit int voltage; //Current ADC input (voltage = Ain) int bestfitness; //fitness of the best individual signed char motorup; //neuron variable for speeding up the motor signed char motordown; //neuron variable for slowing up the motor signed char tmotorup; //total spike counters, only used for debugging signed char tmotordown; eeprom int eebestfitness[400]; //big array that stores past best fitness values eeprom int eebestfitnesscounter; //used to access array eeprom unsigned char eeneuronconn[IndividualNum][NeuronNum]; //values stored to eeprom eeprom unsigned char eesensorconn[IndividualNum]; eeprom unsigned char eesigns[IndividualNum]; eeprom unsigned int eethreshold[NeuronNum]; eeprom unsigned char eememflag; //flag telling not to initialize from scratch eeprom float eefitness[NeuronNum]; unsigned int i, j, k, a, d, b, z, e, x, y, w, q; //for loop counters //////////////Timer 0 Overflow Interrupt//////////////////////////////////////// interrupt[TIM0_OVF] void timer0_ovfl(void) { if (time1>0) --time1; if (time2>0) --time2; if (time3>0) --time3; if (time4>0) --time4; if (time5>0) --time5; }//end of overflow interrupt //////////////////////////////////////////////////////////////////////////////// ////////////////////////TASK 1////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// void task1(void) { time1 = t1; motorup = 0; //set spike counters to 0 motordown = 0; if (evolveflag == 1) //just evolved { memb[6] = threshold[individual] + 20; //add nonzero value to outputs to start the system memb[7] = threshold[individual] + 20; evolveflag = 0; tmotorup = 0; tmotordown = 0; //total spike counters set to 0 } for (a=0; a>a)&0x01!=0) { //calculate the contribution of the sensor to membrane potential memb[a] = (memb[a] + (((sensoroutput & sensorconn[individual]) & 0b10000000)>>7) + (((sensoroutput & sensorconn[individual]) & 0b01000000)>>6) + (((sensoroutput & sensorconn[individual]) & 0b00100000)>>5) + (((sensoroutput & sensorconn[individual]) & 0b00010000)>>4) + (((sensoroutput & sensorconn[individual]) & 0b00001000)>>3) + (((sensoroutput & sensorconn[individual]) & 0b00000100)>>2) + (((sensoroutput & sensorconn[individual]) & 0b00000010)>>1) + (((sensoroutput & sensorconn[individual]) & 0b00000001))); //calculate the contribution of the neurons to membrane potential memb[a] = memb[a] + (((neuronoutput & neuronconn[individual][a])&0b10000000)>>7) + (((neuronoutput & neuronconn[individual][a])&0b01000000)>>6) + (((neuronoutput & neuronconn[individual][a])&0b00100000)>>5) + (((neuronoutput & neuronconn[individual][a])&0b00010000)>>4) + (((neuronoutput & neuronconn[individual][a])&0b00001000)>>3) + (((neuronoutput & neuronconn[individual][a])&0b00000100)>>2) + (((neuronoutput & neuronconn[individual][a])&0b00000010)>>1) + ((neuronoutput & neuronconn[individual][a])&0b000000001); } if (memb[a] < minimum) memb[a] = minimum; //if membrane potential goes below 0, set back to 0 } ////////SPIKE GENERATION//////// for(d=0; d= 0) && (randint < 6554)) //if random number is in certain range, spike if past threshold { // (or threshhold-1, threshold-2, threshold+1, threshold+2...) if (memb[d]>= (threshold[individual] -2)) //adds noise to thresholds to prevent locked oscillation { neuronoutput = (neuronoutput | (1<= 6554) && (randint < 13106)) { if (memb[d]>= (threshold[individual] -1)) { neuronoutput = (neuronoutput | (1<= 13106) && (randint < 19959)) { if (memb[d]>= (threshold[individual])) { neuronoutput = (neuronoutput | (1<= 19959) && (randint < 26212)) { if (memb[d]>= (threshold[individual] +1)) { neuronoutput = (neuronoutput | (1<= 26212) && (randint < 32767)) { if (memb[d]>= (threshold[individual] +2)) { neuronoutput = (neuronoutput | (1<= minimum) memb[b] = memb[b] - leakage; else memb[b] = minimum; } } //end of task 1 //////////////////////////////////////////////////////////////////////////////// ////////////////////////TASK 2////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// void task2(void) //updates the speed of the motor { time2 = t2; if ((motorup>0) && (OCR0 < 163)) { OCR0++; //printf("\r\nMOTORUP!\r\n");//debugging motorup = 0; motordown = 0; } if ((motordown>0) && (OCR0 >= 85)) { OCR0 = OCR0 - 1 ; //printf("\r\nMOTORDOWN!\r\n");//debugging motorup=0; motordown=0; } }//end of task 2 //////////////////////////////////////////////////////////////////////////////// ////////////////////////TASK 3////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// void task3(void) { time3 = t3; crash = 0; ADCSR.6=1; //start A to D conversion while (ADCSR.6 == 1){} //wait until conversion is ready Ain = ADCH; //get the sample voltage = Ain; //set sensor output to send pattern of spikes into the network if (voltage > limit) //range above limit { crash = 1; sensoroutput = ((sensoroutput | 0b00000111)& 0b01111111); //OCR2 = 0; //for side motor } else if (voltage > (goal + 5)) //range just over goal { sensoroutput = (sensoroutput | 0b010001011); //OCR2 = (sideMotorSpeed / 2); //for side motor } else if ((voltage > (goal - 5)) && (voltage < (goal + 5))) //goal range { sensoroutput = (sensoroutput | 0b00000000); if (newfitness < 65536) //much higher number than fitness could ever reach... { newfitness = newfitness + 2; //raise fitness printf("\r\nfitness = %d",newfitness); //print out changing fitness if connected to hyperterm } //if(newfitness >= 250) //side motor control //{ //// OCR2 = sideMotorSpeed; //} //else //{ // OCR2 = 0; //} } else if (voltage < (goal - 5) && (voltage > floor)) //range below goal range, above floor { sensoroutput = (sensoroutput | 0b10110000); if (newfitness < 65536) { newfitness = newfitness + 1; //raise fitness printf("\r\nfitness = %d",newfitness); //print out changing fitness if connected to hyperterm } //if(newfitness >= 250) //side motor control //{ // OCR2 = (sideMotorSpeed / 2); //} //else //{ // OCR2 = 0; //} } else if (voltage <= floor) //lowest range { sensoroutput = ((sensoroutput | 0b10111000) & 0b10111111); //OCR2 = 0; //for side motor } }//end of task 3 //////////////////////////////////////////////////////////////////////////////// ////////////////////////TASK 4////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// void task4(void) { time4 = t4; ////////Fitness Check//////// worst = 0; //set the index to first one and loop through to find worst for(z = 1; z < IndividualNum; z++) //find worst individual { if(fitness[z] < fitness[worst]) { worst = z; } } if(newfitness >= fitness[worst] && newfitness>= fitness[individual]) //keep the new one { fitness[individual] = newfitness; } else //don't keep the new one, set old variables back { signs[individual] = oldsigns; for(d = 0; d < NeuronNum; d++) { neuronconn[individual][d] = oldneuronconn[d]; sensorconn[individual] = oldsensorconn[d]; } threshold[individual] = oldthreshold; } ////////Mutation//////// individual = (rand() % IndividualNum); //pick random individual and mutate printf("individual: %d\r\n",individual); //if connected to hyperterm, print when switching to new individual oldsigns = signs[individual]; // Save old versions for(e = 0; e < NeuronNum; e++) { oldneuronconn[e] = neuronconn[individual][e]; oldsensorconn[e] = sensorconn[individual]; } oldthreshold = threshold[individual]; // Mutate signs[individual] = (signs[individual]^(1<<(rand() % NeuronNum)));//mutating sign of one neuron randn = (rand() % NeuronNum); neuronconn[individual][randn] = (neuronconn[individual][randn]^(1<<(rand() % NeuronNum))); //mutate neuron connections sensorconn[individual] = (sensorconn[individual]^(1<<(rand() % NeuronNum))); //mutate sensor connections threshold[individual] = (threshold[individual]^(1<<(rand() % 4))); //mutate thresholds if(threshold[individual] > 6 || threshold[individual] < 2) threshold[individual] = oldthreshold; evolveflag = 1; if(newfitness <= 1000) //if last individual did really well, stay at same motor speed, otherwise reset to slow { OCR0 = 85;} newfitness = 0; //reset fitness variable memb[individual] = 0; //reset membrane potential }//end task 4 //////////////////////////////////////////////////////////////////////////////// ////////////////////////TASK 5////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// void task5(void) { printf("\r\nTask 5\r\n"); //when connected to hyperterm, this lets user know data is being written to eeprom time5 = t5; bestfitness = 0; //find best fitness for (w = 0; w bestfitness){ bestfitness = fitness[w]; } } eebestfitness[eebestfitnesscounter] = bestfitness; //stores best fitnesses in an array in eeprom if (eebestfitnesscounter < 400) eebestfitnesscounter++; for(x = 0; x < IndividualNum; x++) //store all other important data to eeprom { eesigns[x] = signs[x]; eesensorconn[x] = sensorconn[x]; for(y = 0; y < NeuronNum; y++) { eeneuronconn[x][y] = neuronconn[x][y]; } eefitness[x] = fitness[x]; eethreshold[x] = threshold[x]; } eememflag = 1; //flag that says don't do complete initialize next time -- use from mem }//end of task 5 //////////////////////////////////////////////////////////////////////////////// ////////////////////////MAIN//////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// void main(void) { initialize(); if(eebestfitnesscounter != 0) //print fitness log of previous run to hyperterm { for (q=0; q<=eebestfitnesscounter; q++) { printf("iteration # %d - best fitness: %d \r\n", q,eebestfitness[q]); } } while(1) //task scheduler { if (time1==0) task1(); if (time2==0) task2(); if (time3==0) task3(); if (time4==0) task4(); if (time5==0) task5(); } }//end of main //////////////////////////////////////////////////////////////////////////////// ////////////////////////INITIALIZE////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// void initialize(void) { //set up the ports DDRC = 0xff; PORTC = 0x00; DDRB = 0xff; PORTB = 0x00; DDRD = 0xff; //for side motor PORTD = 0x00; resetvalue = 85; //OCR0 start value OCR0 = resetvalue; TIMSK = 1; //set up timer 0 TCCR0 = 0b01101011; //set prescaler to 64, clear on compare match, PWM turned on sideMotorSpeed = 100; //side motor //OCR2 = 0; //TCCR2 = 0b01101011; //set prescaler to 64, clear on compare match, PWM turned on UCSRB = 0x18 ; //HYPERTERM - setup serial setup for debugging using printf, etc. UBRRL = 103 ; printf("\r\nI'm learning...\r\n"); //starting the program time1 = t1; //task timers time2 = t2; time3 = t3; time4 = t4; time5 = t5; //generate the starting network neuronoutput = 0; sensoroutput = 0; individual = 0; //always just start on individual 0 bestfitness = 0; if (eememflag == 0) //first time running, initialize everything { eebestfitnesscounter = 0; //set to 0 on original run, but otherwise count up for (i=0; i 16383) {signs[i] = signs[i] | 0b00000001;} //inserts a 1 if(i!=7){signs[i]<<1;} for(j=0; j 16383) {neuronconn[i][j] = neuronconn[i][j] | 0b00000001;} if (k!=NeuronNum) {neuronconn[i][j] = neuronconn[i][j] << 1;} } } sensorconn[i] = 0b11111111; //sensor starts connected to everything } } else //get the values from the eeprom if program resets { for (i=0; i