 |
|
 |
| Parallax Forums > Public Forums > Stamps In Class > Better Boe-Bot IR Distance Measurements (Circuit + Programs) | Forum Quick Jump
|
|  Andy Lindsay (Parallax) Forum Moderator

       Date Joined Jul 2004 Total Posts : 1095 | Posted 12/7/2005 12:57 PM (GMT -8) |   | | This circuit below and the attached programs provide distance measurements that are better than the examples in Robotics with the Boe-Bot, Chapter 8. The measurements split a one foot (approx) distance into eight zones that are pretty evenly spaced, and there's next to no jitter in the measurements.
The example programs make the distance measurement by placing different resistances in series with the IR LEDs. The different series resistances are set by manipulating the input/output states of P4, P5, and P6. In the initialization of the program, P4 to P7 are all set LOW (connected to Vss), but left as inputs with the command OUTB = %0000. After that, the program manipulates which of those pins are connected to VSS and which of them are inputs with by setting DIRB equal to different values. For example, DIRB = %0101 sets P6 and P4 to outputs, but leaves P5 an input. Since earlier in the program, the OUTB was set to %0000, any I/O pin that gets changed to an output will send the LOW signal. If DIRB = %0001, that makes P6 and P5 inputs, but P4 is output-low. That means P4 is connected to Vss. Whenever anything is connected to Vss, it is commonly referred to as connected to ground, or "grounded".
The example programs use FOR DIRB = 1 to 7...NEXT to take P4, P5, and P6 through the following input/output combinations: %0001, %0010, %0011, %0100, %0101, %0110, %0111. Each different OUTB setting causes different combinations of parallel resistors to be in series with the IR LEDs. The thing about different parallel combinations of resistors is that they provide different levels of series resistance with the IR LEDs. From Robotics with the Boe-Bot, Chapter 7, Activity #3, we know that different series resistances equate to different IR LED headlight brightnesses. The brighter the IR LED, the further the IR receiver can see to detect an object. Inside the FOR...NEXT loop, the code counts the number of detections each side saw, and equates that to a distance.
Here is the equation for calculating the equivalent resistance of one or more parallel resistors:
Req = (R1-1 + R2-1 + R3-1 + ... + RN-1)-1
Here is another form of the same equation:
Req = 1 / (1/R1 + 1/R2 + 1/R3 + ... + 1/RN)
Let's say DIRB = %0111. That means that all three resistors are connected to Vss and are part of the circuit. To calculate the equivalent resistance in series with the IR LED, it's:
Req = 1 / (1/2000 + 1/4700 + 1/10000) = 1230 ohms
Here's another example with DIRB = %0101. With this, configuration, P6 and P4 are grounded, but P5 is an input. So the 4.7 k resistor is not part of the circuit, and we only want to calculate the parallel resistance for the 10 k and 2 k resistors. The notation for parallel resistance is R1 || R2, etc. So, this calculation is for 2 k || 10 k:
Req = 1 / (1/2000 + 1/10000) = 1667 ohms.
The different series resistances you can get from the seven different combinations of OUTB are: 1230, 1402, 1667, 2000, 3197, 4700, and 10,000.
Both programs below are also attached to this post.
This example program tests the distance for both IR Detectors and displays it in the Debug Terminal. You should be able to get values from 0 to 7, wich corresponds to between 1 inch and 1 foot.
' -----[ Title ]-------------------------------------------------------------- ' TestDistnaceWithNewCircuit.bs2 ' Test sensitivity of new IR distance circuit.
' {$STAMP BS2} ' Stamp directive. ' {$PBASIC 2.5} ' PBASIC directive.
' -----[ Variables ]----------------------------------------------------------
irDetectLeft VAR Bit irDetectRight VAR Bit distanceLeft VAR Nib distanceRight VAR Nib
' -----[ Initialization ]-----------------------------------------------------
DEBUG CLS, "Left Right", CR
OUTB = %0000
' -----[ Main Routine ]-------------------------------------------------------
DO
GOSUB Get_Ir_Distances
DEBUG " ", DEC1 distanceLeft, " ", DEC1 distanceRight, CRSRX, 0
PAUSE 100
LOOP
' -----[ Subroutine - Get IR Distances ]--------------------------------------
Get_Ir_Distances:
distanceLeft = 0 distanceRight = 0
FOR DIRB = 1 TO 7
FREQOUT 7,1,38500 irDetectLeft = IN8 distanceLeft = distanceLeft + irDetectLeft
FREQOUT 3,1,38500 irDetectRight = IN2 distanceRight = distanceRight + irDetectRight
NEXT
RETURN
This example program is the following Boe-Bot program from Robotics with the Boe-Bot, Chapter 8, Activity #2. With this program, the Boe-Bot should be able to lock onto and follow an object with much less jitter.
' -----[ Title ]-------------------------------------------------------------- ' FollowingBoeBotWithNewDistanceCircuit.bs2 ' Boe-Bot adjusts its position to keep objects it detects in zone 4.
' {$STAMP BS2} ' Stamp directive. ' {$PBASIC 2.5} ' PBASIC directive.
DEBUG "Program Running!"
' -----[ Constants ]----------------------------------------------------------
Kpl CON -15 Kpr CON 15 SetPoint CON 4 CenterPulse CON 750
' -----[ Variables ]----------------------------------------------------------
irDetectLeft VAR Bit irDetectRight VAR Bit distanceLeft VAR Nib distanceRight VAR Nib pulseLeft VAR Word pulseRight VAR Word
' -----[ Initialization ]-----------------------------------------------------
FREQOUT 4, 2000, 3000
' -----[ Main Routine ]-------------------------------------------------------
DO
GOSUB Get_Ir_Distances
' Calculate proportional output.
pulseLeft = SetPoint - distanceLeft * Kpl + CenterPulse pulseRight = SetPoint - distanceRight * Kpr + CenterPulse
GOSUB Send_Pulse
LOOP
' -----[ Subroutine - Get IR Distances ]--------------------------------------
Get_Ir_Distances:
distanceLeft = 0 distanceRight = 0
FOR DIRB = 1 TO 7
FREQOUT 7,1,38500 irDetectLeft = IN8 distanceLeft = distanceLeft + irDetectLeft
FREQOUT 3,1,38500 irDetectRight = IN2 distanceRight = distanceRight + irDetectRight
NEXT
RETURN
' -----[ Subroutine - Get Pulse ]---------------------------------------------
Send_Pulse:
PULSOUT 13,pulseLeft PULSOUT 12,pulseRight PAUSE 5 RETURN
Post Edited (Andy Lindsay (Parallax)) : 12/7/2005 10:03:24 PM GMT File Attachment : TestDistances.bs2 1KB (application/octet-stream) This file has been downloaded 627 time(s). File Attachment : FollowingBoeBotWithNewDistanceCircuit.bs2 2KB (application/octet-stream) This file has been downloaded 601 time(s). | | Back to Top | | |
   |  kiros Registered Member
        Date Joined Nov 2005 Total Posts : 2 | Posted 12/22/2005 4:48 AM (GMT -8) |   | I liked this much better then the 1 that came with the manual :D Thx for this. I will try to add more to the kode, if i find out how everything works. I've never realy koded much before :P But if i make it, i will post the results. Again, thx for this 300% better solution.
Kim, Norway | | Back to Top | | |
    |  Ryan Clarke Registered Member
        Date Joined Jul 2004 Total Posts : 745 | Posted 1/23/2006 8:53 PM (GMT -8) |   | | | |
   |  Andy Lindsay (Parallax) Forum Moderator

       Date Joined Jul 2004 Total Posts : 1095 | Posted 9/5/2006 8:18 AM (GMT -8) |   | Hey, Zoot,
That looks great! It's a perfect link for this thread too.
Regards, Andy | | Back to Top | | |
   |  Evil Axis Blue Ninja Rider
        Date Joined Oct 2006 Total Posts : 9 | Posted 11/6/2006 5:26 AM (GMT -8) |   | I read your post above, and it makes me think a rolling average would work nicely.
For example
I would need the following: a counter > cntr number of measurements to average by > avgNum (let's say 4 for this example) an array to keep the measurements in
then while cntr < avgNum I start filling the array, and average by cntr to decide what to do
once cntr = avgNum, then I start pushing new measurements into the array, and moving old measurements out of the array, this would provide me with a rolling average.
This is my idea.
I am also thinking I could just start filling the array and average by avgNum from the begging, and accept a few milliseconds of weirdness while the program goes through the first cycles.
Anyhow, I have to go to work now, and don't have time to code this. If I get it done tonight, then I will post the code here.
Thanks! | | Back to Top | | |
 |  Evil Axis Blue Ninja Rider
        Date Joined Oct 2006 Total Posts : 9 | Posted 11/6/2006 5:30 PM (GMT -8) |   | I added the averaging into the program, and it really does slow down the jitter, but it doesn't go away. I found that averaging over 4 pulses works ok. When the target does not move, then the bot rocks back and forth like a crazy person, but much slower than the original jitter
here is the code:
' added constant AvgBy CON 4
'added VARs distLeftArray VAR Nib(AvgBy) distRightArray VAR Nib(AvgBy) index VAR Nib avgDistLeft VAR Byte avgDistRight VAR Byte
'in the initialization, I fill the array with the target value, so the bot doesn't move until it has a good average FOR index = 0 TO AvgBy - 1 distLeftArray(index) = SetPoint distRightArray(index) = SetPoint NEXT
'this is the new main routine DO
GOSUB Get_Ir_Distances 'shuffle older values to higher index in the array FOR index = AvgBy - 2 TO 0 distLeftArray(index + 1) = distLeftArray(index) distRightArray(index + 1) = distRightArray(index) NEXT distLeftArray(0) = distanceLeft distRightArray(0) = distanceRight
'calculate rolling average avgDistLeft = 0 avgDistRight = 0 FOR index = 0 TO AvgBy - 1 avgDistLeft = avgDistLeft + distLeftArray(index) avgDistRight = avgDistRight + distRightArray(index) NEXT avgDistLeft = avgDistLeft / AvgBy avgDistRight = avgDistRight / AvgBy ' Calculate proportional output.
pulseLeft = SetPoint - avgDistLeft * Kpl + CenterPulse pulseRight = SetPoint - avgDistRight * Kpr + CenterPulse
GOSUB Send_Pulse
LOOP
Anyhow, i hope someone finds this interesting or useful You only have to change the value of AvgBy to experiment with different averages. 4 works pretty well, with 10 it just sits there, 5 and 6 work, but are slower to respond.
Andy,
thanks for the awesome posts. I have read some of your other ones, and the instructions and diagrams are spectacular. You should work for parallax!  Post Edited (Evil Axis) : 11/7/2006 1:35:00 AM GMT | | Back to Top | | |
 |  Evil Axis Blue Ninja Rider
        Date Joined Oct 2006 Total Posts : 9 | Posted 11/6/2006 6:10 PM (GMT -8) |   | After doing the averaging, I carefully read your post about PID control. I haven't tried to integrate the PID algorithms into the program, but it seems that i will never get the bot to sit still when the object it is following stops, since the measurements from the IR pairs are so inaccurate.
Am I correct in that assumption?
On the other hand, the PID stuff is really interesting.
Sorry if I hijacked the thread. I just got really interested in making the jitter go away. Seems that I am banging into the limits of the sensors though. | | Back to Top | | |
 |  Andy Lindsay (Parallax) Forum Moderator

       Date Joined Jul 2004 Total Posts : 1095 | Posted 11/7/2006 9:49 AM (GMT -8) |   | Well, attached is a video clip that contrasts P vs. PID with the same noisy sensors. The first bot is the same old P control example with the Boe-Bot's motion mirroring the noise it's getting from its distance sensors. The second bot is a PID controlled bot. Same noisy sensors, much better tracking (both dynamic and static). There's an apple and orange aspect here since the PID bot has a Propeller chip instead of a BASIC Stamp. However, the Propeller's ability to get 40 distances instead of just 5 from the same sensors only served to make its jitter worse. With only proportional control, the Bot with the Propeller chip jittered so badly in response to all the distance sensor noise that it would lose sight of the the object it was tracking and wonder off. So the PID really did a great job of cleaning up its object following behavior. Although I've never gotten around to writing PID Boe-Bot following code, I'm very confident that it's doable. With some tuning of the Kp, Ki, and Kd, PID should clean up the Boe-Bot's behavior just as well as the performance on the video clip. You may even be able to clean it up further by using your current averaging code as an input filter before the PID calculations. Yeah, you're right, we are drifting a little off the topic of this thread. Well, if you start developing code and have questions or code to post, definitely start a new thread.
Andy Lindsay
Education Department
Parallax, Inc. Post Edited (Andy Lindsay (Parallax)) : 11/7/2006 5:53:47 PM GMT File Attachment : P vs PID control.zip 1.88Mb (application/x-zip-compressed) This file has been downloaded 420 time(s). | | Back to Top | | |
     |  Andy Lindsay (Parallax) Forum Moderator

       Date Joined Jul 2004 Total Posts : 1095 | Posted 7/6/2009 11:22 AM (GMT -8) |   | | Hi MichelB,
OUTB = %0000 ensures that all the any I/O pin in bank b (P4..P7) will send a low signal if its corresponding direction register bit is set to output with a binary 1.
For example, OUTB = %0000 and DIRB = %0101 sets P4 and P6 output-low while leaving P5 and P7 as inputs. If you change DIRB to %0010, all I/O pins will be input except for P5, which will be output-low.
When an I/O pin is set to input, it's about like unplugging the resistor from the socket. So, with DIRB = %0101, the signal can pass to ground (output-low = shorted to ground) through the resistors connected to P4 and P6, but not P5. When DIRB is %0010, the signal can pass through the resistor connected to P5, but not the other resistors.
Education Department
Parallax, Inc. | | Back to Top | | |
    | 26 posts in this thread. Viewing Page : 1 2 | | Forum Information | Currently it is Friday, November 20, 2009 4:11 PM (GMT -8) There are a total of 393,671 posts in 55,517 threads. In the last 3 days there were 88 new threads and 710 reply posts. View Active Threads
| | Who's Online | This forum has 17684 registered members. Please welcome our newest member, Dogg. 32 Guest(s), 4 Registered Member(s) are currently online. Details Dragon, Kit Morton, Mike Green, ChuckG |
Forum powered by dotNetBB v2.42EC SP2.02 dotNetBB © 2000-2009 |
|
|