; PICBOT II software for LF84 ; Version 1.20 March 24, 1999 ; for Parallax SPASM assembler ; Made by Terry Newton device PIC16F84, RC_OSC, WDT_ON, PWRT_ON pgoptions = 11100111b ; program options... ; bit 0 1=learned responses, 0=fixed responses ; bit 1 1=switch to fixed responses when power is low ; bit 2 1=use last action to select memory (banking/feedback) ; bit 3 1=use dark bits to select memory (expand environment) ; bit 4 1=use lastbad/lastbad2 bits to select memory ; bit 5 1=use "gamma" routine ; bit 6 1=relax bad moves if previous environments bad ; bit 7 1=anti-circle, raise badmove if too many of same move ; Ex. 01100111b = relax, gamma, bankmem, fixediflow, learned pops = 20 ; pops per cycle popdur = 45 ; x ontime+offtime ontime = 1 ; duty cycle = offtime = 1 ; ontime/(ontime+offtime) maxsleep = 180 ; number of looks before waking in unchanging env. maxconfidence = 3 ; maximum confidence memories can attain (0-3) calibrateL = 10 ; delays for photocell read routine calibrateR = 10 ; more for dim light, less for bright darkthresh = 90 ; transition from 00 to 11 when cells equal phdiffmask = 01111000b ; mask for equalising raw values when ; comparing L to R - if difference falls in ; the '0' bits then counted as equal light optsleep = 10001111b ; internal rtc, max wdt, no pullups optpause = 10001100b ; bits 0-2 control pause between pops maxsame = 7 ; maximum identical moves to tolerate (if anticircle) ; Port assignments RightFeelPin = ra.0 RightPhotocell = ra.1 LeftPhotocell = ra.2 LeftFeelPin = ra.3 PowerPin = rb.0 StatusLED = rb.1 ; rb.2 = left motor + (rev) ; rb.3 = left motor - (for) ; rb.4 = right motor - (rev) ; rb.5 = right motor + (for) LMRev = 2 LMFor = 3 RMRev = 4 RMFor = 5 forward = 00101000b reverse = 00010100b right = 00001000b ; left motor forward left = 00100000b ; right motor forward revright = 00000100b ; left motor reverse revleft = 00010000b ; right motor reverse spnright = 00011000b ; left forward, right reverse spnleft = 00100100b ; right forward, left reverse popcnt = 10h ; variable for counting pops flags = 11h ; flags collection... badenv = flags.0 ; set if something bad in environment badmove = flags.1 ; set if something wrong with action sleeping = flags.2 ; set if in deepsleep watching = flags.3 ; set if in watch mode popping = flags.4 ; set if in a pop cycle lastbad = flags.5 ; set if last environment was bad lastbad2 = flags.6 ; set if environment before that was bad eevalid = flags.7 ; set if last move was remembered ; (don't penalise for what it didn't do!) environment = 12h ; environment byte leftfeeler = environment.0 rightfeeler = environment.1 lightonleft = environment.2 lightonright = environment.3 darkonleft = environment.4 ; if selected darkonright = environment.5 gammamask = 00000011b ; important bits - feelers action = 13h confidence = 14h LightL = 15h LightR = 16h loops = 17h loops2 = 18h optionflags = 19h ; program options... learningmode = optionflags.0 fixedlowpwr = optionflags.1 bankmem = optionflags.2 expandenv = optionflags.3 usebadbits = optionflags.4 usegamma = optionflags.5 relaxmoves = optionflags.6 anticircle = optionflags.7 temp = 1Ah temp1 = 1Bh temp2 = 1Ch temp3 = 1Dh uncertainity = 1Eh ; not sure what's in this register boring = 1Fh ; increments if move is same as last move lastaction = 20h ; ; start flow ; org 000h reset mov !OPTION, #optsleep ; max wdt clrb rp0 ; reset page bit clr intcon ; no interrupts at all mov !ra, #00001111b mov !rb, #00000001b ; set port i/o bits clr ra ; clr rb ; clear motor outs jnb status.3, rest ; go if waking from sleep clr flags ; clear flags clr boring rest jb popping, nextpop ; jump if in middle of a pop cycle jb powerpin, watch ; become alert if enough power setb sleeping ; otherwise set deepsleep flag mov !OPTION, #optsleep ; long duration sleep ; sleep and keep on charging jmp reset watch ; charge until something changes or counter runs out jnb sleeping, wakeup ; if not in deepsleep, continue on jb watching, watch1 mov popcnt, #maxsleep ; set up max delay before waking setb watching ; set flag so it branches around watch1 mov temp, environment ; save last environment call getenvironment ; look around jb badenv, wakeup ; wake if bad environment cjne temp, environment, wakeup ; wake if change in env. djnz popcnt, doze ; wake if count runs out jmp wakeup doze sleep ; else sleep and charge jmp reset wakeup mov popcnt, #pops ; set up pop counter clrb sleeping ; not sleeping anymore clrb watching ; or watching poploop ; ==================================================== ; behavior code here call getenvironment ; look around snb badenv call longflash ; flash if bad environment mov optionflags, #pgoptions ; set program options ; do selected algorithm... jnb learningmode, fixed jnb fixedlowpwr, learned jb PowerPin, learned ; fixed if power low unless jnb badenv, fixed ; a challenging obstacle jb lastbad, learned ; is encountered jb lastbad2, learned ; ; hard-coded responses... ; fixed clrb eevalid ; no penalty later if it doesn't work jnb leftfeeler, popahead jb rightfeeler, popback popahead jb leftfeeler, spinright jb rightfeeler, spinleft jb lightonleft, popleft jb lightonright, popright mov action, #forward jmp drive popleft mov action, #left jmp drive popright mov action, #right jmp drive popback mov action, #reverse jb lightonleft, rvright jb lightonright, rvleft jmp drive rvleft mov action, #revleft jmp drive rvright mov action, #revleft jmp drive spinleft mov action, #spnleft jmp drive spinright mov action, #spnright jmp drive ; ; learning with memory... ; learned jnb eevalid, remember ; no unfair penalties jb badmove, decrease ; decrease conf. if bad move jnb badenv, increase ; if new env good, increase conf. jb lastbad, decrease ; else if last env or one before jb lastbad2, decrease ; that bad decrease confidence jmp increase ; else increase conf. increase inc confidence ; reward working moves csne confidence, #maxconfidence ; if confidence reaches max call gamma ; do gamma routine cjbe confidence, #maxconfidence, storemem ; write if <=max jmp remember ; else next move decrease dec confidence ; discourage non-working moves jnb confidence.7, storemem ; write if >= 0 otherwise... scramble dec uncertainity ; random delay based xor uncertainity, lightL ; on several factors xor uncertainity, lightR xor uncertainity, popcnt xor uncertainity, flags mov temp, uncertainity scr1 dec temp jnz scr1 ; delay by chosen amount xor eedata, tmr0 ; scramble with timer bits jnb eedata.2, as1 ; anti-smoke jb eedata.3, scramble as1 jnb eedata.4, as2 jb eedata.5, scramble as2 cje eedata, #0, scramble ; anti-still mov confidence, #0 ; confidence 0 for new memory storemem and eedata, #11111100b or eedata, confidence ; combine action and confidence call writememory ; write it call shortflash ; short flash when randomising remember mov eeadr, environment ; address a memory jnb bankmem, remem2 ; if bankmem selected movb eeadr.4, eedata.6 ; use 2 bits of last memory to movb eeadr.5, eedata.7 ; select 1 of 4 16 mem banks remem2 jnb usebadbits, remem3 ; if usebadbits selected movb eeadr.4, lastbad ; select using previous movb eeadr.5, lastbad2 ; environment bad flags remem3 call readmemory mov action, eedata mov confidence, eedata and confidence, #00000011b ; conf. bits 0,1 and action, #00111100b ; motor bits 2-5 ; set badmove flag if going the wrong way or not at all clrb badmove csne action, #0 setb badmove ; set if action = 0 (empty memory) jb badenv, moveok ; skip checks if environment bad jnb relaxmoves, chk4bm ; if relax option enabled jb lastbad, moveok ; skip checks if either last jb lastbad2, moveok ; or previous env. bad chk4bm snb action.LMrev setb badmove snb action.RMrev setb badmove ; set if either motor in reverse jb action.LMfor, moveok jb action.RMfor, moveok setb badmove ; set if neither motor going forward moveok setb eevalid ; flag as a remembered move ; anti-circle code jnb anticircle, acend mov temp, action and temp, #00111100b cjne temp, lastaction, ac1 inc boring cjb boring, #maxsame, ac2 setb badmove jmp ac2 ac1 clr boring ac2 mov lastaction, action and lastaction, #00111100b acend ; ==================================================== ; move robot with move in action drive mov temp, #popdur ; how much drloop mov w, rb and w, #11000011b or w, action mov rb, w ; activate motors with action mov loops, #ontime call wait mov w, rb and w, #11000011b mov rb, w ; motor off (without led off) mov loops, #offtime call wait djnz temp, drloop ; loop until done drstop setb popping ; tell startup we're in a move cycle mov !OPTION, #optpause ; shorten delay sleep ; sleep between pops to save power jmp reset nextpop ; here if wakes with popping set clrb popping ; end of move cycle djnz popcnt, poploop ; next pop mov !OPTION, #optsleep ; long duration sleep ; rest and charge jmp reset ; subroutines ; get environment byte subroutine getenvironment clr environment ; start all bits clear sb leftfeelpin ; set feeler bits setb leftfeeler ; pins low=touching sb rightfeelpin ; env high=touching setb rightfeeler ; read photocells mov lightL, #127 ; max light level mov !ra, #00001011b ; make L photobit an out clr ra ; short out cap mov loops, #10 ; for few ms call wait mov !ra, #00001111b ; make ins again ploopL jb ra.2, readR ; go on when input goes high mov temp1, #calibrateL Ldly1 djnz temp1, Ldly1 ; delay loop for photodiodes djnz lightL, ploopL ; loop if still above 0 readR mov lightR, #127 mov !ra, #00001101b clr ra mov loops, #10 call wait mov !ra, #00001111b ploopR jb ra.1, readend mov temp1, #calibrateR Ldly2 djnz temp1, Ldly2 djnz lightR, ploopR readend ; mask noise and lightL, #phdiffmask and lightR, #phdiffmask ; set environment bits jnb expandenv, sete2 ; if expand environment selected csa lightL, #darkthresh setb darkonleft csa lightR, #darkthresh setb darkonright sete2 csbe lightL, lightR ; if left > right setb lightonleft ; set lightonleft flag csbe lightR, lightL ; if right > left setb lightonright ; set lightonright flag ; if equal, determine if light or dark jb lightonleft, geeval jb lightonright, geeval cjbe lightL, #darkthresh, geeval setb lightonright ; if equal and bright light setb lightonleft ; set both light bits geeval ; set bad-environment flag movb lastbad2, lastbad movb lastbad, badenv clrb badenv mov w, environment and w, #00000011b ; isolate feelers sz ; if either touching setb badenv ; set badenv flag gend ret ; "gamma" subroutine... uses temp, temp1, temp2, temp3 ; spreads current memory to similar memories with conf=0 gamma jnb usegamma, gammaend ; if selected mov w, eeadr and w, #gammamask jz gammaend ; if important mov temp2, eedata ; save original data mov temp3, eeadr ; and address mov temp, eeadr and temp, #gammamask ; reduce address to important bits mov eeadr, #00111111b ; start at the top gammaloop mov temp1, eeadr and temp1, #gammamask cjne temp1, temp, gammanext ; if similar call readmemory and eedata, #00000011b jnz gammanext ; and if conf = 0 mov eedata, temp2 ; transfer memory and eedata, #11111100b ; confidence 0 call writememory setb StatusLED mov loops, #10 call wait clrb StatusLED ; flicker when in gamma gammanext djnz eeadr, gammaloop ; next address mov eedata, temp2 ; restore original data mov eeadr, temp3 ; and address gammaend ret ; wait routine - waits approx loops milliseconds ; (not calibrated at all) wait movlw 50 movwf loops2 wait2 nop nop nop decfsz loops2 goto wait2 decfsz loops goto wait clr wdt ; convenient ret ; read eeprom memory readmemory setb rp0 ; bank 1 setb eecon1.0 ; set read bit clrb rp0 ; bank 0, data in eedata ret ; write eedata to eeprom writememory and eeadr, #00111111b ; ensure address is in range setb rp0 ; bank 1 bsf eecon1, 2 ; enable write movlw 55h movwf eecon2 movlw 0AAh movwf eecon2 ; write seq. to eecon2 bsf eecon1, 1 ; initiate write eewait jb eecon1.1, eewait ; wait for it to happen clrb eecon1.5 ; clear flag clrb rp0 ; bank 0 ret ;debug subs shortflash setb statusLED mov loops, #30 call wait clrb statusLED mov loops, #60 call wait ret longflash setb statusLED mov loops, #60 call wait clrb statusLED mov loops, #30 call wait ret ; clear out eedata... org 2100h ds 64 ; end of source