Marc Bax
/
EtonBreadboard1
Firmware for Eton breadboard
Revision 0:2017f5924a22, committed 2011-03-23
- Comitter:
- marcbax
- Date:
- Wed Mar 23 09:39:57 2011 +0000
- Commit message:
- v0.80, date 23/3/2011
Changed in this revision
diff -r 000000000000 -r 2017f5924a22 Servo.lib --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Servo.lib Wed Mar 23 09:39:57 2011 +0000 @@ -0,0 +1,1 @@ +http://mbed.org/users/simon/code/Servo/#36b69a7ced07
diff -r 000000000000 -r 2017f5924a22 main.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/main.cpp Wed Mar 23 09:39:57 2011 +0000 @@ -0,0 +1,499 @@ +//Firmware to drive Eton bee trainer breadboard +char* fwversion = "0.80"; //For published versions use format "n.nn" + //For development versions add "D" to end of string +//This version published on 23/03/2011 + +//Include libraries +#include "mbed.h" +#include "Servo.h" //need this library to control servos + +//Pin assignments and external functions +DigitalOut led1(LED1), led2(LED2), led3(LED3), led4(LED4); //for debugging purposes only +DigitalOut buzzer(p5); //pin high means buzzer on +DigitalOut airswitcher(p7); //pin high shorts coax for air switcher valve +Serial display(p9,p10); //serial display controller by ByVAC BV4618 controller +AnalogOut irLED(p18); //only one analog out controls both IR LEDS in parallel +AnalogIn ptor1(p19), ptor2(p20); //analog input for beeholder phototransistors +Servo arm1(p21), elbow1(p22); //servos for station 1 robot arm +Servo arm2(p23), elbow2(p24); //servos for station 2 robot arm +I2C beeholder(p28,p27); //set up I2C communication to read beeholder serial no +DigitalOut bhsel1(p29), bhsel2(p30); //select lines for station 1 and station 2 - pull low to select holder +DigitalIn upsw(p13), risw(p14), dnsw(p15), lesw(p16), oksw(p17); //footswitch connected parallel to OK switch +LocalFileSystem local("local"); //allow access to the mbed "thumbdrive" as a file system +FILE *logfile = fopen("/local/etonlog.csv","w"); //creates new file etonlog.csv and set for writing. Overwrites existing file! + +//Definition of global constants + //station 1 (left) robot arm positions + float arm1basepos = 0.4; + float elbow1basepos = 0.07; + float arm1dippos = 0.2; + float elbow1dippos = 0.6; + float arm1ticklepos = 0.68; + float elbow1ticklepos = 0.07; + float arm1feedpos = 0.73; + float elbow1feedpos = 0.4; + + //station 2 (right) robot arm positions + float arm2basepos = 0.4; + float elbow2basepos = 0.07; + float arm2dippos = 0.2; + float elbow2dippos = 0.07; + float arm2ticklepos = 0.2; + float elbow2ticklepos = 0.07; + float arm2feedpos = 0.2; + float elbow2feedpos = 0.07; + + //robot arm hold times all times are in seconds + float diptime = 1; //time that brush stays down dipped in sugar water + float tickletimeout = 1.5; //maximum time to tickle if no PER is detected + float feedtime = 3; //feeding time + + //PER detection parameters + float calsetval = 1.4; //voltage to which phototransistor output will be calibrated + float PERsetval = 2.1; //phototransistor output needs to be above this voltage for PER + float PERtime = 0.2; //phototransistor output needs to stay high this long in seconds + + //I2C address + int addr = 0xA2; //address is actually 0x51, but mbed expects left-shifted address + +//Definition of global variables + +struct holderrecord { //used to hold data on beeholder + int serialno; //beeholder serial number 0-9999 + float calvalue; //IR-LED calibration value + char cycleno; //number of cycles gone through in this session + char reslastcycle; //result of last cycle, 1 for PER + char ticklenextcycle; //whether tickling was done for last cycle + time_t tstamp; //timestamp when last cycle was run +}; + +holderrecord currentholder; //struct record for the current beeholder +holderrecord sessionrecord[30]; //sessionrecord contains holderrecords for up to 30 beeholders + +int numbeeholders; //number of beeholders used in current session +int station; //which station is used in this session + + + +//Function declarations + +//Short beep +void beeponce() { + buzzer = 1; + wait(0.1); + buzzer = 0; +} + +//beep beep beep +void multibeeps(int number, float interval) { + for(int i=0;i<number;i++){ + beeponce(); + wait(interval); + } +} + +//Clears and homes the display +void cleardisplay() { + display.printf("\e[2J\e[H"); +} + +//Returns both robot arms to base position +void armstobase() { + elbow1 = elbow1basepos; + elbow2 = elbow2basepos; + wait(0.5); //need this delay to avoid snagging brush on IR LED + arm1 = arm1basepos; + arm2 = arm2basepos; +} + +//Initialises sessionrecords +void sessionrecordinit() { + for (int i=0; i<30; i++) { //set base values for all possible beeholders + sessionrecord[i].serialno = 0; //set serialno to 0 so we can detect a unresponsive holder + sessionrecord[i].calvalue = 0; + sessionrecord[i].cycleno = 0; + sessionrecord[i].reslastcycle = 0; + sessionrecord[i].ticklenextcycle = 1; //default is to tickle on each cycle + } +} + +//Initialisation on power-on +void initialise() { + + //Set pins to a defined state + led1 = led2 = led3 = led4 =0; //internal LEDs only used for debugging purposes + buzzer = 0; //buzzer off + airswitcher = 0; //relay contacts open, clean air position + bhsel1 = bhsel2 = 1; //I2C select lines high to deselect both beeholders + upsw.mode(PullUp); //set pull-up on all frontpanel switches + risw.mode(PullUp); + dnsw.mode(PullUp); + lesw.mode(PullUp); + oksw.mode(PullUp); + + //Set robot arms to base positions + armstobase(); + + //initialise the display + display.baud(19200); //set display baud rate to 19200 + display.putc(0x0d); //send CR to display - this needs to be first character sent after power-up + wait(0.5); //wait for display to adjust to serial baud rate + display.printf("\e[4L\e[20c"); //set display to 4 lines of 20 characters + cleardisplay(); //clear screen and home cursor + + //display splash screen with time + display.printf("Eton trainer v%s\r", fwversion); //show firmware release version + time_t seconds = time(NULL); //creates timestamp + char bufferd[20], buffert[20]; + strftime(bufferd, 20, "%d/%m/%Y", localtime(&seconds)); //formats date part of timestamp + display.printf("Date: %s\r", bufferd); //displays date + strftime(buffert, 20, "%X", localtime(&seconds)); //formats time part of timestamp + display.printf("Time: %s\r", buffert); //displays time + wait(5); //how long splash screen will be displayed + cleardisplay(); //clear screen and home cursor + + //initialise sessionrecord + sessionrecordinit(); + + //enter info in logfile.csv + fprintf(logfile, "%s\r", bufferd); //writes date, time and firmware version + fprintf(logfile, "%s\r", buffert); + fprintf(logfile, "v%s\r", fwversion); + + multibeeps(3, 0.4); //three beeps to signal initialisation ready +} + +//Converts the last 4 digits in the serial number string into a integer 0-9999 +int serialstring2int(char bser[8]) { + int tempserial = 0; + tempserial = tempserial + (bser[4]-0x30)*1000; //5th digit is thousands + tempserial = tempserial + (bser[5]-0x30)*100; //6th digit is hundreds + tempserial = tempserial + (bser[6]-0x30)*10; //7th digit is tens + tempserial = tempserial + (bser[7]-0x30); //8th digit is units + return tempserial; +} + +//beeholder resets on rising edge of select line +void resetbeeholder() { //need this as mounting beeholder causes undefined start of beeholder firmware + bhsel1 = bhsel2 = 0; + wait(0.1); + bhsel1 = bhsel2 = 1; + wait(0.3); +} + +//Reads beeholder serial number from station 1 or 2 +int getserialno(int station) { + char bser[8]; //define 8-byte serial number string to read + resetbeeholder(); //does not work without this!! + for (int i=0;i<8;i++) bser[i]=0x30; + if (station==1) bhsel1=0; //pull select line station 1 low + if (station==2) bhsel2=0; //pull select line station 2 low + wait(0.2); + beeholder.stop(); //I2C stop condition + wait(0.2); //delay for beeholder to respond + beeholder.write(addr,0x0,1); //initial write before read + beeholder.read(addr,bser,8); //read 8 byte serial number + bhsel1 = bhsel2= 1; //pull both select lines high + int serialno = serialstring2int(bser); //translate serial number string to integer + return serialno; +} + +//Returns 1 if a PER is detected on this beeholder within timeout seconds +int detectPER(int station, float timeout) { + Timer ttotal, tper; + ttotal.start(); //start timers for time-out and PER-detect + ttotal.reset(); + tper.start(); + tper.reset(); + if (station == 1) { + while ((ttotal.read() < timeout) && (tper.read() < PERtime)) { //loop until timeout or PER detected + wait_ms(10); + if (ptor1 * 3.3 < PERsetval) tper.reset(); //if phototransistor voltage below treshold keep PER timer in reset + //if above treshold let timer run until it reaches PERtime + } + } + if (station == 2) { + while ((ttotal.read() < timeout) && (tper.read() < PERtime)) { + if (ptor2 * 3.3 < PERsetval) tper.reset(); + } + } + ttotal.stop(); + tper.stop(); + return (tper.read() >= PERtime); //if the loop exit condition was a PER, return a TRUE value +} + +//Checks if bee shows PER when stimulated with odour but without feeding +int checktrained(int station) { + airswitcher = 1; + int responded = detectPER(station, 6); //PER needs to be detected within 6 seconds + airswitcher = 0; + return responded; +} + +//Function performs beeholder/IR-led calibration +float calibrate(int station, int runs) { + float tempcal; + tempcal=0.5; //start calibration at 50% voltage + irLED=tempcal; + float calstep; //start calstep at 25% voltage + calstep = tempcal/2; + for (int i=0; i<10; i++) { //does a "10-bit binary search" for the correct voltage to get a good response + irLED = tempcal; + wait(0.1); //important to allow AD converter to settle + if (ptor1 < calsetval/3.3) { //check phototransistor voltage against desired value + tempcal = tempcal - calstep; //if phototransistor voltage is too low then reduce brightness + } + else { + tempcal = tempcal + calstep; //if phototransistor voltage is too high then increase brightness + } + calstep = calstep/2; //on each loop of the for-cycle make smaller changes to IR LED voltage + } + float calib; + calib = tempcal; //set preliminary calibration to the value just measured + for (int j=1; j<runs; j++) { //run another j-1 runs, this corrects for antennae-movement as + tempcal=0.5; //we use the lowest calibration value from j runs + irLED=tempcal; //this is similar to what we do in the cassettes + calstep = tempcal/2; + for (int i=0;i<10;i++) { + irLED = tempcal; + wait(0.1); + if (ptor1 < calsetval/3.3) { + tempcal = tempcal - calstep; + } + else { + tempcal = tempcal + calstep; + } + calstep = calstep/2; + } + if (tempcal < calib) calib = tempcal; //use the lowest of j calibration values + } + return calib; +} + +//switches the IR LED on at the right brightness level for the beeholder +void IRledON(int i) { + irLED = sessionrecord[i].calvalue; + } + +//Performs a conditioning cycle. if tickle==0, no tickling takes place. Return==1 if a PER has been detected +int condcycle(int station, int tickle) { + int perseen; + perseen = 0; + //for station 1 + if (station == 1) { + //dip brush + arm1 = arm1dippos; + wait(0.5); + elbow1 = elbow1dippos; + wait (diptime); + elbow1 = elbow1basepos; + wait(0.3); + arm1 = arm1basepos; + //switch air to supply trace vapour + airswitcher = 1; //air contains target vapour + display.printf("Vapour ON"); + wait (0.5); + //tickle + if (tickle) { //if tickling, first tickle then wait for PER or timeout + elbow1 = elbow1ticklepos; + arm1 = arm1ticklepos; + perseen = detectPER(1, tickletimeout); //tickle until timeout or PER detected + } + //or not tickle + else { + perseen = detectPER(1, tickletimeout); //if not tickling, wait for PER or timeout then move to pre-feeding position + arm1 = arm1ticklepos - 0.05; //move to position between LED and holder + wait(0.3); //this is needed to avoid the brush snagging on the phototransistor + elbow1 = elbow1ticklepos; + } + //feeding only if you have tickled or a PER has been detected + if (tickle || perseen) { //only feed if a PER has been detector, or "tickle" is true + elbow1 = elbow1feedpos; + arm1 = arm1feedpos; + wait(feedtime); + arm1 = arm1ticklepos -0.05; + elbow1 = elbow1ticklepos; + } + //move back to base position + arm1 = arm1basepos; + elbow1 = elbow1basepos; + airswitcher = 0; //air valve to clean air + display.printf("\e[DFF\r"); //rewrite "ON" to "OFF" on display + } + //for station 2 + if (station == 2) { + //dip brush + arm2 = arm2dippos; + wait(0.5); + elbow2 = elbow2dippos; + wait (diptime); + elbow2 = elbow2basepos; + wait(0.3); + arm2 = arm2basepos; + //switch air to supply trace vapour + //airswitcher = 1; //no air switching for station 2 + wait (0.5); + //tickle + if (tickle) { //if tickling, first tickle then wait for PER or timeout + elbow2 = elbow2ticklepos; + arm2 = arm2ticklepos; + perseen = detectPER(2, tickletimeout); + } + else { + perseen = detectPER(2, tickletimeout); //if not tickling, wait for PER or timeout then move to pre-feeding position + arm2 = arm2ticklepos - 0.05; + wait(0.3); //this is needed to avoid the brush snagging on the phototransistor + elbow2 = elbow2ticklepos; + } + //feeding only if tickling takes place or a PER has been detected + if (tickle || perseen) { + elbow2 = elbow2feedpos; + arm2 = arm2feedpos; + wait(feedtime); + arm2 = arm2ticklepos -0.05; + elbow2 = elbow2ticklepos; + } + //move back to base position + arm2 = arm2basepos; + elbow2 = elbow2basepos; + } + return perseen; +} + +//User to input choice between station 1 and 2 for this session +int stationchoice() { + int station; + station = 1; + cleardisplay(); //clear screen and home cursor + display.printf(" Station selection "); + display.printf("Left=1 2=Right"); + while (lesw && risw) { //lesw and risw become false when pressed! + wait(0.02); + if (!lesw) station=1; //on LEFT select station 1 + if (!risw) station=2; //on RIGHT select station 2 + } + display.printf("\rStation %1u selected", station); + fprintf(logfile, "%3u, station selected\r", station); + return station; +} + +//Registers and calibrates all beeholders used in this session +int registerbeeholders() { + int i; + bool done; + char buffert[30]; + i = done = 0; + cleardisplay(); //clear screen and home cursor + fprintf(logfile, "calibration record:\r"); + fprintf(logfile, "i, serialno, LED V, time\r"); + while (i<30 && !done) { //register and calibrate a maximum of 30 beeholders + display.printf("calibrating %u\r",i+1); + sessionrecord[i].serialno = getserialno(station); //read serial number + if (sessionrecord[i].serialno != 0) { //check if serial number correctly read - if not it will be 0000 + sessionrecord[i].calvalue = calibrate(station, 5); //5 calibration cycles + sessionrecord[i].tstamp = time(NULL); //create timestamp NOW + strftime(buffert, 20, "%X", localtime(&sessionrecord[i].tstamp)); //formats time part of timestamp + cleardisplay(); + display.printf("SN %4u - cal %4.2fV\r", sessionrecord[i].serialno, sessionrecord[i].calvalue*3.3); + display.printf("OK for next\r"); + display.printf("DOWN for training"); + fprintf(logfile, "%4u,%6u,%6.2f, %s, calibrate\r", i, sessionrecord[i].serialno, sessionrecord[i].calvalue*3.3, buffert); + i++; + while (!done && oksw) { //loop until OK or DOWN are pressed + wait(0.02); + done = !dnsw; //DOWN exits registration cycle and moves to training + } + } + else { //retry when serialno can't be read (is 0000) + cleardisplay(); + display.printf("invalid serial no\r"); + display.printf("reseat beeholder\r"); + display.printf("press OK"); + while (oksw) wait(0.02); //loop until OK is pressed to start calibration loop again + } + cleardisplay(); + } + return i; //upon done condition, i== number of beeholders calibrated +} + +//gets holderrecord for the holder with a certain serial number +int getholderindex(int serialno) { + for (int i=0; i<numbeeholders; i++) { //reverse lookup of index for a certain serial number + if (sessionrecord[i].serialno == serialno) return i; + } + return 29; //if the record is not found, returns i==29 +} + +//all the elements making up a single training cycle with one beeholder +void trainingcycle() { + wait(0.2); + time_t tstamp = time(NULL); //create timestamp NOW + char buffert[30]; + strftime(buffert, 20, "%X", localtime(&tstamp)); //format timestamp to time string + int serialno = getserialno(station); //read serial number + int i = getholderindex(serialno); //get index i for serial number + IRledON(i); //switch IR LED on at correct brightness + sessionrecord[i].cycleno++; //increment cycle number for this beeholder + cleardisplay(); + display.printf("SN: %4u, cycle %u\r", serialno, sessionrecord[i].cycleno); + sessionrecord[i].reslastcycle = condcycle(station, sessionrecord[i].ticklenextcycle); //do a conditioning cycle + fprintf(logfile, "%s,",buffert); + fprintf(logfile, " %4u,",serialno); + fprintf(logfile, " %2u,", sessionrecord[i].cycleno); + if (sessionrecord[i].reslastcycle) { //log PER or TimeOut + fprintf(logfile, " PER,"); + } + else { + fprintf(logfile, " TO,"); + } + fprintf(logfile, " training\r"); + if (sessionrecord[i].reslastcycle) { + display.printf("PER detected\r"); + } + else { + display.printf("PER time-out\r"); + } + display.printf("mount holder + OK\r"); + display.printf("DOWN to finish"); +} + +//main program +int main() { + initialise(); + + //Choose which station this session will use + station = stationchoice (); + cleardisplay(); + + //Register and calibrate beeholders used in this session + display.printf("Now register holders\r"); + display.printf("seat first holder\rpress OK\r"); + while (oksw) wait(0.02); //loop so first beeholder can be mounted, then OK pressed + numbeeholders = registerbeeholders(); + display.printf("%2u holders entered\r", numbeeholders); + wait(3); + cleardisplay(); + + //Conduct training + display.printf("Start training cycle\r"); + display.printf("mount holder + OK\r"); + display.printf("DOWN to finish"); + fprintf(logfile, "Training started\r"); + fprintf(logfile, "time, serial, cycleno, result\r"); + wait(1); + InterruptIn oksw(p17); //redefine OK and footswitch as interrupts + oksw.mode(PullUp); + bool finishsession; + finishsession = 0; + oksw.fall(&trainingcycle); //call subroutine "trainingcycle" on OK/footswitch interrupt + while (!finishsession) { //loop while servicing interrupts + wait(0.02); + finishsession = !dnsw; //until DOWN button is pressed, which exits to program close + } + + //Close logfile + fprintf(logfile, "session closed"); + fclose(logfile); //close logfile for reading + cleardisplay(); + display.printf("Session finished\r\rdownload etonlog.csvand rename"); +}
diff -r 000000000000 -r 2017f5924a22 mbed.bld --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mbed.bld Wed Mar 23 09:39:57 2011 +0000 @@ -0,0 +1,1 @@ +http://mbed.org/users/mbed_official/code/mbed/builds/63bcd7ba4912