Light following and collision detection combination
ltmhall
Posts: 102
···I’m designing a robot that will roam towards a light source placed in front of it. It will also be
designed to maneuver around objects in its path using collision detection. The light circuit will
consist of three photo-resistor’s (photo-resistors in parallel with 0.01ufd capacitors)·placed on
the front side of the robot (currently I only have two on the robot, but I plan on adding a third).
·
··············· ·\······· /·······
············· 45 \ 90 / 45······
············
···· Top view showing angles of how the photo-resistors will be·positioned on the robot.
··············· ·top view·······
·
· The problem I have is deciding how to maneuver the robot when the photo-resistors don’t sense
the light source. For instance, if the robot senses the light and moves towards it. Along the way the
robot collides into an object and the left micro-switches is pressed. The robot will move backwards
and then turn left (the left turn is 90 degrees for my robot). Afterwards, the robot is now positioned
away from the light source and their in lies the problem. I tried having the robot stop, make 90 degree
turn and then take a measurement and then see if there is light, and it seemed to work when the robot
was within 3 ft of the light source. However, when the robot was further away it wouldn’t sense the light
and all it would do is turn in circles.
·* Any help would be appreciated !
·
·
' {$STAMP BS2}········································ ·' Stamp directive.
' {$PBASIC 2.5}·········································· ' PBASIC directive
LeftAmbient CON 120
RightAmbient CON 122
LeftBright CON 10
RightBright CON 10
' Average Scale factor
LeftThreshold CON LeftBright + LeftAmbient / 2 * 5 / 8
RightThreshold CON RightBright + RightAmbient / 2 * 5 / 8
'
[noparse][[/noparse] Variables ]
' Declare variables for storing measured RC times of the
' left & right photoresistors.
timeLeft VAR Word
timeRight VAR Word
'
[noparse][[/noparse] Main Routine ]
DO
GOSUB Test_Photoresistors
GOSUB Navigate
GOSUB Test_Switches
LOOP
[noparse][[/noparse] Subroutine - Test_Photoresistors ]
Test_Photoresistors:
HIGH 3·················································' Left RC time measurement.
PAUSE 3
RCTIME 3,1,timeLeft·
HIGH 4················································ ' Right RC time measurement.
PAUSE 3
RCTIME 4,1,timeRight
RETURN
'
[noparse][[/noparse] Subroutine - Navigate ]
Navigate:
IF (timeLeft < LeftThreshold) AND (timeRight < RightThreshold) THEN
PULSOUT 15, 850····························· ·' Both detect flashlight beam,
PULSOUT 14, 650····························· ·' full speed forward.
ELSEIF (timeLeft < LeftThreshold) THEN···· ' Left detects flashlight beam,
PULSOUT 15, 700······························ ·' move left.
PULSOUT 14, 700
ELSEIF (timeRight < RightThreshold) THEN·· ' Right detects flashlight beam,
PULSOUT 15, 800······························· ·' move right.
PULSOUT 14, 800
ELSE
PULSOUT 15, 750······························ ·‘ * THIS IS WHERE THE PROBLEM IS, WHEN NO··············
·PULSOUT 14, 750···························· · ‘·· LIGHT IS SEEN····················· ·····
ENDIF
PAUSE 20···············································' Pause
RETURN
[noparse][[/noparse] Subroutine - Switches ]
GOSUB Test_Switches:
IF (IN5 = 0) THEN······························· ·' Left switch contacts
GOSUB Back_Up ·································· ' Back up & turn left
GOSUB Turn_Left
ELSEIF (IN7 = 0) THEN···················· ·· ' Right switch contacts
GOSUB Back_Up··································· ' Back up & turn right
GOSUB Turn_Right
ELSE
ENDIF
RETURN
[noparse][[/noparse] Subroutine - Other ]
·
Turn_Left:·············································· ' Left turn, about 90-degrees.
FOR pulseCount = 0 TO 20
PULSOUT 15, 650
PULSOUT 14, 650
PAUSE 20
NEXT
RETURN
Turn_Right:
FOR pulseCount = 0 TO 20···················· ' Right turn, about 90-degrees.
PULSOUT 15, 850
PULSOUT 14, 850
PAUSE 20
NEXT
RETURN
Back_Up:·································· ········· ··' Back up.
FOR pulseCount = 0 TO 40
PULSOUT 15, 650
PULSOUT 14, 850
PAUSE 20
NEXT
RETURN
·
·
Comments
Then, I would make some changes to the FSM used for following light so that the defined states "remember" the last direction and mode that the light sensors were in. This gives you a way to, say, move in a larger-radius circle towards the last "known" or "remembered" direction that you had some decent light. A conceptual flow chart might go something like this:
- light L bigger? go left -> set "memory" bit left
- light R bigger? go left -> set "memory" bit right
- average light below some pre-defined threshold?
no -> go to top
yes -> circle wide (maybe 20" radius) in last "memory" direction -> set timeout
timeout? bail on light following until your threshold is high again
The demo Sumobot code by Parallax also has a simple version of the above scenario (if one IR detector acquires the target, the bot stores the "last" direction it saw the target at, so that if both detectors "lose" the target, the 'bot makes a best guess to circle widely in that last "known" direction").
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
When the going gets weird, the weird turn pro. -- HST
on FSM's ?
www.parallax.com/dl/docs/prod/sic/AppliedSumo-v1.0.pdf
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
When the going gets weird, the weird turn pro. -- HST
and all it would do is turn in circles."
Replace the photo sensors with light to frequency chips (sold here at parallax) Your robot will be able to find a light cigar in a dark room, not kidding those chips are amazing. I found a o2 monitor artical and built one using a red led and a uv led and the chip, it could sense the difference in light transmission difference in saturated oxygin in my finger tip. You will need a different input subroutine to read them but it is simple.
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Think Inside the box first and if that doesn't work..
Re-arrange what's inside the box then...
Think outside the BOX!
Some of the code in that section (as well as in the rest of the doc.) has "search patterns" for when the target is lost.
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
When the going gets weird, the weird turn pro. -- HST
in the search patterns about storing the state where it last detected a target ? They show how to
move and look around for a target, which I think is helpful, but didn't see anything about using
the stored state.
Post Edited (ltmhall) : 3/16/2007 3:37:38 PM GMT
www.parallax.com/dl/docs/prod/robo/sumobotman.pdf
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
When the going gets weird, the weird turn pro. -- HST
on how to write the seach pattern when the robot dosen't see the light with both photoresistors ?
Any suggestions would be appreciated ?
Now, since FSMs are so cool, the real way to do the above is to set it up as it's own FSM (where each state is, say, below ambient, above ambient). This way the FSM can keep track of what you *want* to do with light, but could still be subsumed (overridden) by your obstacle avoidance, remote control, whatever. And, an FSM with a duration countdown can let you "timeout" the search pattern if it doesn't reacquire above ambient light after X counts. There are more efficient (and many alternative ways) to do the above, but hopefully this gives you a clear enough outline to implement your own ideas.
Is this helpful?
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
When the going gets weird, the weird turn pro. -- HST
Post Edited (Zoot) : 3/18/2007 5:47:05 AM GMT
If the average light of both photoresistors was greater than the threshold would I want the robot to go
forward.Then the code works by checking to see if lightL is greater than the lightR.·If so lightbit is·equal to 0, and if not lightbit equals 1.
I understand from your comment that the code below turns the robot·toward brighter light, but I don't reconize the code. Is this used to rotate the motors ? How would " forward and reversed" be defined at the
begining of the program?
motor(lightBit) = reverse 'turn towards brighter light as defined by "saved" light bit
motor(1-lightBit) = forward
duration = 20
Also I don't understand the motor VAR Byte/Word (2) at the beginning of the code.
I tried running using this code and I get a error from the line " motor VAR· Byte/Word (2)", am I missing something else ?
Also would this bit of code be used as a subroutine like test_photoresistors or something ?
Any further explanations would be really appreciated !
Post Edited (ltmhall) : 3/18/2007 2:48:39 PM GMT
That's just an idea for deciding if you have enough light to begin with.
That's pseudo code really. You could just as easily write:
It's more a structure, not real code to run. However you run your code, you've got lightBit to decide which way to turn, UNLESS the ambient light is marginal, in which case you start circling in the lightBit direction.
Use some other variable to "countdown" once you've started circling, so you can give up at some point and have the 'bot do something else.
It's not real code and won't compile. I often use arrays for my motors or paired sensors because it make some things easier.
Whether or not it's a subroutine depends on how you want to use it, but here's another attempt at a pseudo-code "flowchart" for organizing what you have going on (I think):
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
When the going gets weird, the weird turn pro. -- HST
In step 3 where the light AVg is compared to some threshold, you say “ set countdown timer to 20 and skip to step 7”,
however, in your pseudo-code above it jump straight step 7. Would I want to remove duration =20 and
put under the "else" command underneath it ?
Also at step six you say “go to step 1 and do it again why would go to step 1, is it because you want to
align both photoresistors in front of the light.
First the photoresistor vales are measure and then a average (lightAVg) is created. Next lightAVg is compared to some threshold and if it’s less than this threshold
the program jumps to where the duration is set to twenty and the duration is compared to zero. If lightAVg is greater than the threshold, lightL is compared to lightR. If lightL is greater than lightR than lightBit equals zero. If lightR is greater than lightL lightBit is equal to one. Next the robot moves right or left, depending on what the value of lightBit is equal to. The program loops itself until the average is less than the threshold. Next
the duration is compared to zero. If the duration is greater than zero the robot turns in circles and the value of the duration is decremented by one. When the duration is greater than zero the timer times out and the robot moves forward.
Where you "charge up" the duration to an appropriate countdown value is really up to you and partially depends on how you set up your code. The important think is to set it BEFORE it gets used, and only once, so that your circling doesn't time out immediately.
Otherwise it sounds like you've got a pretty good understanding of the flow of things. Remember there are always many ways to accomplish the same task. I would also emphasize that HOW you choose to decide that your light values aren't worth directly tracking may take some experimenting. Using an average ambient light value is one trick. You could also take the difference between the values and use that. You could also just check to see if one or the other sensor is very high/low.
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
When the going gets weird, the weird turn pro. -- HST
Also make sure that I set my duration = 20 before I check if it's greater than zero
Yes. Remember that the "20" is just a number I made up. What the number is and how fast it counts down really depends on the rest of your program and code. For example, if your code loops through every 20ms or so (so you can refresh pulses) then a countdown of 20 would be a approx. 400ms (less than 1/2 second). It will take some experimenting.
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
When the going gets weird, the weird turn pro. -- HST