Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Revision 0:0993f4cf5312, committed 2011-07-25
- Comitter:
- marcbax
- Date:
- Mon Jul 25 11:52:02 2011 +0000
- Commit message:
- V0.70 as delivered on July 25th
Changed in this revision
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Servo.lib Mon Jul 25 11:52:02 2011 +0000 @@ -0,0 +1,1 @@ +http://mbed.org/users/simon/code/Servo/#36b69a7ced07
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/main.cpp Mon Jul 25 11:52:02 2011 +0000
@@ -0,0 +1,593 @@
+//Firmware to drive Sorbonne-2 bee training module
+char* fwversion = "0.70"; //For published versions use format "n.nn"
+ //For development versions add "D" to end of string
+//This version published on 25/07/2011
+
+#include "mbed.h"
+#include "Servo.h"
+
+DigitalOut led1(LED1), led2(LED2), led3(LED3), led4(LED4);
+DigitalOut lidclose(p5), lidlift(p6);
+DigitalOut clamp(p7), unclamp(p8);
+DigitalOut lockr(p12), unlockl(p13), lockl(p14), unlockr(p26);
+AnalogIn viclamp(p15);
+AnalogIn vswdetect(p16);
+AnalogIn adc4(p17);
+AnalogOut irLED(p18);
+AnalogIn vtemp(p19);
+AnalogIn ptor(p20);
+Servo arm(p21), elbow(p22);
+DigitalOut fan(p23);
+I2C beeholder(p9, p10);
+DigitalOut bhsel(p11);
+Serial acucomms(p28, p27);
+DigitalIn tmselect(p29);
+DigitalOut airswitcher(p25), spare1(p24);
+LocalFileSystem local("local"); //allow access to the mbed "thumbdrive" as a file system
+//FILE *calfile = fopen("/local/calfile.ini","w"); //file used to store bee holder calibration values
+FILE *logfile = fopen("/local/sorb2log.csv","w"); //creates new file sorb2log.csv and set for writing. Overwrites existing file!
+
+//Definition of global constants
+ //Training module PCB #2 robot arm positions
+ //Increase in arm position moves arm away from bee holder
+ //Increase in elbow position lowers tip
+ float armbasepos = 0.81;
+ float elbowbasepos = 0.6;
+ float armdippos = 0.81;
+ float elbowdippos = 0.84;
+ float armticklepos = 0.15;
+ float elbowticklepos = 0.63;
+ float armfeedpos = 0.08;
+ float elbowfeedpos = 0.77;
+
+ //robot arm hold and move times //all times are in seconds
+ float diptime = 1; //time that brush stays down dipped in sugar water
+ float tickletimeout = 3; //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
+
+ //Protocols
+ int addr = 0xA2; //I2C address is actually 0x51, but mbed expects left-shifted address
+ int I2Cfreq = 10000; //I2C bus frequency
+ int baudrate = 19200; //baudrate of serial connection to ACU
+
+//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[101]; //sessionrecord contains holderrecords for up to 100 beeholders
+
+int numbeeholders; //number of beeholders used in current session
+int serialnum;
+char comchar; //serial command character for module control
+float fanspeed;
+bool lockstatus, clampstatus, lidstatus; //are true when locked, clamped or closed
+char swstatus; //4-bit number to indicate status of 4 detect switches
+float swvalue; //ADC value for detect switch voltage
+
+//Function declarations
+
+//Initialises sessionrecords
+void sessionrecordinit() {
+ for (int i=0; i<101; 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
+ }
+}
+
+//Reads serial numbers and calibration values from calfile.ini
+void getcaldata() {
+
+}
+
+//Initialise at power-up or reset
+void init_tm() {
+ led1=led2=led3=0;
+ led4=1;
+ lidclose=lidlift=0;
+ clamp=unclamp=0;
+ lockr=unlockr=lockl=unlockl=0;
+ irLED=0;
+ bhsel=0;
+ airswitcher=0;
+ spare1=0;
+ fan=0;
+ acucomms.baud(baudrate);
+ beeholder.frequency(I2Cfreq);
+ comchar=0;
+ lockstatus=0;
+ numbeeholders=0;
+ sessionrecordinit();
+ acucomms.printf("\n\r\rFirmware version: %s", fwversion);
+}
+
+//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
+ bhsel = 0;
+ wait(0.1);
+ bhsel = 1;
+ wait(0.3);
+}
+
+//gets holderrecord index for the holder with a certain serial number
+int getholderindex(int serialno) {
+ for (int i=1; i<=100; i++) { //reverse lookup of index for a certain serial number
+ if (sessionrecord[i].serialno == serialno) return i;
+ }
+ return 0; //if the record is not found, returns i==0
+}
+
+//Reads beeholder serial number
+int getserialno() {
+ 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;
+ bhsel = 0; //pull select line 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
+ bhsel = 1; //pull select line high
+ int serialno = serialstring2int(bser); //translate serial number string to integer
+ return serialno;
+}
+
+//Returns 1 if a PER is detected within timeout seconds
+int detectPER(float timeout) {
+ Timer ttotal, tper;
+ ttotal.start(); //start timers for time-out and PER-detect
+ ttotal.reset();
+ tper.start();
+ tper.reset();
+ while ((ttotal.read() < timeout) && (tper.read() < PERtime)) { //loop until timeout or PER detected
+ wait_ms(10);
+ if (ptor * 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
+ }
+ ttotal.stop();
+ tper.stop();
+ return (tper.read() >= PERtime); //if the loop exit condition was a PER, return a TRUE value
+}
+
+//Function performs beeholder/IR-led calibration
+float calibrate(int runs) {
+ float tempcal, ptorhold;
+ tempcal=0.5; //start calibration at 50% voltage
+ irLED=tempcal;
+ float calstep; //start calstep at 25% voltage
+ calstep = tempcal/2;
+ //acucomms.printf("\n\rInitial calibration:");
+ 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
+ ptorhold=ptor;
+ //acucomms.printf("\n\r%5.3f - %5.3f", tempcal, ptorhold);
+ if (ptorhold < 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);
+ ptorhold=ptor;
+ if (ptorhold < 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
+ }
+ irLED = 0;
+ return calib;
+}
+
+//switches the IR LED on at the right brightness level for the beeholder
+void IRledON(int i) {
+ irLED = sessionrecord[i].calvalue;
+}
+
+//moves arm to a position in a specified time, allowing speed control
+void armmove (float endpos, float movetime) {
+ float startpos = arm.read();
+ int numsteps = (movetime * 50); //50 pulses/second, so each step is 1 servo pulse
+ for (int i=0; i<numsteps; i++) {
+ arm = startpos + i * (endpos - startpos)/numsteps;
+ wait(movetime/numsteps);
+ }
+ arm = endpos;
+}
+
+//moves elbow to a position in a specified time, allowing speed control
+void elbowmove (float endpos, float movetime) {
+ float startpos = elbow.read();
+ int numsteps = (movetime * 50); //50 pulses/second, so each step is 1 servo pulse
+ for (int i=0; i<numsteps; i++) {
+ elbow = startpos + i * (endpos - startpos)/numsteps;
+ wait(movetime/numsteps);
+ }
+ elbow = endpos;
+}
+
+//Performs a conditioning cycle. if tickle==0, no tickling takes place. Return==1 if a PER has been detected
+int condcycle(int tickle) {
+ int perseen;
+ perseen = 0;
+ //dip brush
+ armmove(armdippos, 0.5);
+ elbowmove(elbowdippos, 0.3);
+ wait(diptime);
+ elbowmove(elbowbasepos, 0.3);
+ armmove(armbasepos, 0.5);
+ airswitcher=1; //switch air to target odour
+ //tickle
+ if (tickle) { //if tickling, first tickle then wait for PER or timeout
+ elbowmove(elbowticklepos, 0.2);
+ armmove(armticklepos, 1.5); //slower move of arm towards bee
+ perseen = detectPER(tickletimeout); //tickle until timeout or PER detected
+ }
+ //or not tickle
+ else {
+ perseen = detectPER(tickletimeout); //if not tickling, wait for PER or timeout then move to pre-feeding position
+ armmove(armticklepos-0.05, 1); //move to position between LED and holder
+ elbowmove(elbowticklepos, 0.3);
+ }
+ //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
+ elbowmove(elbowfeedpos, 0.3);
+ armmove(armfeedpos, 0.3);
+ wait(feedtime);
+ armmove(armticklepos -0.05, 0.3);
+ elbowmove(elbowticklepos, 0.3);
+ }
+ //move back to base position
+ airswitcher=0; //switch back to clean air
+ armmove(armbasepos, 0.5); //back to basepos
+ elbowmove(elbowbasepos, 0.3); //
+ return perseen;
+}
+
+
+char switchstatus(float vswdetect) {
+ //outputs char (4-bit flag) to reflect positions of 4 detect switches
+ if (vswdetect>0.38 && vswdetect<0.4) return 11;
+ if (vswdetect>0.4 && vswdetect<0.45) return 9;
+ if (vswdetect>0.45 && vswdetect<0.49) return 10;
+ if (vswdetect>0.49 && vswdetect<0.54) return 8;
+ if (vswdetect>0.54 && vswdetect<0.58) return 7;
+ if (vswdetect>0.58 && vswdetect<0.62) return 5;
+ if (vswdetect>0.62 && vswdetect<0.66) return 3;
+ if (vswdetect>0.66 && vswdetect<0.74) return 1;
+ if (vswdetect>0.74 && vswdetect<0.8) return 6;
+ if (vswdetect>0.8 && vswdetect<0.85) return 4;
+ if (vswdetect>0.85 && vswdetect<0.95) return 2;
+ if (vswdetect>0.95 && vswdetect<1.01) return 0;
+ return 16;
+}
+
+//Clamp bee holder
+void clampholder() {
+ unclamp=1;
+ wait(4);
+ unclamp=0;
+}
+
+//Unclamp bee holder
+void unclampholder() {
+ clamp=1;
+ wait(1);
+ clamp=0;
+}
+
+//Lift lid
+void liftlid() {
+ bool notup;
+ notup=1;
+ lidclose=1;
+ while (notup) {
+ wait(0.01);
+ notup = (switchstatus(vswdetect.read()) != 7);
+ }
+ lidclose=0;
+ lidstatus=0;
+}
+
+//Close lid
+void closelid() {
+ bool notdown;
+ notdown=1;
+ lidlift=1;
+ while (notdown) {
+ wait(0.01);
+ notdown = (switchstatus(vswdetect.read()) != 11);
+ }
+ lidlift=0;
+ lidstatus=1;
+}
+
+//Lock lid
+void locklid() {
+ wait(0.1);
+}
+
+//Unlock lid
+void unlocklid() {
+ wait(0.1);
+}
+
+//Set date and time
+void setdatetime() {
+
+
+}
+
+
+void registerbeeholder() {
+ //registers and calibrates the bee holder currently clamped
+ int serialno, i;
+ float calvalue;
+ serialno = getserialno();
+ i = getholderindex(serialno);
+ if (i == 0) {
+ numbeeholders++;
+ if (numbeeholders == 101) {
+ acucomms.printf("Number of holders exceeds 100");
+ }
+ else {
+ sessionrecord[numbeeholders].serialno = serialno;
+ calvalue = calibrate(5);
+ if (calvalue < 0.98 && calvalue > 0.25) {
+ sessionrecord[numbeeholders].calvalue = calvalue;
+ acucomms.printf("\n\rCal %4u - %4.2fV", serialno, calvalue*3.3);
+ }
+ else {
+ acucomms.printf("\n\rCal %4u - invalid", serialno);
+ }
+ }
+ }
+}
+
+/*
+//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(); //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
+ if ((sessionrecord[i].calvalue > 0.25) && (sessionrecord[i].calvalue < 0.97)) { //check that calvalue is in expected range
+ 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, calibrated\r", i, sessionrecord[i].serialno, sessionrecord[i].calvalue*3.3, buffert);
+ i++;
+ }
+ else {
+ cleardisplay();
+ display.printf("SN %4u - cal %4.2fV\r", sessionrecord[i].serialno, sessionrecord[i].calvalue*3.3);
+ display.printf("Cal out of range!\r");
+ multibeeps(2,0.5);
+ display.printf("OK to recalibrate\r");
+ fprintf(logfile, "%4u,%6u,%6.2f, %s, out of range\r", i, sessionrecord[i].serialno, sessionrecord[i].calvalue*3.3, buffert);
+ }
+ 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();
+ multibeeps(3,0.3); //beep-beep-beep when beeholder not correctly read
+ 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
+}
+
+*/
+
+float calcairtemp(float vntc) {
+ return 0.1;
+}
+
+//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;
+ serialno = getserialno();
+ int i = getholderindex(serialno); //get index i for serial number
+ if (i != 0) {
+ IRledON(i); //switch IR LED on at correct brightness
+ sessionrecord[i].cycleno++; //increment cycle number for this beeholder
+ acucomms.printf("\n\rSN: %4u, cycle %u - ", serialno, sessionrecord[i].cycleno);
+ sessionrecord[i].reslastcycle = condcycle(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) {
+ acucomms.printf("PER detected");
+ }
+ else {
+ acucomms.printf("PER time-out");
+ }
+ }
+ else {
+ acucomms.printf("\n\rBee holder %4u not registered", serialno);
+ }
+}
+
+
+
+int main() {
+ init_tm();
+ while (comchar != 88) {
+ comchar = acucomms.getc();
+ switch (comchar) {
+ case 65: //"A"
+ //Continue after pause
+ break;
+ case 66: //"B"
+ //Register bee holder
+ registerbeeholder();
+ break;
+ case 67: //"C"
+ //Calibrate bee holder
+ acucomms.printf("\r\nCalibration: %5.3f", calibrate(5));
+ break;
+ case 68: //"D"
+ //Clamp bee holder
+ clampholder();
+ break;
+ case 69: //"E"
+ //Unclamp bee holder
+ unclampholder();
+ break;
+ case 70: //"F"
+ //Open lid
+ liftlid();
+ break;
+ case 71: //"G"
+ //Close lid
+ closelid();
+ break;
+ case 72: //"H"
+ //Lock lid
+ locklid();
+ break;
+ case 73: //"I"
+ //Unlock lid
+ unlocklid();
+ break;
+ case 74: //"J"
+ //Conduct training cycle
+ trainingcycle();
+ break;
+ case 75: //"K"
+ //Read air temperature
+ break;
+ case 76: //"L"
+ //Toggle fan on/off
+ fan=!fan;
+ break;
+ case 77: //"M"
+ //Move arm/elbow to basepos
+ armmove(armbasepos, 1);
+ elbowmove(elbowbasepos, 1);
+ break;
+ case 78: //"N"
+ //Move arm/elbow to dippos
+ armmove(armdippos, 1);
+ elbowmove(elbowdippos, 1);
+ break;
+ case 79: //"O"
+ //Move arm/elbow to ticklepos
+ armmove(armticklepos, 1);
+ elbowmove(elbowticklepos, 1);
+ break;
+ case 80: //"P"
+ //Move arm/elbow to feedpos
+ armmove(armfeedpos, 1);
+ elbowmove(elbowfeedpos, 1);
+ break;
+ case 81: //"Q"
+ //Print SWdetect value
+ wait(0.1);
+ swvalue = vswdetect.read();
+ acucomms.printf("\rVSWDETECT: %5.3f", swvalue);
+ break;
+ case 82: //"R"
+ //multiple calibrations to see variation
+ acucomms.printf("\r\nBee holder: %4u", getserialno());
+ for (int i=0; i<40; i++) {
+ acucomms.printf("\r\nN%3u C=%5.3f", i+1, calibrate(5));
+ wait(15);
+ }
+ acucomms.printf("\r\nDone");
+ break;
+ case 83: //"S"
+ //Toggle air switcher
+ airswitcher = !airswitcher;
+ if (airswitcher) {
+ acucomms.printf("\n\rAirswitcher on");
+ }
+ else {
+ acucomms.printf("\n\rAirswitcher off");
+ }
+ break;
+ case 84: //"T"
+ //set date and time on RTC
+ setdatetime();
+ break;
+ default: //All other characters
+ //Do nothing
+ break;
+ }
+ if (comchar != 88) comchar=0;
+ }
+ acucomms.printf("\n\rSession closed");
+ //Close logfile
+ fprintf(logfile, "session closed");
+ fclose(logfile); //close logfile for reading
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/main_070.cpp Mon Jul 25 11:52:02 2011 +0000
@@ -0,0 +1,593 @@
+//Firmware to drive Sorbonne-2 bee training module
+char* fwversion = "0.70"; //For published versions use format "n.nn"
+ //For development versions add "D" to end of string
+//This version published on 25/07/2011
+
+#include "mbed.h"
+#include "Servo.h"
+
+DigitalOut led1(LED1), led2(LED2), led3(LED3), led4(LED4);
+DigitalOut lidclose(p5), lidlift(p6);
+DigitalOut clamp(p7), unclamp(p8);
+DigitalOut lockr(p12), unlockl(p13), lockl(p14), unlockr(p26);
+AnalogIn viclamp(p15);
+AnalogIn vswdetect(p16);
+AnalogIn adc4(p17);
+AnalogOut irLED(p18);
+AnalogIn vtemp(p19);
+AnalogIn ptor(p20);
+Servo arm(p21), elbow(p22);
+DigitalOut fan(p23);
+I2C beeholder(p9, p10);
+DigitalOut bhsel(p11);
+Serial acucomms(p28, p27);
+DigitalIn tmselect(p29);
+DigitalOut airswitcher(p25), spare1(p24);
+LocalFileSystem local("local"); //allow access to the mbed "thumbdrive" as a file system
+//FILE *calfile = fopen("/local/calfile.ini","w"); //file used to store bee holder calibration values
+FILE *logfile = fopen("/local/sorb2log.csv","w"); //creates new file sorb2log.csv and set for writing. Overwrites existing file!
+
+//Definition of global constants
+ //Training module PCB #2 robot arm positions
+ //Increase in arm position moves arm away from bee holder
+ //Increase in elbow position lowers tip
+ float armbasepos = 0.81;
+ float elbowbasepos = 0.6;
+ float armdippos = 0.81;
+ float elbowdippos = 0.84;
+ float armticklepos = 0.15;
+ float elbowticklepos = 0.63;
+ float armfeedpos = 0.08;
+ float elbowfeedpos = 0.77;
+
+ //robot arm hold and move times //all times are in seconds
+ float diptime = 1; //time that brush stays down dipped in sugar water
+ float tickletimeout = 3; //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
+
+ //Protocols
+ int addr = 0xA2; //I2C address is actually 0x51, but mbed expects left-shifted address
+ int I2Cfreq = 10000; //I2C bus frequency
+ int baudrate = 19200; //baudrate of serial connection to ACU
+
+//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[101]; //sessionrecord contains holderrecords for up to 100 beeholders
+
+int numbeeholders; //number of beeholders used in current session
+int serialnum;
+char comchar; //serial command character for module control
+float fanspeed;
+bool lockstatus, clampstatus, lidstatus; //are true when locked, clamped or closed
+char swstatus; //4-bit number to indicate status of 4 detect switches
+float swvalue; //ADC value for detect switch voltage
+
+//Function declarations
+
+//Initialises sessionrecords
+void sessionrecordinit() {
+ for (int i=0; i<101; 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
+ }
+}
+
+//Reads serial numbers and calibration values from calfile.ini
+void getcaldata() {
+
+}
+
+//Initialise at power-up or reset
+void init_tm() {
+ led1=led2=led3=0;
+ led4=1;
+ lidclose=lidlift=0;
+ clamp=unclamp=0;
+ lockr=unlockr=lockl=unlockl=0;
+ irLED=0;
+ bhsel=0;
+ airswitcher=0;
+ spare1=0;
+ fan=0;
+ acucomms.baud(baudrate);
+ beeholder.frequency(I2Cfreq);
+ comchar=0;
+ lockstatus=0;
+ numbeeholders=0;
+ sessionrecordinit();
+ acucomms.printf("\n\r\rFirmware version: %s", fwversion);
+}
+
+//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
+ bhsel = 0;
+ wait(0.1);
+ bhsel = 1;
+ wait(0.3);
+}
+
+//gets holderrecord index for the holder with a certain serial number
+int getholderindex(int serialno) {
+ for (int i=1; i<=100; i++) { //reverse lookup of index for a certain serial number
+ if (sessionrecord[i].serialno == serialno) return i;
+ }
+ return 0; //if the record is not found, returns i==0
+}
+
+//Reads beeholder serial number
+int getserialno() {
+ 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;
+ bhsel = 0; //pull select line 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
+ bhsel = 1; //pull select line high
+ int serialno = serialstring2int(bser); //translate serial number string to integer
+ return serialno;
+}
+
+//Returns 1 if a PER is detected within timeout seconds
+int detectPER(float timeout) {
+ Timer ttotal, tper;
+ ttotal.start(); //start timers for time-out and PER-detect
+ ttotal.reset();
+ tper.start();
+ tper.reset();
+ while ((ttotal.read() < timeout) && (tper.read() < PERtime)) { //loop until timeout or PER detected
+ wait_ms(10);
+ if (ptor * 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
+ }
+ ttotal.stop();
+ tper.stop();
+ return (tper.read() >= PERtime); //if the loop exit condition was a PER, return a TRUE value
+}
+
+//Function performs beeholder/IR-led calibration
+float calibrate(int runs) {
+ float tempcal, ptorhold;
+ tempcal=0.5; //start calibration at 50% voltage
+ irLED=tempcal;
+ float calstep; //start calstep at 25% voltage
+ calstep = tempcal/2;
+ //acucomms.printf("\n\rInitial calibration:");
+ 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
+ ptorhold=ptor;
+ //acucomms.printf("\n\r%5.3f - %5.3f", tempcal, ptorhold);
+ if (ptorhold < 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);
+ ptorhold=ptor;
+ if (ptorhold < 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
+ }
+ irLED = 0;
+ return calib;
+}
+
+//switches the IR LED on at the right brightness level for the beeholder
+void IRledON(int i) {
+ irLED = sessionrecord[i].calvalue;
+}
+
+//moves arm to a position in a specified time, allowing speed control
+void armmove (float endpos, float movetime) {
+ float startpos = arm.read();
+ int numsteps = (movetime * 50); //50 pulses/second, so each step is 1 servo pulse
+ for (int i=0; i<numsteps; i++) {
+ arm = startpos + i * (endpos - startpos)/numsteps;
+ wait(movetime/numsteps);
+ }
+ arm = endpos;
+}
+
+//moves elbow to a position in a specified time, allowing speed control
+void elbowmove (float endpos, float movetime) {
+ float startpos = elbow.read();
+ int numsteps = (movetime * 50); //50 pulses/second, so each step is 1 servo pulse
+ for (int i=0; i<numsteps; i++) {
+ elbow = startpos + i * (endpos - startpos)/numsteps;
+ wait(movetime/numsteps);
+ }
+ elbow = endpos;
+}
+
+//Performs a conditioning cycle. if tickle==0, no tickling takes place. Return==1 if a PER has been detected
+int condcycle(int tickle) {
+ int perseen;
+ perseen = 0;
+ //dip brush
+ armmove(armdippos, 0.5);
+ elbowmove(elbowdippos, 0.3);
+ wait(diptime);
+ elbowmove(elbowbasepos, 0.3);
+ armmove(armbasepos, 0.5);
+ airswitcher=1; //switch air to target odour
+ //tickle
+ if (tickle) { //if tickling, first tickle then wait for PER or timeout
+ elbowmove(elbowticklepos, 0.2);
+ armmove(armticklepos, 1.5); //slower move of arm towards bee
+ perseen = detectPER(tickletimeout); //tickle until timeout or PER detected
+ }
+ //or not tickle
+ else {
+ perseen = detectPER(tickletimeout); //if not tickling, wait for PER or timeout then move to pre-feeding position
+ armmove(armticklepos-0.05, 1); //move to position between LED and holder
+ elbowmove(elbowticklepos, 0.3);
+ }
+ //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
+ elbowmove(elbowfeedpos, 0.3);
+ armmove(armfeedpos, 0.3);
+ wait(feedtime);
+ armmove(armticklepos -0.05, 0.3);
+ elbowmove(elbowticklepos, 0.3);
+ }
+ //move back to base position
+ airswitcher=0; //switch back to clean air
+ armmove(armbasepos, 0.5); //back to basepos
+ elbowmove(elbowbasepos, 0.3); //
+ return perseen;
+}
+
+
+char switchstatus(float vswdetect) {
+ //outputs char (4-bit flag) to reflect positions of 4 detect switches
+ if (vswdetect>0.38 && vswdetect<0.4) return 11;
+ if (vswdetect>0.4 && vswdetect<0.45) return 9;
+ if (vswdetect>0.45 && vswdetect<0.49) return 10;
+ if (vswdetect>0.49 && vswdetect<0.54) return 8;
+ if (vswdetect>0.54 && vswdetect<0.58) return 7;
+ if (vswdetect>0.58 && vswdetect<0.62) return 5;
+ if (vswdetect>0.62 && vswdetect<0.66) return 3;
+ if (vswdetect>0.66 && vswdetect<0.74) return 1;
+ if (vswdetect>0.74 && vswdetect<0.8) return 6;
+ if (vswdetect>0.8 && vswdetect<0.85) return 4;
+ if (vswdetect>0.85 && vswdetect<0.95) return 2;
+ if (vswdetect>0.95 && vswdetect<1.01) return 0;
+ return 16;
+}
+
+//Clamp bee holder
+void clampholder() {
+ unclamp=1;
+ wait(4);
+ unclamp=0;
+}
+
+//Unclamp bee holder
+void unclampholder() {
+ clamp=1;
+ wait(1);
+ clamp=0;
+}
+
+//Lift lid
+void liftlid() {
+ bool notup;
+ notup=1;
+ lidclose=1;
+ while (notup) {
+ wait(0.01);
+ notup = (switchstatus(vswdetect.read()) != 7);
+ }
+ lidclose=0;
+ lidstatus=0;
+}
+
+//Close lid
+void closelid() {
+ bool notdown;
+ notdown=1;
+ lidlift=1;
+ while (notdown) {
+ wait(0.01);
+ notdown = (switchstatus(vswdetect.read()) != 11);
+ }
+ lidlift=0;
+ lidstatus=1;
+}
+
+//Lock lid
+void locklid() {
+ wait(0.1);
+}
+
+//Unlock lid
+void unlocklid() {
+ wait(0.1);
+}
+
+//Set date and time
+void setdatetime() {
+
+
+}
+
+
+void registerbeeholder() {
+ //registers and calibrates the bee holder currently clamped
+ int serialno, i;
+ float calvalue;
+ serialno = getserialno();
+ i = getholderindex(serialno);
+ if (i == 0) {
+ numbeeholders++;
+ if (numbeeholders == 101) {
+ acucomms.printf("Number of holders exceeds 100");
+ }
+ else {
+ sessionrecord[numbeeholders].serialno = serialno;
+ calvalue = calibrate(5);
+ if (calvalue < 0.98 && calvalue > 0.25) {
+ sessionrecord[numbeeholders].calvalue = calvalue;
+ acucomms.printf("\n\rCal %4u - %4.2fV", serialno, calvalue*3.3);
+ }
+ else {
+ acucomms.printf("\n\rCal %4u - invalid", serialno);
+ }
+ }
+ }
+}
+
+/*
+//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(); //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
+ if ((sessionrecord[i].calvalue > 0.25) && (sessionrecord[i].calvalue < 0.97)) { //check that calvalue is in expected range
+ 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, calibrated\r", i, sessionrecord[i].serialno, sessionrecord[i].calvalue*3.3, buffert);
+ i++;
+ }
+ else {
+ cleardisplay();
+ display.printf("SN %4u - cal %4.2fV\r", sessionrecord[i].serialno, sessionrecord[i].calvalue*3.3);
+ display.printf("Cal out of range!\r");
+ multibeeps(2,0.5);
+ display.printf("OK to recalibrate\r");
+ fprintf(logfile, "%4u,%6u,%6.2f, %s, out of range\r", i, sessionrecord[i].serialno, sessionrecord[i].calvalue*3.3, buffert);
+ }
+ 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();
+ multibeeps(3,0.3); //beep-beep-beep when beeholder not correctly read
+ 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
+}
+
+*/
+
+float calcairtemp(float vntc) {
+ return 0.1;
+}
+
+//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;
+ serialno = getserialno();
+ int i = getholderindex(serialno); //get index i for serial number
+ if (i != 0) {
+ IRledON(i); //switch IR LED on at correct brightness
+ sessionrecord[i].cycleno++; //increment cycle number for this beeholder
+ acucomms.printf("\n\rSN: %4u, cycle %u - ", serialno, sessionrecord[i].cycleno);
+ sessionrecord[i].reslastcycle = condcycle(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) {
+ acucomms.printf("PER detected");
+ }
+ else {
+ acucomms.printf("PER time-out");
+ }
+ }
+ else {
+ acucomms.printf("\n\rBee holder %4u not registered", serialno);
+ }
+}
+
+
+
+int main() {
+ init_tm();
+ while (comchar != 88) {
+ comchar = acucomms.getc();
+ switch (comchar) {
+ case 65: //"A"
+ //Continue after pause
+ break;
+ case 66: //"B"
+ //Register bee holder
+ registerbeeholder();
+ break;
+ case 67: //"C"
+ //Calibrate bee holder
+ acucomms.printf("\r\nCalibration: %5.3f", calibrate(5));
+ break;
+ case 68: //"D"
+ //Clamp bee holder
+ clampholder();
+ break;
+ case 69: //"E"
+ //Unclamp bee holder
+ unclampholder();
+ break;
+ case 70: //"F"
+ //Open lid
+ liftlid();
+ break;
+ case 71: //"G"
+ //Close lid
+ closelid();
+ break;
+ case 72: //"H"
+ //Lock lid
+ locklid();
+ break;
+ case 73: //"I"
+ //Unlock lid
+ unlocklid();
+ break;
+ case 74: //"J"
+ //Conduct training cycle
+ trainingcycle();
+ break;
+ case 75: //"K"
+ //Read air temperature
+ break;
+ case 76: //"L"
+ //Toggle fan on/off
+ fan=!fan;
+ break;
+ case 77: //"M"
+ //Move arm/elbow to basepos
+ armmove(armbasepos, 1);
+ elbowmove(elbowbasepos, 1);
+ break;
+ case 78: //"N"
+ //Move arm/elbow to dippos
+ armmove(armdippos, 1);
+ elbowmove(elbowdippos, 1);
+ break;
+ case 79: //"O"
+ //Move arm/elbow to ticklepos
+ armmove(armticklepos, 1);
+ elbowmove(elbowticklepos, 1);
+ break;
+ case 80: //"P"
+ //Move arm/elbow to feedpos
+ armmove(armfeedpos, 1);
+ elbowmove(elbowfeedpos, 1);
+ break;
+ case 81: //"Q"
+ //Print SWdetect value
+ wait(0.1);
+ swvalue = vswdetect.read();
+ acucomms.printf("\rVSWDETECT: %5.3f", swvalue);
+ break;
+ case 82: //"R"
+ //multiple calibrations to see variation
+ acucomms.printf("\r\nBee holder: %4u", getserialno());
+ for (int i=0; i<40; i++) {
+ acucomms.printf("\r\nN%3u C=%5.3f", i+1, calibrate(5));
+ wait(15);
+ }
+ acucomms.printf("\r\nDone");
+ break;
+ case 83: //"S"
+ //Toggle air switcher
+ airswitcher = !airswitcher;
+ if (airswitcher) {
+ acucomms.printf("\n\rAirswitcher on");
+ }
+ else {
+ acucomms.printf("\n\rAirswitcher off");
+ }
+ break;
+ case 84: //"T"
+ //set date and time on RTC
+ setdatetime();
+ break;
+ default: //All other characters
+ //Do nothing
+ break;
+ }
+ if (comchar != 88) comchar=0;
+ }
+ acucomms.printf("\n\rSession closed");
+ //Close logfile
+ fprintf(logfile, "session closed");
+ fclose(logfile); //close logfile for reading
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mbed.bld Mon Jul 25 11:52:02 2011 +0000 @@ -0,0 +1,1 @@ +http://mbed.org/users/mbed_official/code/mbed/builds/63bcd7ba4912