; Bit-Net controller for a microcore walking robot ; PIC16C54 source code for the Parallax assembler ; by Terry Newton, last modified Apr 27, 1998 ; ; Simpler version for use with hardware timers, ; runs whenever microcore runs otherwise sleeps. ; ; *** set to PIC device, 54 or 56 *** device PIC16C54, RC_OSC, WDT_ON, PROTECT_OFF reset startup ; behaviour masks... BadInBits = 11000001b ; bad environment bits BadOutBits = 00100001b ; bad out bits with good environment ; drive constants TimeMax = 120 ; max control cycles per action cycle TimeMin = 60 ; minimum control cycles (time out = 0) EffectStart = 100 ; starting counter for each control cycle EffectMax = 14 ; maximum control duty cycle (% if start=100) EffectNorm = 7 ; normal control strength when effect outbit = 0 Discharge = 40 ; ms to discharge photo input caps ; port masks PortAMask = 00000011b ; bit 0-1 inputs, bit 2-3 out PortARst = 00000000b ; for clearing both analog ins PortARst1 = 00000010b ; for clearing analog in 1 PortARst2 = 00000001b ; for clearing analog in 2 PortBMask = 00001101b ; bit 1 4-7 outs, bits 2-3 ins, 0=in PortBHiZ = 11111101b ; for hi-z state (no control) PortBStat = 11111100b ; make bit 0 out for status/reset ; pin assignments... ; analog inputs, 8 bit resolution (cell to +, .1u or .2u to gnd) AnaIn_1 = ra.0 ; L Photo AnaIn_2 = ra.1 ; R Photo ; digital inputs, active low (ground) DigIn_1 = rb.2 ; L Feeler DigIn_2 = rb.3 ; R Feeler ; outputs Reverse = rb.1 ; to reversal circuit (active low) Node_1 = rb.4 ; Node_2 = rb.5 ; to microcore in nodes Node_3 = rb.6 ; thru 1M resistors Node_4 = rb.7 ; StatusLED = rb.0 ; for debugging, hiz or high ; RAM assignment... statby = 03h ; PIC status byte TempSave = 07h ; stolen Port C reg Environment = 08h ; current environment buffer NetInput = 09h ; BN input nodes... ; input bit names Feeler_L = 0 ; left whisker Dark_L = 1 ; darkness on left Photo_L = 2 ; more light on left than right Photo_M = 3 ; left about equal to right Photo_R = 4 ; more light on right than left Dark_R = 5 ; darkness on right Feeler_R = 6 ; right whisker Feeler_F = 7 ; forward sensor (really Feeler_L AND Feeler_R) PhotoBitsI = 11100011b ; to mask photo bits (saves a byte...) NetOutput = 0Ah ; BN output nodes... ; output bit names revbit = 0 ; reverse out node1 = 1 ; individual node outs node2 = 2 node3 = 3 node4 = 4 effect = 5 ; increase control effect time = 6 ; increase action cycle time VarA = 0Bh ; GP variables VarB = 0Ch VarC = 0Dh VarD = 0Eh VarE = 0Fh ; Activation bit-matrix Matrix0 = 10h ; reverse Matrix1 = 11h ; node 1 Matrix2 = 12h ; node 2 Matrix3 = 13h ; node 3 Matrix4 = 14h ; node 4 Matrix5 = 15h ; effect Matrix6 = 16h ; time Loops = 17h ; for time delay Loops2 = 18h ; temp delay var BeforeLastE = 1Ah ; environment before last BeforeLastO = 1Bh ; output before last Temp = 1Ch ; temp variables Temp1 = 1Dh Flags = 1Eh ; collection of bits for... Train = Flags.0 ; Apply training signal BadInput = Flags.1 ; Input contains undesirable bits LastBad = Flags.2 ; bad input flag of last cycle BeforeLast = Flags.3 ; and the cycle before that (maybe 1 more level?) RandBit = Flags.4 ; for random bit generator NetRunning = Flags.5 ; for net watcher TempF = Flags.6 ; temp flag RandShift = 1Fh ; for random number generator ; page 0 subroutines... Wait ; delay about Loops milliseconds (note: VERY approximate!) movlw 150 ; calibrate here if needed movwf Loops2 wait2 nop nop nop decfsz Loops2 goto wait2 decfsz Loops goto wait clr wdt ; no time out ret ; sub for generating random bit in RandBit ; This needs work! (not so bad now but still ???) random movb Temp.0, RandShift.6 movb Temp1.0, RandShift.7 xor Temp, Temp1 movb c, /temp.0 rl RandShift clrb RandBit snb RandShift.0 setb RandBit ret ; sub to flash LED with contents of W, on lsb-msb off ; modified... high/low start, 8 data bits, low stop (long) ; easier to pick off a data cable to a PC LEDflash mov Temp, w mov !rb, #PortBStat setb statusLED mov loops,#100 ; start bit high call wait mov !rb, #PortBHiZ mov loops,#100 ; start bit low call wait mov Temp1, #8 LEDfla2 mov !rb, #PortBHiZ jnb Temp.0, LEDfla3 mov !rb, #PortBStat setb statusLED ; LED bits 0 to 7 LEDfla3 mov loops,#100 call wait rr Temp djnz Temp1, LEDfla2 mov !rb, #PortBHiZ mov loops,#255 call wait ; long stop bit 0 ret GetEnvironment ; Process the environment - read digital and quasi-analog inputs and ; form a collection of feature bits to present to the bit-net clr VarA clr VarB clr Environment ; start all environment bits 0 ; get photo input values one cell at a time ; each two passes, dark flags set to overflow mov !ra, #PortARst1 clrb AnaIn_1 ; discharge cap for photo L mov loops, #Discharge call wait mov !ra, #PortAMask ; back to input state G1loop dec VarA jz G1dark jnb AnaIn_1, G1loop jmp G2start G1dark jb Environment.Dark_L, G2start setb Environment.Dark_L jmp G1loop G2start mov !ra, #PortARst2 clrb AnaIn_2 ; discharge cap for photo R mov loops, #Discharge call wait mov !ra, #PortAMask G2loop dec VarB jz G2dark jnb AnaIn_2, G2loop jmp Gproc G2dark jb Environment.Dark_R, Gproc setb Environment.Dark_R jmp G2loop Gproc mov Temp, VarA mov Temp1, VarB cja Temp, #240, Gproc1 ; if either photo <= 240 cja Temp1, #240, Gproc1 and Temp, #11111000b ; mask off lower bits and Temp1, #11111000b Gproc1 csbe Temp, Temp1 setb Environment.Photo_L ; set photo_L if 1 > 2 csbe Temp1, Temp setb Environment.Photo_R ; set photo_R if 1 < 2 csne Temp1, Temp setb Environment.Photo_M ; set photo_M if 1 = 2 ; limit input space... (no more than two inputs set at once) jnb Environment.Dark_L, noDD ; don't set both sides to dark jnb Environment.Dark_R, noDD clrb Environment.Dark_L clrb Environment.Dark_R noDD jb Environment.Dark_L, noDL0 ; don't set photos if either dark jnb Environment.Dark_R, noDL1 noDL0 and Environment, #PhotoBitsI noDL1 movb Environment.Feeler_L, /DigIn_1 ; set feeler_L to inverted dig1 in movb Environment.Feeler_R, /DigIn_2 ; same for feeler_R jnb Environment.Feeler_L, noFF ; if both feelers, clear L and R jnb Environment.Feeler_R, noFF ; and set feeler_F clrb Environment.Feeler_L clrb Environment.Feeler_R setb Environment.Feeler_F noFF ; analyse inputs and set BadInput flag clrb BadInput mov w, Environment and w, #BadInBits sz setb BadInput ret ; train the net... (subroutine) TrainNet xor RandShift, RTCC ; start 'random' mov FSR, #Matrix0 ; start of bitnet matrix bytes, out loop clr VarB ; for each output bit... mov VarE, #00000001b ; rotating output bit mask Tloop clr VarA ; for each input bit... mov VarD, #00000001b ; rotating input bit mask Tloop1 call random ; get random RandBit mov Temp, 0 ; Temp = matrix byte (out) jnb RandBit, Tloop2 ; if random chance... mov w, NetInput and w, VarD jz Tloop2 ; if NetInput(in) = 1... clrb TempF mov w, NetOutput and w, VarE sz setb TempF ; save NetOutput(out) in TempF mov Temp1, VarD not Temp1 ; Temp1 = inverted input bit mask and Temp, Temp1 ; turn off matrix bit jb TempF, Tloop2 or Temp, VarD ; if TempF not set, set matrix bit Tloop2 mov Temp1, #BadOutBits and Temp1, VarE jz Tupdate ; if output is a badbit... mov Temp1, #BadInBits and Temp1, VarD jnz Tupdate ; if input is NOT a badbit... mov Temp1, VarD not Temp1 ; Temp1 = inverted input bit mask and Temp, Temp1 ; turn off matrix bit Tupdate mov 0, Temp ; update matrix clc rl VarD ; rotate input bit mask left inc VarA cjne VarA, #8, Tloop1 ; next input bit clc rl VarE ; rotate output bit mask left inc FSR inc VarB cjne VarB, #7, Tloop ; next out bit ret ; sleep mode - stop net cycling and wait until disturbed Sleep mov !rb, #PortBHiZ ; let go, net stopped ; pattern 10101010 mov w, #10101010b call LEDflash ; dump bitnet to LED... mov FSR, #Matrix0 mov VarC, #7 dump mov w, 0 call LEDflash inc FSR djnz VarC, dump ; pattern 01010101 mov w, #01010101b call LEDflash mov VarE, rb ; save port pins Sleep2 mov option, #00001110b ; about a second sleep ; go to sleep Sleep3 mov !rb, #PortBHiZ ; make ports inputs cje VarE, rb, Sleep2 ; keep sleeping until pins change Wakeup setb statby.3 ; set in case wdt times out jmp start0 ; come alive! ; ***** code execution starts here ***** startup jnb statby.3, Sleep3 ; timeout from sleep start0 mov OPTION, #00001111b ; int rtc, max wdt (!OPTION for SPASM) mov !ra, #PortAMask ; set the A port direction bits mov ra, #00001100b ; make unused pins high (were eeprom) mov !rb, #PortBHiZ ; and the B port bits to no control setb Reverse ; forward march! call GetEnvironment ; look around clrb LastBad ; clear flags and net nodes clr NetInput clr NetOutput mainloop movb BeforeLast, LastBad ; save lastbad flag movb LastBad, BadInput ; save bad input flag mov BeforeLastE, NetInput ; save env before last mov BeforeLastO, NetOutput ; and the response mov NetInput, Environment ; set the input nodes ; evaluate the bit-net... clr NetOutput mov w, NetInput and w, Matrix0 sz setb NetOutput.0 mov w, NetInput and w, Matrix1 sz setb NetOutput.1 mov w, NetInput and w, Matrix2 sz setb NetOutput.2 mov w, NetInput and w, Matrix3 sz setb NetOutput.3 mov w, NetInput and w, Matrix4 sz setb NetOutput.4 mov w, NetInput and w, Matrix5 sz setb NetOutput.5 mov w, NetInput and w, Matrix6 sz setb NetOutput.6 ; for debugging mov w, NetOutput call LEDflash ; flash the output bits ; control the nervous net with bit-net output... movb Reverse,/NetOutput.revbit ; update reverse out mov VarA, #TimeMax ; cycles per period jb NetOutput.time, PLoop1 mov VarA, #TimeMin ; decrease if time bit not set Ploop1 mov !rb, #PortBHiZ ; start each cycle all hiz mov VarC, #EffectStart ; duty cycle counter ; set duty cycle according to Effect output mov VarB, #EffectMax ; max allowed duty cycle jb NetOutput.effect, PLoop2 mov VarB, #EffectNorm ; decrease if effect bit not set PLoop2 cjne VarC, VarB, PL3 ; go if countdown <> duty cycle mov VarD, #PortBHiZ jnb NetOutput.node1, PL2A ; set out dir bits and VarD, #11101110b ; for each set nodeout bit PL2A jnb NetOutput.node2, PL2B ; (and bit 0 status LED) and VarD, #11011110b PL2B jnb NetOutput.node3, PL2C and VarD, #10111110b PL2C jnb NetOutput.node4, PL2D and VarD, #01111110b PL2D mov !rb, VarD ; set direction bits setb StatusLED clrb Node_1 ; set node outs to low clrb Node_2 clrb Node_3 clrb Node_4 PL3 mov loops, #1 call wait ; delay djnz VarC, Ploop2 ; check for next effect value mov !rb, #PortBHiZ ; back to no control ; exit action loop if anything touches the feelers jb Environment.Feeler_L, PL3A jb Environment.Feeler_R, PL3A jb Environment.Feeler_F, PL3A ; don't check if already was touching jnb DigIn_1, PL3B jnb DigIn_2, PL3B ; exit early if either feeler in goes low PL3A djnz VarA, Ploop1 ; do enough times to have an effect PL3B ; see if net is still running.... mov Temp, #100 mov VarE, rb clrb NetRunning ChkNet cse VarE, rb setb NetRunning ; set flag if change mov loops, #5 call wait ; delay each cycle (total about half seconds) djnz Temp, ChkNet jb NetRunning, NetOK ; go if running jmp Sleep ; go to sleep if net stopped NetOK ; evaluate the results of last move (modified to remember back 2 moves) call GetEnvironment ; see what's up clrb Train ; start in a good mood jb LastBad, Eval1 ; if lastbad = 0 (the one in NetInput) mov w, NetOutput and w, #BadOutBits sz ; if bad output setb Train ; set Train flag Eval1 jb LastBad, Eval2 ; if lastbad = 1 jb Beforelast, Eval2 ; or beforelast = 1 jmp Eval3 Eval2 snb BadInput ; if bad input in current environment setb train ; set train flag Eval3 jnb Train, mainloop ; loop if no training to do mov w, #11111111b call LEDflash ; solid flash to indicate training call TrainNet ; train net with current pattern jnb BeforeLast, Eval4 ; if BeforeLast flag set mov TempSave, NetInput ; to restore mov BeforeLastE, NetInput mov BeforeLastO, NetOutput call TrainNet ; train with previous pattern mov NetInput, TempSave ; restore last env Eval4 jmp mainloop ; end of code