//BBC-Buggy.ino - 2020-08-31 char thisrobot[] ="BBC-Buggy "; char thisprog[] ="BBC-Buggy 2020-09-19"; /* Uno Sketch uses 20068 bytes (62%) of program storage space. Maximum is 32256 bytes. Global variables use 752 bytes (36%) of dynamic memory, leaving 1296 bytes for local variables. Maximum is 2048 bytes. set Serial terminal to 9600 baud Note - The Arduino Serial Monitor can't send [Esc]. If another Terminal is used which can send [Esc] then at GetCcmnd() this will be printed, which may print as a symbol or the Terminal may change it to "." ============================================================ History ------- 19Sep2020 h,H,T,gH,tH,?m 13Sep2020 added tL t_toLight, tD t_toDark 11Sep2020 added 'bad' default run 07Sep2020 added "comments" 31 Aug 2020 - ported from Zeaker2 Zeaker2 30 Aug 2020 - added date to thisprog[] 08 Jan 2019 - added copy to help 25 May 2017 - program finished ============================================================ BBC-Buggy --------- Umbilical - Ch2,Rbump,PenU,Lrev ,Ch0 ,Ch1 ,0vL,5vL,12v,12v Ch3,Lbump,Tilt,/motors,step,Rrev,5vL,0vP,0vP,0vP 12v - motor supply 0vP - motor 0v 5v - 5v logic 0vL - 0v logic Ch3 - L-LDR Ch2 - R-LDR Ch1 - BarCode/line sense Ch0 - LDR Lbump - Left bumper Rbump - Right bumper Tilt - not fitted PenU - Pen up Mstep - step both motors each step is ~1.45mm (from BetaBasic program) Lrev - Left motor direction F=0, B=1 Rrev - Right motor direction F=0, B=1 /motors - motor enable low Tyre diameter 65.84mm One revoulution 206.84mm Motors - Phillips ID35 - 7.5deg /step, 48 steps /rev Gearing 10t:30t 206.84 /3 /48 =1.43mm per step Track 162mm - (508.9mm circumference) 355.87 steps /360deg -- for 360 track would be 163.87mm ============================================================ Bugs - ============================================================ To do next - ============================================================= improvements? ------------- C - command, Clf line find, Cl follow line for distance ============================================================= Primary commands used 012345678 ?*.!$~()Esc BDFLQRU bnsw ' 'space and ','comma ignored COMMANDS ======== [Esc],[Q] - stop, quit operations, go to command mode [.] - stop, end current operation - recording, playing, input ["] - start/end of a comment, processed in GetCcmnd() [(] - start of a Do, will show its location in EEPROM when played, eg (=263 If a jump to another Act is made from within a Do then the Do location will be shown eg (@267) and when returning the return location will be shown, eg (267) A jump to an Act from a Do will on . continue in the Do If a jump is made to an Act which contains another Do then that Do will become the current Do and the old Do will not be returned to [)] - end of a Do, will show its location in EEPROM when played, eg )=285 [0] - use page0 for the next cmnd or Act number [1-8] Play act, or the Act to record, copy, load etc [F]{digits}[,] - Forwards - if no digits then 1 - units mm [B]{digits}[,] - Backwards - if no digits then 1 - units mm [R]{digits}[,] - turn Right - if no digits then 1 - units degrees [L]{digits}[,] - turn Left - if no digits then 1 - units degrees [T]{digits}[,] - turn to heading - if no digits then ignore [H] - goto 'home' [D] - Pen down [U] - Pen up [w][0-9,0] - wait seconds, 0=10 [n][0-9,0] - nap tenths second, 0=10 SPEED [s][1-9] - steptime/3 [+] - speed-up, steptime -=1 >=1 [-] - speed-down, steptime +=1 [u] - speed-up, steptime -=1 >=stepmin [d] - speed-down, steptime *=2 [m] - set speed-max for speed-up to current speed [s] - save speed TURN [t][m] - Turn Memory - turn same way as last time [o] - Turn Other - turn other way from last time [l] - Turn to Light [d] - Turn to Dark [u] - Turn unwind SENSORS [$][b] - test bumper status and ReAct [e] - test eyes staus and ReAct [l] - return LDR value [c] - return barcode value SKILL [t][l] - Turn to Light [d] - Turn to Dark [L] - Turn at Light [D] - Turn at Dark [u] - Turn unwind [H] - Turn to 'home' [h] - set current location as new 'home' [H] - goto 'home' [g][H] - goto 'home' MIND [?][m] - print Mind BEHAVIOUR [b][0] - do default behaviour [S] - save current behaviour as default [a][1-8] - Act to autorun on power on [0] - no autorun [d] - if Playing ends, run autorun Act [m][digits][,] - default move mm or degrees [r][digits][,] - rotatescale, actual steps for 360 degrees [s][digits][,] - stepescale, actual steps for 100mm [e][digits][,] - eye thredhold [l][digits][,] - LDR thredhold [c][digits][,] - BarCode thredhold [$][0,1] - sensor react 0=off [!][0,1] - 0=turn off reacting flag to jump from a ReAct, automatically turns on again SYSTEM [*][r][(0) 1-8] - record act, optional 0 use page0 [l][(0) 1-8] - load act, optional 0 use page0 [c][(0) 1-8][(0) 1-8] - copy Act to Act, optional 0 use page0 PRINT [?][?] - print Acts [0] - prints Acts 0, and changes '??' to just print current page - (for QL zero2 program) [a] - change back to ?? prints all Acts [1-8] - print Act [!} - print ReActs [b] - print Behaviour - thisprog,autoAct,f_autoPower,steptime,stepmin,stepScale360 [m] - print Mind [d] - dump all acts to PC without descriptions, suitable for loading [$] - show all sensor values [h] - print help [f] - print free RAM Notes [(] - will show its location in EEPRO< when played eg (=263 [)] - will show its location in EEPRO< when played eg )=285 If a call to another Act is made from within Mind then the location to return to will be shown, eg (267) Acts by default are stored in page 1, 0 changes to page 0 for the next command only. Page 0 ia EEPROM bytes 0-255, Page 1 is EEPROM bytes 256-511 etc. ============================================================= Program == SECTIONS =============================================== == NEW == CHANGED == INCLUDES EEPROM.h - the Arduino EEPROM library == PINS == VARIABLES and CONSTANTS == SETUP == LOOP DoCommand: == USER ROUTINES Experiment() //until Quit Xplore() //Wander() until Quit == FUNCTIONS void GetCcmnd() //reads Serial or playing Act until Ccmnd != 0, prints Ccmnd void PlayAct() void setEEPROMindexes(char Act) // set EEPROM pointers void RecordCcmnd() void GetNum() void getAct() //called when recording, loading, printing and copying Acts, Ccmnd ->'.', '1' - '8' void loadAct() void copyAct() void show_bump() void show_eyes() void show_light() void show_code() void waitSecs(byte cmnd) //read delay time from Act and wait void waitTenthsSecs(byte cmnd) //read delay time from Act and wait void badkey() // indicate invalid key boolean Quit() //check for Quit void PrintReActs() void printReAct() void DumpActs() //Dump Acts, Acts0, ReActs. Print without names and length void PrintActs0() void PrintAllActs() void printAct() void printBehaviour() void printHelp() void printMind() void disp_freeram() TAB FILES movement.ino SKILL - t_light(), t_dark(), t_atLight(), t_atDark() t_unwind() MOVEMENT - Forward(), Backward(), turnRight(), turnLeft() PenUp(), PenDown() //=========================================================== */ /*== NEW ==================================================== */ /*== CHANGED ================================================ */ //== INCLUDES =============================================== #include // to read and write internal EEPROM // EEPROM.update(address,bytevalue) // bytevalue =EEPROM.read(address) #include // atan() always=0 without this //== PINS =================================================== //pin0 Rx when connected to a SparkFun RS232 module can't have // a 1k protection resistor as doesn't then receive. //pin1 Tx //pin2 //pin3 const byte RMdir =4; // Fd=0 Bk=1 const byte LMdir =5; // Fd=0 Bk=1 const byte Mstep =6; const byte MotorsOff =7; const byte PenCtrl =8; const byte Rbump =9; const byte Lbump =10; const byte Tilt =11; const byte Sounder =12; //off-Buggy on Arduino board const byte Ch0 =A0; //LDR ~23k-300R 0.06v-2.45v ~3(black)-511(white) const byte Ch1 =A1; //BarCode/LineFollower 20(white)-580(black) const byte Ch2 =A2; const byte Reye =A2; //dark low, bright high ~70 - 530 const byte Ch3 =A3; const byte Leye =A3; //dark low, bright high ~70 - 530 //== VARIABLES and CONSTANTS ================================ boolean f_recording =false; //recording an Act boolean f_recordC =false; //record current Command boolean f_play =false; //Play current Act boolean f_reacting =false; //in a ReAct - set if a React is initiated. boolean f_doDefault =true; //true for the first loop boolean f_runDefault =false; //run Default when nothing else to do boolean f_inDo =false; boolean f_printAll =true; //'??' prints all acts, false '??' prints current page boolean f_dark =true; //React on Dark boolean f_TurnedRight =true; //last turn was R boolean f_react =true; //react to sensors - =0 for when decisions are made by an external processor boolean f_comment =false; //1=>comment string in a command string //boolean f_bG =0; //auto sense Ground control //boolean f_bW =0; //auto sense Whiskers control //boolean f_bU =0; //auto sense Ultrasonic control const byte NL =10; //NewLine value const byte LF =10; //LineFeed value const byte CR =13; //Carriage Return value const byte Esc =27; //Esc key value char Act; //current Act as '1' - '8' char autoAct ='0'; //act to run on reset, poweron byte actIndex =0; //current Act number, set to default int EEPROMindex =-1; //index to moves in an Act in EEPROM, -1 => nothing to continue with #> int ReactAt; //copy of EEPROMindex at React int ActEnd; //end address of current recording Act in EEPROM int moves =0; //current move char Ccmnd =0; //current Character command, default null command char stackCcmnd =0; //set in GetNum() if Ccmnd not digit or terminator, set in badkey if subcmnd == Q . Esc byte epage; //the Act page for the current Act, default page =1 for Acts 1-8 and page =0 for 01-08 byte slotbase; //working slotbase long numValue =0; //temporary value in getnum() //needs to be long because of scale sums String numString =""; //temporary string in getnum() //MACHINE int steptime =20; //mSec between motor steps 2=fast int defaultsteptime =6; int stepmin =8; //max speed long msteps; //used in move routines long thisMove =0; //mm or deg int DoAt =0; //EEPROM address always >1 since must be preceded by {x where x is act value '1' - '8' long steps; //motor steps to move byte defaultMove =10; //mm or degrees int stepScale100; int rotateScale360; long heading =0; // if smaller than 'long numValue' becomes negative when assigned numValue int AtX =0; // Actual X position int AtY =0; // Actual Y position int moveX =0; // this move X int moveY =0; // this move Y float homeHeading; // direction to Home position int homeDistance; // distance to Home //SENSORS byte bumpState; int eyeThresholddefault =400; int eyeThreshold; byte eyesState; int LDRthresholddefault =350; int LDRthreshold; byte LDRstate; int BarCodeThresholddefault =450; int BarCodeThreshold; byte BarCodeState; int BClast; int BChere; int BCchange; int BCchangemax =40; const int rotateScale360default =356; const int stepScale100default =70; const byte EautoAct =255; //address in EEPROMpage0, last available byte const byte EstepScale100hi =254; //address in EEPROMpage0 const byte EstepScale100lo =253; //address in EEPROMpage0 const byte ErotateScale360hi =252; //address in EEPROMpage0 const byte ErotateScale360lo =251; //address in EEPROMpage0 const byte Esteptime =250; //address in EEPROMpage0 const byte EdefaultMove =249; //address in EEPROMpage0 const byte EeyeThresholdhi =248; //address in EEPROMpage0 const byte EeyeThresholdlo =247; //address in EEPROMpage0 const byte ELDRthresholdhi =246; //address in EEPROMpage0 const byte ELDRthresholdlo =245; //address in EEPROMpage0 const byte EBarCodeThresholdhi =244; //address in EEPROMpage0 const byte EBarCodeThresholdlo =243; //address in EEPROMpage0 //== SETUP ================================================== void setup() { pinMode(PenCtrl, OUTPUT); pinMode(MotorsOff, OUTPUT); pinMode(Mstep, OUTPUT); pinMode(LMdir, OUTPUT); pinMode(RMdir, OUTPUT); digitalWrite(PenCtrl, HIGH); //Pen Up digitalWrite(MotorsOff, HIGH); //motors OFF digitalWrite(Mstep, LOW); digitalWrite(LMdir, HIGH); //Fd digitalWrite(RMdir, HIGH); //Fd pinMode(A4,INPUT); Serial.begin(9600); // to communicate with Serial Monitor Serial.println(); Serial.println(thisprog); epage =1; //set to default page, Acts 1 - 8 autoAct =EEPROM.read(EautoAct); if (autoAct<'0' || autoAct>'8') { autoAct ='0'; EEPROM.update(EautoAct,autoAct); } //maybe uninitialised steptime =EEPROM.read(Esteptime); if (steptime<0 || steptime>20 ) {steptime =6; EEPROM.update(Esteptime,steptime); } defaultMove =EEPROM.read(EdefaultMove); if (defaultMove <0 || defaultMove >200 ) {defaultMove =10; EEPROM.update(EdefaultMove,defaultMove); } rotateScale360 =(EEPROM.read(ErotateScale360hi) *256) +EEPROM.read(ErotateScale360lo); if (rotateScale360 <0 || rotateScale360 >400) //400 is some higher number, probably uninitialised EEPROM { rotateScale360 =rotateScale360default; } stepScale100 =(EEPROM.read(EstepScale100hi) *256) +EEPROM.read(EstepScale100lo); if (stepScale100 <0 || stepScale100 >400) //400 is some higher number, probably uninitialised EEPROM { stepScale100 =stepScale100default; } eyeThreshold =(EEPROM.read(EeyeThresholdhi) *256) +EEPROM.read(EeyeThresholdlo); if (eyeThreshold <10 || eyeThreshold >1000) //1000 is some higher number, probably uninitialised EEPROM { eyeThreshold =eyeThresholddefault; } LDRthreshold =(EEPROM.read(ELDRthresholdhi) *256) +EEPROM.read(ELDRthresholdlo); if (LDRthreshold <10 || LDRthreshold >1000) //1000 is some higher number, probably uninitialised EEPROM { LDRthreshold =LDRthresholddefault; } BarCodeThreshold =(EEPROM.read(EBarCodeThresholdhi) *256) +EEPROM.read(EBarCodeThresholdlo); if (BarCodeThreshold <10 || BarCodeThreshold >1000) //1000 is some higher number, probably uninitialised EEPROM { BarCodeThreshold =BarCodeThresholddefault; } } //== LOOP =================================================== void loop() { f_recordC =true; // record Command, default =true if (f_doDefault) // true on the first loop { f_doDefault =false; // don't do it again Ccmnd =autoAct; if(Ccmnd=='0') { f_runDefault =false; Ccmnd ='.'; } // '0' -> no autorun, can't run it so do stop } else { if (stackCcmnd !=0) { Ccmnd =stackCcmnd; stackCcmnd =0; } else { Serial.print(">"); //ready prompt GetCcmnd(); } } DoCommand: if(Ccmnd==255 || Ccmnd==-1 ) Ccmnd ='.'; //uninitialised EEPROM value, don't play it, change to '.' switch (Ccmnd) { case LF: f_recordC =false; break; //ignore and don't record linefeed case CR: f_recordC =false; break; //ignore and don't record carriage return case ' ': break; //strip space case ',': break; //strip comma case 'Q': // fall through case Esc: f_reacting =false; f_inDo =false; DoAt =0; f_runDefault =false; //[Esc] key, fall through to '.' case '.': if (f_recording) { EEPROM.update(EEPROMindex,'.'); } //terminated string f_recording =false; stackCcmnd =0; if (f_reacting) // end of ReAct { f_reacting =false; EEPROMindex =ReactAt; f_play =true; break; } if (DoAt !=0) { Serial.print("("); Serial.print(DoAt); Serial.print(")"); EEPROMindex =DoAt; DoAt =0; f_inDo =true; break; } f_play =false; // end of Act Serial.println(); if (f_runDefault) { f_doDefault =true; } break; case '(': f_inDo =true; Serial.print("="); Serial.println(EEPROMindex-1); break; case ')': f_inDo =false; Serial.print("="); Serial.println(EEPROMindex-1); break; // case 'X': // if recording record 'X' otherwise do Xplore() until 'Q' or reset // if (!f_recording) { Xplore(); } break; case 'E': // if recording record 'E' otherwise do Experiment() until 'Q' or reset if (!f_recording) { Experiment(); } break; case '!': epage =3; break; //reset to 1 at the end of setEEPROMindexes(char Act) case '0': epage =0; break; //reset to 1 at the end of setEEPROMindexes(char Act) case '1': // fall through case '2': // fall through case '3': // fall through case '4': // fall through case '5': // fall through case '6': // fall through case '7': // fall through case '8': if (!f_recording) { if (f_inDo) { DoAt =EEPROMindex; Serial.print("(@"); Serial.print(DoAt); Serial.print(")"); f_inDo =false; //because we are jumping to another Act } f_play =true; Act =Ccmnd; setEEPROMindexes(Act); } break; case 'F': if (f_recording) { RecordCcmnd(); } //so 'F' is recorded GetNum(); thisMove =numValue; go_Forward(); break; case 'B': if (f_recording) { RecordCcmnd(); } //so 'B' is recorded GetNum(); thisMove =numValue; go_Backward(); break; case 'R': if (f_recording) { RecordCcmnd(); } //so 'R' is recorded GetNum(); thisMove =numValue; go_turnRight(); break; case 'L': if (f_recording) { RecordCcmnd(); } //so 'L' is recorded GetNum(); thisMove =numValue; go_turnLeft(); break; case 'H': if (f_recording) { RecordCcmnd(); } //so 'H' is recorded go_Home(); break; case 'h': if (f_recording) { RecordCcmnd(); } //so 'h' is recorded heading =0; AtX =0; AtY =0; //set current as home break; case 'T': // Turnto heading if (f_recording) { RecordCcmnd(); } //so 'T' is recorded GetNum(); if (stackCcmnd!=0) { break; } //error - don't use default thisMove =numValue -heading; if (thisMove >180) { thisMove =thisMove -360; } p(" thisMove",thisMove); go_Turn(); break; //Pen case 'U': PenUp(); break; case 'D': PenDown(); break; //Voice case 'V': tone(Sounder,1000,300); break; // case 'W': WhiskerReact(); break; // case 'G': BeardReact(); break; //go case 'g': if (f_recording) { RecordCcmnd(); } //so 'g' is recorded GetCcmnd(); //get parameter switch (Ccmnd) { case 'H': go_Home(); break; } break; //wait case 'w': if (f_recording) { RecordCcmnd(); } //so 'w' is recorded GetCcmnd(); //get parameter if ( !isDigit(Ccmnd) ) { badkey(); Serial.print("?1"); Ccmnd ='1'; } //1=default waitSecs(Ccmnd -'0'); //'0' is 10 break; // if recording Ccmnd will be recorded //nap case 'n': if (f_recording) { RecordCcmnd(); } //so 'n' is recorded GetCcmnd(); //get parameter if ( !isDigit(Ccmnd) ) { badkey(); Serial.print("?1"); Ccmnd ='1'; } //1=default waitTenthsSecs(Ccmnd -'0'); //'0' is 10 break; // if recording Ccmnd will be recorded //===================================== //TURN case 't': if (f_recording) { RecordCcmnd(); } //so 's' is recorded GetCcmnd(); //get parameter switch (Ccmnd) t_memory: { case 'm': if (f_TurnedRight) { turnRight(); } else { turnLeft(); }; break; t_other: case 'o': if (!f_TurnedRight) { turnRight(); } else { turnLeft(); }; break; t_light: case 'l': t_light(); break; t_dark: case 'd': t_dark(); break; t_toLight: case 'L': t_atLight(); break; t_toDark: case 'D': t_atDark(); break; t_unwind: case 'u': t_unwind(); break; t_toHome: case 'H': t_toHome; break; } break; //===================================== //SPEED case 's': if (f_recording) { RecordCcmnd(); } //so 's' is recorded GetCcmnd(); //get parameter switch (Ccmnd) { case '1': // fall through case '2': // fall through case '3': // fall through case '4': // fall through case '5': // fall through case '6': // fall through case '7': // fall through case '8': // fall through case '9': steptime =(Ccmnd-'0') *8; break; // and if recording record Ccmnd case '+': steptime -=1; steptime =max(steptime,stepmin); break; // and if recording record '+' case '-': steptime +=1; break; // and if recording record '-' case 'u': steptime -=1; steptime =max(steptime,stepmin); break; // and if recording record 'u' case 'd': steptime *=2; break; // and if recording record 'd' case 'm': stepmin =steptime; break; // and if recording record 'm' case 's': EEPROM.update(Esteptime,steptime); break; //save // and if recording record 's' default: steptime =defaultsteptime; break; } break; //===================================== //SENSE case '$': if (f_recording) { RecordCcmnd(); } //so '$' is recorded GetCcmnd(); //get parameter switch (Ccmnd) { case 'b': bumpState =2 *digitalRead(Lbump) +digitalRead(Rbump); Serial.print(bumpState); if (!f_react || bumpState==0) {break;} //Serial.println(epage);Serial.println(EEPROMindex); if (!f_reacting) { ReactAt =EEPROMindex; } epage =3; setEEPROMindexes('0' +bumpState); f_reacting =true; //Serial.println(epage);Serial.println(EEPROMindex); break; case 'e': eyesState =2 *analogRead(Leye)>eyeThreshold +analogRead(Reye)>eyeThreshold; Serial.print(eyesState); if (!f_react || eyesState==0) {break;} if (!f_reacting) { ReactAt =EEPROMindex; } epage =3; setEEPROMindexes('3' +eyesState); f_reacting =true; break; case 'l': LDRstate =analogRead(Ch0)>LDRthreshold; Serial.print(LDRstate); if (!f_react || LDRstate==0) {break;} if (!f_reacting) { ReactAt =EEPROMindex; } epage =3; setEEPROMindexes('7'); f_reacting =true; break; case 'c': BarCodeState =analogRead(Ch1)>BarCodeThreshold; //Barcode-reader - Ch1 Serial.print(BarCodeState); if (!f_react) { break; } if (BarCodeState==0 && f_dark) {break;} if (BarCodeState==1 && !f_dark) {break;} if (!f_reacting) { ReactAt =EEPROMindex; } epage =3; setEEPROMindexes('8'); f_reacting =true; break; case '~': if (BClast==0) { BClast =analogRead(Ch1); } //just initialise it BChere =analogRead(Ch1); BCchange =BClast -BChere; BCchange =abs(BCchange); BClast =BChere; Serial.print(BCchange); if (!f_react) { break; } if (BCchange > BCchangemax) { if (!f_reacting) { ReactAt =EEPROMindex; } BClast=0; epage =3; setEEPROMindexes('8'); f_reacting =true; } break; default: badkey(); if (stackCcmnd==0) { Serial.println("bad key sense");} Ccmnd ='?'; //so if recording then '?' is recorded break; } // end switch case $ break; //===================================== //BEHAVES 0Samsrelc$ case 'b': if (f_recording) { RecordCcmnd(); } //so 'b' is recorded GetCcmnd(); //get parameter switch (Ccmnd) { b_default0: case '0': autoAct =EEPROM.read(EautoAct); defaultMove =EEPROM.read(EdefaultMove); break; b_save: case 'S': EEPROM.update(EautoAct,autoAct); EEPROM.update(EdefaultMove,defaultMove); EEPROM.update(EstepScale100hi,stepScale100 /256); EEPROM.update(EstepScale100lo,stepScale100 &255); EEPROM.update(ErotateScale360hi,rotateScale360 /256); EEPROM.update(ErotateScale360lo,rotateScale360 &255); EEPROM.update(EeyeThresholdhi,eyeThreshold /256); EEPROM.update(EeyeThresholdlo,eyeThreshold &255); EEPROM.update(ELDRthresholdhi,LDRthreshold /256); EEPROM.update(ELDRthresholdlo,LDRthreshold &255); EEPROM.update(EBarCodeThresholdhi,BarCodeThreshold /256); EEPROM.update(EBarCodeThresholdlo,BarCodeThreshold &255); break; b_AutoAct: case 'a': if (f_recording) { RecordCcmnd(); } //so 'a' is recorded GetCcmnd(); //get parameter switch (Ccmnd) { case '0': // fall through case '1': // fall through case '2': // fall through case '3': // fall through case '4': // fall through case '5': // fall through case '6': // fall through case '7': // fall through case '8': autoAct =Ccmnd; break; case 'd': f_runDefault =true; break; default: badkey(); Ccmnd='0'; break; } // end switch break; b_MoveDefault: case 'm': if (f_recording) { RecordCcmnd(); } //so 'm' is recorded GetNum(); if (numValue <1 || numValue >200 ) { badkey(); Ccmnd='?'; break; } defaultMove =numValue; break; b_stepscale: case 's': if (f_recording) { RecordCcmnd(); } //so 's' is recorded GetNum(); if (numValue<50 || numValue>380 ) { badkey(); Ccmnd='?'; break; } stepScale100 =numValue; break; b_rotatescale: case 'r': if (f_recording) { RecordCcmnd(); } //so 'r' is recorded GetNum(); if (numValue<340 || numValue>380 ) { badkey(); Ccmnd='?'; break; } rotateScale360 =numValue; break; b_eyeThreshold:case 'e': if (f_recording) { RecordCcmnd(); } //so 'e' is recorded GetNum(); if (numValue<10 || numValue>1000 ) { badkey(); Ccmnd='?'; break; } eyeThreshold =numValue; break; b_LDRthreshold:case 'l': if (f_recording) { RecordCcmnd(); } //so 'e' is recorded GetNum(); if (numValue<10 || numValue>1000 ) { badkey(); Ccmnd='?'; break; } LDRthreshold =numValue; break; b_BCthreshold: case 'c': if (f_recording) { RecordCcmnd(); } //so 'c' is recorded GetCcmnd(); //get parameter switch (Ccmnd) { case 'l': f_dark = false; break; case 'd': f_dark = true; break; default: GetNum(); if (numValue<10 || numValue>1000 ) { badkey(); Ccmnd='?'; break; } BarCodeThreshold =numValue; break; } break; b_SensorReact: case '$': if (f_recording) { RecordCcmnd(); } //so '$' is recorded GetCcmnd(); //get parameter switch (Ccmnd) { case '0': f_react =false; break; case '1': f_react =true; break; default: badkey(); Ccmnd='?'; break; } break; b_Reacting: case '!': if (f_recording) { RecordCcmnd(); } //so '$' is recorded GetCcmnd(); //get parameter switch (Ccmnd) { case '0': f_reacting =false; break; //case '1': f_reacting =true; break; default: badkey(); Ccmnd='?'; break; } break; } // end switch behaviour break; //===================================== //SYSTEM case'*': Serial.print("***");GetCcmnd(); //get parameter switch (Ccmnd) { sys_record: case 'r': f_recordC =false; if (!f_recording) { getAct(); if(Ccmnd=='.') { break; } setEEPROMindexes(Act); f_recording =true; } break; sys_load: case 'l': f_recording =false; loadAct(); break; sys_copy: case 'c': f_recording =false; copyAct(); break; } // end switch system break; //===================================== //PRINT case '?': f_recordC =false; if (!f_recording) { GetCcmnd(); //get parameter switch (Ccmnd) { case 'm': printMind(); break; case 'h': printHelp(); break; // print instructions case 'b': printBehaviour(); break; case '1': // fall through case '2': // fall through case '3': // fall through case '4': // fall through case '5': // fall through case '6': // fall through case '7': // fall through case '8': Act =Ccmnd; printAct(); break; case 'a': f_printAll =true; break; case '0': f_printAll =false; PrintActs0(); break; case '?': PrintAllActs(); break; case 'd': DumpActs(); break; case '!': PrintReActs(); break; case 'f': disp_freeram(); break; case '$': Serial.println(); Serial.print("$b "); Serial.print(" bumpers ="); show_bump(); Serial.print("$e "); Serial.print(" eyes ="); show_eyes(); Serial.print("$l "); Serial.print(" LDR - Ch0 ="); show_light(); Serial.print("$c "); Serial.print(" Barcode-reader - Ch1 ="); show_code(); break; default: badkey(); if (stackCcmnd==0) { printHelp(); Ccmnd='?'; break; } } // end switch } // end if break; default: f_recordC =false; //don't record bad key badkey(); if (stackCcmnd==0) { Serial.println("bad key"); } break; } // end switch //===================================== Record: if (f_recording && f_recordC) { RecordCcmnd(); } } //== END {LOOP} ============================================= //== USER ROUTINES ========================================== void Experiment() //until Quit { while(true) { //put your own routine here e.g. if(Quit()) { break; } } // end while } //---------------------------- void Xplore() //Wander() until Quit { /*while(true) { Wander(); if(Quit()) { break; } } // end while*/ } //== SYSYTEM ============================================== void GetCcmnd() //reads Serial or playing Act until Ccmnd != 0, prints Ccmnd { Ccmnd =0; f_comment =false; do { while(Ccmnd==0) { if (f_recording) { while(!Serial.available()) {} //wait for Serial Ccmnd =Serial.read(); } else //if (!f_recording) { if (Serial.available()) { Ccmnd =Serial.read(); } //over-ride if Serial, null ignored else { if (f_play || f_reacting) { Ccmnd =PlayAct(); } } //get Act or React Ccmnd } //end if (!f_recording) } //end while Ccmnd==0 Serial.print(Ccmnd); if (Ccmnd=='"') { f_comment =!f_comment; } if (f_comment) { Ccmnd =0; } } while (f_comment); if (Ccmnd=='"') { Ccmnd =','; } //don't let " escape } //---------------------------- char PlayAct() { char _Ccmnd =EEPROM.read(EEPROMindex++); return _Ccmnd; } //---------------------------- void setEEPROMindexes(char Act) // set EEPROM pointers { actIndex =Act -'1'; // ASCII to numeric, Act 1 == actIndex 0 EEPROMindex =(256 *epage) +(actIndex*32); ActEnd =EEPROMindex +31; epage =1; //back to default page for next Act number } //---------------------------- void RecordCcmnd() { EEPROM.update(EEPROMindex,Ccmnd); EEPROMindex++; if (EEPROMindex>=ActEnd) { f_recording =false; EEPROM.update(ActEnd,'.'); badkey(); } //terminated string } //---------------------------- int GetNum() { if (!isDigit(Ccmnd) ) { GetCcmnd(); } // needed for bc threshold if ( !isDigit(Ccmnd) ) { numValue =defaultMove; stackCcmnd =Ccmnd; f_recordC =false; } else { numString = ""; do { numString +=Ccmnd; if (f_recording) { RecordCcmnd(); } //so digit is recorded GetCcmnd(); if ( !isDigit(Ccmnd) ) { stackCcmnd =Ccmnd; f_recordC =false; break; } } while (true); numValue =numString.toInt(); numString = ""; } } //---------------------------- void getAct() //called when recording, loading, printing and copying Acts, Ccmnd ->'.', '1' - '8' { Ccmnd =0; do { if(Serial.available()) { Ccmnd =Serial.read(); switch (Ccmnd) { case Esc: Ccmnd ='.'; //[Esc] key, fall through to '.' case '.': Serial.print("."); break; //quit, print . //ready prompt case '!': epage =3; Ccmnd =0; break; //do it again to read Act case '0': epage =0; Ccmnd =0; break; //do it again to read Act case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': Act =Ccmnd; break; default: badkey(); Serial.print(" enter Act or '.'"); Ccmnd =0; } //end case } //end if Serial } while(Ccmnd==0); } //---------------------------- void loadAct() { getAct(); // Ccmnd ->'.' - Quit, // '0' - sets Act0 (or , '!' ReAct) page then gets Act // '1' - '8' - sets Act page'1' - '8', - if (Ccmnd!='.') { setEEPROMindexes(Act); while(true) { while(!Serial.available()) {} Ccmnd =Serial.read(); //wait for Serial if(Ccmnd=='.' || Ccmnd==Esc) { break; } EEPROM.update(EEPROMindex,Ccmnd); EEPROMindex++; if (EEPROMindex>=ActEnd) { badkey(); break; } //ActEnd =EEPROMindex +31; } EEPROM.update(EEPROMindex,'.'); //terminated string } } //---------------------------- void copyAct() { getAct(); if (Ccmnd!='.') { setEEPROMindexes(Act); int fromEEPROMindex =EEPROMindex; int fromActEnd =ActEnd; getAct(); if (Ccmnd!='.') { setEEPROMindexes(Act); for(byte i =0; i<=fromActEnd -fromEEPROMindex; i++) { EEPROM.update(EEPROMindex +i,EEPROM.read(fromEEPROMindex +i)); } } } } //---------------------------- //== SENSORS ============================================== //---------------------------- void show_bump() { Serial.print("LR="); Serial.print(digitalRead(Lbump)); Serial.println(digitalRead(Rbump)); } //---------------------------- void show_eyes() { Serial.print("LR="); Serial.print(analogRead(Leye)); Serial.print(','); Serial.print(analogRead(Reye)); eyesState =2 *analogRead(Leye)>eyeThreshold +analogRead(Reye)>eyeThreshold; Serial.print(' '); Serial.println(eyesState); } //---------------------------- void show_light() { Serial.print(analogRead(Ch0)); Serial.print(','); Serial.print(analogRead(A4)); LDRstate =analogRead(Ch0)>LDRthreshold; Serial.print(' '); Serial.println(LDRstate); } //---------------------------- void show_code() { Serial.print(analogRead(Ch1)); BarCodeState =analogRead(Ch1)>BarCodeThreshold; Serial.print(' '); Serial.println(BarCodeState); } //---------------------------- //== UTILITIES ============================================== //---------------------------- void waitSecs(byte cmnd) //read delay time from Act and wait { if ( cmnd==0 ) { cmnd =10; } delay(cmnd *1000); } //---------------------------- void waitTenthsSecs(byte cmnd) //read delay time from Act and wait { if ( cmnd==0 ) { cmnd =10; } delay(cmnd *100); } //---------------------------- void badkey() // indicate invalid key { tone(Sounder,1000,300); if( Ccmnd=='Q' || Ccmnd=='.' || Ccmnd==Esc || Ccmnd=='#') { stackCcmnd =Ccmnd; } } //---------------------------- boolean Quit() //check for Quit { if( Serial.available() ) { Ccmnd =Serial.read(); } if( Ccmnd=='Q' || Ccmnd=='.' || Ccmnd==Esc || Ccmnd=='#') { return true; } else { return false; } } //--------------------------- /* void WhiskerReact() // "W" read Whisker sensors and avoid obstacles (if any) using avoidObstacles() behaviour rules { readWhiskers(); queryObstaclesLR(); reactObstaclesLR(); } //---------------------------- void BeardReact() // "G" Ground - read Beard sensors and avoid holes (if any) using avoidHoles() behaviour rules { readBeard(); queryEdgeLR(); reactHolesLR(); } */ //---------------------------- void PrintReActs() { Serial.println(); Serial.print("b & e indicates bump or eyes sensed LR"); for(Act ='1'; Act<='8'; Act++) { epage =3; printReAct(); } Serial.println(); } //---------------------------- void printReAct() { Serial.println(); Serial.print("ReAct"); Serial.print(Act); Serial.print(" "); switch (Act) { case '1': Serial.print("b_01"); Serial.print(" "); break; case '2': Serial.print("b_10"); Serial.print(" "); break; case '3': Serial.print("b_11"); Serial.print(" "); break; case '4': Serial.print("e_11"); Serial.print(" "); break; case '5': Serial.print("e_10"); Serial.print(" "); break; case '6': Serial.print("e_01"); Serial.print(" "); break; case '7': Serial.print("LDR "); Serial.print(" "); break; case '8': Serial.print("code"); Serial.print(" "); break; } // end switch setEEPROMindexes(Act); Ccmnd =EEPROM.read(EEPROMindex++); // -1 (=255) is uninitialised EEPROM value while(Ccmnd !='.' && Ccmnd !=-1) { Serial.print(Ccmnd); moves++; Ccmnd =EEPROM.read(EEPROMindex++); } EEPROMindex -=1; //step back to end of record just in case playing Serial.print(". - "); Serial.print(moves); //there are moves which take more than 1 character Serial.print(" bytes"); //so the space taken in EEPROM is really bytes moves =0; } //---------------------------- void DumpActs() //Dump Acts, Acts0, ReActs. Print without names and length { for(Act ='1'; Act<='8'; Act++) { setEEPROMindexes(Act); Serial.println(); Ccmnd =EEPROM.read(EEPROMindex++); // -1 (=255) is uninitialised EEPROM value while(Ccmnd !='.' && Ccmnd !=-1) { Serial.print(Ccmnd); Ccmnd =EEPROM.read(EEPROMindex++); } } for(Act ='1'; Act<='8'; Act++) { epage =0; setEEPROMindexes(Act); Serial.println(); Ccmnd =EEPROM.read(EEPROMindex++); // -1 (=255) is uninitialised EEPROM value while(Ccmnd !='.' && Ccmnd !=-1) { Serial.print(Ccmnd); Ccmnd =EEPROM.read(EEPROMindex++); } } /* for(Act ='1'; Act<='8'; Act++) { epage =3; setEEPROMindexes(Act); Serial.println(); Ccmnd =EEPROM.read(EEPROMindex++); // -1 (=255) is uninitialised EEPROM value while(Ccmnd !='.' && Ccmnd !=-1) { Serial.print(Ccmnd); Ccmnd =EEPROM.read(EEPROMindex++); } }*/ Serial.println(); } //---------------------------- void PrintActs0() { for(Act ='1'; Act<='8'; Act++) { epage =0; printAct(); } Serial.println(); } //---------------------------- void PrintAllActs() { byte currentpage =epage; if (!f_printAll) { for(Act ='1'; Act<='8'; Act++) { epage =currentpage; printAct(); } Serial.println(); } else { for(Act ='1'; Act<='8'; Act++) { epage =1; printAct(); } Serial.println(); for(Act ='1'; Act<='8'; Act++) { epage =0; printAct(); } Serial.println(); } } //---------------------------- void printAct() { Serial.println(); if (epage==3) {Serial.print("ReAct");} else {Serial.print("Act");} // Serial.print("Act"); if(epage==0) { Serial.print('0'); } //for logical page0 Acts Serial.print(Act); Serial.print(" "); setEEPROMindexes(Act); Ccmnd =EEPROM.read(EEPROMindex++); // -1 (=255) is uninitialised EEPROM value while(Ccmnd !='.' && Ccmnd !=-1) { Serial.print(Ccmnd); moves++; Ccmnd =EEPROM.read(EEPROMindex++); } EEPROMindex -=1; //step back to end of record just in case playing Serial.print(". - "); Serial.print(moves); Serial.print(" bytes"); moves =0; } //---------------------------- void printMind() { Serial.println(); Serial.println("**MIND**********"); Serial.print(heading); Serial.println(" heading"); Serial.print(AtX); Serial.println(" AtX"); Serial.print(AtY); Serial.println(" AtY"); Serial.print(moveX); Serial.println(" moveX"); Serial.print(moveY); Serial.println(" moveY"); } //---------------------------- void printBehaviour() { Serial.println(); Serial.println(F("**BEHAVIOUR*****")); Serial.println(thisprog); // so we know which program is running Serial.print(autoAct); Serial.println(F(" autoAct")); Serial.print(f_runDefault); Serial.println(F(" autorun")); Serial.print(steptime); Serial.println(F(" steptime =step cmnd *8")); Serial.print(stepmin); Serial.println(F(" min steptime = fastest speed")); Serial.print(defaultMove); Serial.println(F(" default move mm or degrees.")); Serial.print(stepScale100); Serial.println(F(" stepScale100")); Serial.print(rotateScale360); Serial.println(F(" rotateScale360")); Serial.print(eyeThreshold); Serial.println(F(" eye threshold")); Serial.print(LDRthreshold); Serial.println(F(" LDR threshold")); Serial.print(BarCodeThreshold); Serial.println(F(" BarCode Threshold")); Serial.print(f_dark); Serial.println(F(" 1=ReAct on Dark, 0=ReAct on Light")); Serial.print(f_TurnedRight); Serial.println(F(" 1=last turn was R")); Serial.print(f_react); Serial.println(F(" 0=reacting to sensors is OFF")); } //---------------------------- //== HELP TEXT ============================================== void printHelp() { Serial.println(); Serial.println(F("[Q],[Esc] - stop all")); Serial.println(F("[.] - stop, quit current operation - recording, playing, input")); Serial.println(F("[(] - start of Do")); Serial.println(F("[)] - end of Do")); Serial.println(F("[0] - use page0 for the next cmnd or Act, Acts [0][1] - [0][8]")); Serial.println(F(" page 1 is the default")); Serial.println(F("[!] - use ReActs page")); Serial.println(F("[0] - Acts [!][1] - [!][8]")); Serial.println(F("[1-8] Play act, or the Act to record, copy, load etc")); Serial.println(F("[F]{digits}[,] - Forwards - if no digits then 1")); Serial.println(F("[B]{digits}[,] - Backwards - if no digits then 1")); Serial.println(F("[R]{digits}[,] - turn Right - if no digits then 1")); Serial.println(F("[L]{digits}[,] - turn Left - if no digits then 1")); Serial.println(F("[T]{digits}[,] - turn to heading - if no digits then ignore")); Serial.println(F("[H] - goto 'home'")); Serial.println(F("[D] - Pen down")); Serial.println(F("[U] - Pen up")); Serial.println(F("[V] - beep")); Serial.println(F("[w][0-9,0] - wait seconds, 0=10")); Serial.println(F("[n][0-9,0] - nap tenths second, 0=10")); Serial.println(F("SPEED")); Serial.println(F("[s][1-9] - speed, steptime =speed cmnd *8")); Serial.println(F(" [+] - speed-up, steptime -=1 >=1")); Serial.println(F(" [-] - speed-down, steptime +=1")); Serial.println(F(" [u] - speed-up, steptime -=1 >=stepmin")); Serial.println(F(" [d] - speed-down, steptime *=4")); Serial.println(F(" [m] - set speed-max for speed-up to current speed")); Serial.println(F(" [s] - save speed")); Serial.println(F("TURN")); Serial.println(F("[t][m] - Turn Memory - turn same way as last time")); Serial.println(F(" [o] - Turn Other - turn other way from last time")); Serial.println(F(" [l] - Turn to Light")); Serial.println(F(" [d] - Turn to Dark")); Serial.println(F(" [u] - Turn Unwind")); Serial.println(F("SENSORS")); Serial.println(F("[$][b] - return bumper status")); Serial.println(F(" [c] - return barcodereader value")); Serial.println(F(" [l] - return light value")); Serial.println(F(" [e] - return eyes values")); Serial.println(F("SKILL")); Serial.println(F(" [l] - Turn to Light")); Serial.println(F(" [d] - Turn to Dark")); Serial.println(F(" [L] - Turn at Light")); Serial.println(F(" [D] - Turn at Dark")); Serial.println(F(" [u] - Turn Unwind")); Serial.println(F("[h] - set current location as new 'home'")); Serial.println(F("[H] - goto 'home'")); Serial.println(F("[g][H] - goto 'home'")); Serial.println(F("MIND")); Serial.println(F("[?][m] - print Mind")); Serial.println(F("BEHAVIOUR")); Serial.println(F("[b][0] - Restore default behaviour")); Serial.println(F(" [S] - Save behaviour as default")); Serial.println(F(" [a][1-8] - Act to autorun on power on")); Serial.println(F(" [0] - no autorun")); Serial.println(F(" [d] - if Playing ends, run autorun Act")); Serial.println(F(" [m][digits][,] - default move mm or deg.")); Serial.println(F(" [r][digits][,] - rotatescale, actual steps for 360 degrees")); Serial.println(F(" [s][digits][,] - stepescale, actual steps for 100mm")); Serial.println(F(" [e][digits][,] - eye threshold - low dark")); Serial.println(F(" [l][digits][,] - LDR threshold - low dark")); Serial.println(F(" [c][digits][,] - BarCode threshold - high dark")); Serial.println(F(" [$][0,1] - sensor react 0=off")); Serial.println(F(" [!][0,1] - 0=turn off reacting flag to jump from a ReAct,")); Serial.println(F(" automatically turns on again")); Serial.println(F("SYSTEM")); Serial.println(F("[*][r][0 1-8] - record act, 0 use page0")); Serial.println(F(" [l][0 1-8] - load act, 0 use page0")); Serial.println(F(" [c][0 1-8][0 1-8] - copy act to act, 0 use page0")); Serial.println(F("PRINT")); Serial.println(F("[?][?] - prints all acts")); Serial.println(F(" [0] - prints acts 0, and changes '??' to just print current page")); Serial.println(F(" [a] - '??' prints all acts")); Serial.println(F(" [1-8] - print Act in current page")); Serial.println(F(" [!] - print ReActs")); Serial.println(F(" [b] - print behaviour")); Serial.println(F(" [m] - print Mind")); Serial.println(F(" [d] - dump all acts to PC without descriptions, for reloading")); Serial.println(F(" [$} - print sensors")); Serial.println(F(" [h] - print help")); Serial.println(F(" [f] - print free RAM")); } //=========================================================== /*****************Dan*************************/ // print integer value. void i_printf( int val ) { Serial.print(val); } // print string s1. void s_printf( char *s1 ) { Serial.print(s1); } /*********************************************/ void disp_freeram() { s_printf("-SRAM left: "); i_printf( freeRam() ); } /*********************************************/ int freeRam() { extern int __heap_start,*__brkval; int v; return (int)&v - (__brkval == 0 ? (int)&__heap_start : (int) __brkval); } /*********************************************/