' ************************************************************************** ' * * ' * PICAXE-18 BRAIN FOR CYBOT AXE18TOP * ' * * ' ************************************************************************** ' * * ' * Program AXE18TOP.BAS * ' * * ' * Target PICAXE-18 * ' * Compiler Revolution Programming Editor 2.3.5 * ' * Memory Used 128 bytes of 128 ( None free ) * ' * * ' * Version 1.02 * ' * Created 2002-04-23 * ' * Last Modified 2002-08-03 * ' * * ' * Author The Happy Hippy * ' * Web Site http://www.psynet.net/hippy * ' * * ' * Copyright (C) 2002, The Happy Hippy * ' * * ' ************************************************************************** ' * * ' * DESCRIPTION * ' * * ' * The Brain program selects a random motion and speed which it will * ' * tell the Motor Controller to execute for random lengths of time. * ' * If light is present, a light following mode is enetered. If a * ' * collision occurs, the motors will be stopped immediately, until * ' * the cause of the collision, or Cybot, is removed. * ' * * ' * Keep one of the micro switches closed whilst the collsion or the * ' * Cybot is being moved, as it will return to life immediately the * ' * collision ceases to exist. * ' * * ' * The interface connects to the Motor Controller processor. TX from * ' * the Motor Controller processor comes to RX here. TX from here goes * ' * to RX on the Motor Controller processor and RX on the Motion * ' * Monitoring processor. * ' * * ' * One or more micro switches should be connected between S0 and 0v, * ' * and at least one must close during a collision to prevent the * ' * motor drive transistors being burnt out due to stall currents. * ' * * ' * A left facing Light Dependant Resistor (LDR) should be connected * ' * between S1 and 0v, and a right facing LDR between S2 and 0v. If * ' * the LDR's are not connected, the Cybot will only exhibit random * ' * motion behaviour and not light follwoing. The LDR's may safely * ' * be left off if you don't want the light following mode. * ' * * ' ************************************************************************** ' * * ' * CIRCUIT DIAGRAM * ' * * ' * .-. 22K * ' * PI |O|---.--===--. * ' * PO |O|<--|-------|--. * ' * PG |O|<--|-------|--|---. * ' * `-' `--===--|--|---^------------. * ' * .-. 10K | | | * ' * 5V |O|-----------|--|----------------|----------------. * ' * RX |O|-----------|--|----------. | | * ' * TX |O|<-----. | | | | | * ' * 0V |O|------|----|--|----------|-----{ | * ' * `-' | | | | | | * ' * .-. | | | | | 3 x 10K | * ' * S0 |O|------|----|--|----------|-----|------.---===---{ * ' * S1 |O|------|----|--|----------|-----|----.-|---===---{ * ' * S2 |O|------|----|--|----------|-----|--.-|-|---===---{ * ' * 0V |O|<-----|----|--|----------|-----{ | | | | * ' * `-' | | | | | | | | | * ' * .-------' | | | | | | | | * ' * | .----------' | | | | | | | * ' * | | .-----------' | | | | | 4K7 | * ' * | | | .-------------------|-----|--|-|-|---===---{ * ' * | | | | .-----------------|-----|--' | | | * ' * | | | | | PICAXE-18 | | | | | * ' * | | | | | .---------. | | | | | * ' * | | | | `-->| 1 18 |<--|-----|----' | | * ' * | | `--|-----| 2 17 |<--|-----|------' | * ' * | `----|---->| 3 16 |<--' | | * ' * `---. `---->| 4 15 | | | * ' * .---|--------| 5 14 | | | * ' * | `--------| 6 13 | | | * ' * | | 7 12 | | | * ' * | .-------| 8 11 | | | * ' * | | .---| 9 10 | | | * ' * | | | `---------' | | * ' * | | `---===---. | | * ' * | | 2K2 _|_ | | * ' * | +__|__ \ / LED | __|__ * ' * | --.-- Piezo --.-- | --.-- 100nF * ' * | | | | | * ' * `----^-------------^-------------^----------------' * ' * * ' ************************************************************************** ' * * ' * HISTORY * ' * * ' * 1.00 2002-04-23 First public release * ' * * ' * 1.01 2002-07-22 Corrected "Follwoing" typo * ' * * ' * 1.02 2002-08-03 Added "speedRequired" variable * ' * * ' ************************************************************************** ' * * ' * KNOWN BUGS * ' * * ' * 1.00 2002-04-23 Typo. Won't Compile * ' * * ' * 1.01 2002-07-22 Won't Compile * ' * * ' * 1.02 2002-08-03 None * ' * * ' ************************************************************************** ' ************************************************************************** ' * * ' * Define input pin usage * ' * * ' ************************************************************************** symbol S0 = 0 ' RA0 / A2D0 - Switch 0 symbol S1 = 1 ' RA1 / A2D1 - Switch 1 symbol S2 = 2 ' RA2 / A2D2 - Switch 2 symbol RA6 = 6 ' RA6 symbol RX = 7 ' RA7 - Serial In symbol MICROSWITCH = pin0 ' RA0 / S0 - Collision Microswitch symbol LHSLDR = 1 ' RA1 / S1 - LHS LDR symbol RHSLDR = 2 ' RA2 / S2 - RHS LDR ' ************************************************************************** ' * * ' * Define output pin usage * ' * * ' ************************************************************************** symbol TX = 0 ' RB0 - Serial Out symbol RB1 = 1 ' RB1 symbol PIEZO = 2 ' RB2 - Piezo Transducer symbol LED = 3 ' RB3 - LED symbol RB4 = 4 ' RB4 symbol RB5 = 5 ' RB5 symbol RB6 = 6 ' RB6 symbol RB7 = 7 ' RB7 symbol LEDMSK = %00001000 ' LED Bit Mask ' ************************************************************************** ' * * ' * Define constants * ' * * ' ************************************************************************** symbol BAUD = N2400 ' Maximum baud rate ' These are our possible motions symbol STOP = 0 ' Right Stop + Left Stop symbol TURNFORWARDLEFT = 1 ' Right Fwd + Left Stop symbol TURNFORWARDRIGHT = 2 ' Right Stop + Left Fwd symbol MOVEFORWARD = 3 ' Right Fwd + Left Fwd symbol MOVEBACKWARDS = 4 ' Right Back + Left Back symbol TURNBACKWARDSLEFT = 5 ' Right Back + Left Stop symbol TURNBACKWARDSRIGHT = 6 ' Right Stop + Left Back symbol SPINLEFT = 7 ' Right Fwd + Left Back symbol SPINRIGHT = 8 ' Right Back + Left Fwd symbol STOPFOR10S = 15 ' Stop for 10S ' ************************************************************************** ' * * ' * Define variables * ' * * ' ************************************************************************** symbol synchData = b0 symbol motionRequired = b1 ' Motion required by controller symbol followingSpeed = b2 symbol runCounter = b3 ' LED flash counter symbol runForCount = b4 symbol lhsReading = b5 symbol rhsReading = b6 symbol outputBits = b7 ' Output bits symbol speedRequired = b8 symbol randomNumber = w5 ' w5 = b10::b11 symbol randomHi = b10 symbol randomLo = b11 ' ************************************************************************** ' * * ' * Program Initialisation * ' * * ' ************************************************************************** ' The program starts execution here when the processor is powered up, is ' reset, and after the program has been downloaded. ' ' // ... ' ' The Motor Controller will send its first serial synchronisation byte 5S ' after it is reset, the Brain will respond shortly after that. Start: sound PIEZO,(120,25) ' Issue two high frequency beeps pause 60 sound PIEZO,(120,20) pins = 0 ' Turn all outputs off followingSpeed = %00010000 ' Set 50% starting speed pause 3000 ' Wait until 3S from reset goto WaitForSynchronisationByte ' ************************************************************************** ' * * ' * Main Program Loop * ' * * ' ************************************************************************** ' // ... ' .-----------.-----------.-----------------------. ' | t | t | s | s | m | m | m | m | ' `-----------^-----------^-----------------------' ' ' where t is type, must be 00 or it will be ignored ' s is Speed, 0 = slowest .. 3 = fastest ' m is Motion required, 0 .. 15 ' ' 0 = Stop 7 = Turn Left ' 1 = Forward Left 8 = Turn Right ' 2 = Forward Right ' 3 = Move Forward 9 ..11 = Rotate Left ' 4 = Move Backward 12..14 = Rotate Right ' 5 = Backwards left ' 6 = Backwards Right 15 = Stop for 10S ' ' // ... SendMotionRequired: SEROUT TX,BAUD,(motionRequired) ' // ... WaitForSynchronisationByte: SERIN RX,BAUD,synchData UpdateRandomNumber: random randomNumber UpdateRunningTime: runCounter = runCounter + 1 if runCounter < runForCount then UsePreviousMotionRequired runCounter = 0 ToggleLed: outputBits = outputBits ^ LEDMSK pins = outputBits ChooseSpeed: speedRequired = randomLo & %00110000 if speedRequired <> 0 then ChosenSpeedIsOkay ' If 25% ... speedRequired = %00010000 ' .. force 50% ChosenSpeedIsOkay: ChooseMotion: motionRequired = randomLo // 5 | speedRequired ChooseRunTime: random randomNumber runForCount = randomLo | %00010000 & %01111111 UsePreviousMotionRequired: ' ************************************************************************** ' * * ' * Check For Collision * ' * * ' ************************************************************************** ' If we have a collision, we must stop the motors as soon as we can, or the ' stall current may cause the motor drive transistors to burn out or blow ' up. ' ' We check the micro switch input every loop, and as soon as we see it is ' closed ( input goes low ), we tell the Motor Controller we want to stop ' the motors for 10S. ' ' The motors will remain stopped until the timeout and the collision ceases ' to exist, when the micro switch is opened, whereupon it will continue ' to exhibit its normal behaviour patterns. ' ' Note that 'MICROSWITCH' is defined as 'pin0' in the earlier input bit ' definitions. If we simply defined it as '0', the test would always be ' evaluated as false, and no collision would ever be detected. CheckIfCollision: if MICROSWITCH = 1 then NoCollision motionRequired = STOPFOR10S goto SendMotionRequired NoCollision: ' ************************************************************************** ' * * ' * Check If Light Is Present * ' * * ' ************************************************************************** ' Although we have determined a new motion, or are using a previous motion, ' we must modify our behaviour as soon as we detect the presence of light. ' When light is present we select an entirely different behaviour pattern ' based upon the light inputs. This is an example of 'subsumption' which ' is frequently used in robot behaviour design. ' ' Reading the two analogue inputs takes time, and adds to the overal system ' timing and extends the PWM cycle time. It would be nice to read just one ' of the two inputs on sequential loops ( as the data will not change that ' quickly ), but a shortage of program space prevents that. ' ' We check to see if there is any light present. As the light increases ' light readings drop. The level of 80 we check for, just happened to be ' perfect for my front room during the day, but may need to be adjusted ' for other environments. ' ' A proper algorithm would average out the light readings when it thought ' no light was present to create a dynamically changing threshold which ' would work in all environments. This would require a lot more program ' space than we have. ' ' If no light is presnt, we kick the speed of motion required when doing ' light following. This does not have any effect now, but will cause a ' random speed to be used when the motion request is made when light ' following. Note we only kick the speed when there is no light present ' so light following does not speed up and down too frequently. ' ' Only two speeds are used; 1 (%--01----) and 3 (%--11----), so the Cybot ' will move at 50% or 100% of maximum speed. Note how followingSpeed is ' set in the initialisation, or we would have speeds of 0 (%--00----) ' and 2 (%--10----), 25% and 75%. ReadLightDependantResistors: readadc LHSLDR,lhsReading readadc RHSLDR,rhsReading CheckIfLightPresent: if lhsReading < 80 Then LightIsPresent if rhsReading < 80 Then LightIsPresent NoLightPresent: speedRequired = speedRequired ^ %00100000 goto SendMotionRequired ' ************************************************************************** ' * * ' * Follow The Light * ' * * ' ************************************************************************** ' We know there is light present so we now have to create the motions to ' follow it. ' ' If the light levels are approximately equal, we assume it is directly in ' front of us and head forward. If the light is brighter on the left we go ' left, if it is brighter on the right we go right. ' ' This is one area where the PICAXE-18 wins over the PICAXE-24; because the ' anaolgue is only read as 16 levels, we can do a simple compare to see if ' the two light levels are approximately equal. ' ' Remember that the light level reading drops as the light gets brighter so ' the light is on the left when the lhsReading is less than the rhsReading, ' and on the right when rhsReading is less than the lhsReading. ' ' Having determined the motion to make, we add in the speed required we ' wish to go at. This adds some variety to the behaviour. We add the speed ' after setting the motionRequired, rather than at the same time, as this ' saves code space. ' ' Once we have determined the motion and speed required, we tell the Motor ' Controller processor what we want it to do. LightIspresent: if lhsReading = rhsReading then LightIsAtTheFront if lhsReading < rhsReading then LightIsOnTheLeft LightIsOnTheRight: motionRequired = TURNFORWARDRIGHT goto AddSpeedRequired LightIsOnTheLeft: motionRequired = TURNFORWARDLEFT goto AddSpeedRequired LightIsAtTheFRont: motionRequired = MOVEFORWARD AddSpeedRequired: motionRequired= motionRequired | followingSpeed goto SendMotionRequired ' ************************************************************************** ' * * ' * End of source code * ' * * ' **************************************************************************