To LUGNET HomepageTo LUGNET News HomepageTo LUGNET Guide Homepage
 Help on Searching
 
Post new message to lugnet.roboticsOpen lugnet.robotics in your NNTP NewsreaderTo LUGNET News Traffic PageSign In (Members)
 Robotics / 4608
4607  |  4609
Subject: 
Re: New RIK-user hints, bumpers, many topics
Newsgroups: 
lugnet.robotics
Date: 
Sat, 17 Apr 1999 02:51:38 GMT
Original-From: 
John Cooper <ROBOTS@JPSCstopspammers.CO.UK>
Reply-To: 
robots@jpsc/avoidspam/.co.uk
Viewed: 
1397 times
  
Using the 'DEFCON' IRPD code from John and James Cooper


Where might this code be found.  It sounds interesting, and I don't
recall finding this anywhere on my journeys through the net.

Thanks.

It'll be in the archive, I don't know the message number, but the original was
http://www.lugnet.com/news/display.cgi?lugnet.robotics:3488 so you'll be able
to browse the thread.

In the next few days I'll put it on my web site, along with my current FORTH
attempt to match it. http://www.jpsc.co.uk/robots



..later

Actually I've just reviewed my latest version and it is significantly defferent
from the original (I've taken advantage of the new expressions in NQC) that I
think I'll put it up here again. Apologies to anyone if they think this message
is too long, in future I'll get my site together and publish links to that.


/*
Mark R. David  markdavid@mediaone.net

RCX Radarbots and distance measurement

While I like the idea of a radarbot, most of the algorithms I've seen
for implementing it were basically "You're close when the return signal
starts to get really noisy." I wanted to know more about what was going
on, see if I could be more precise about it, and particularly try to
come up with a way of measuring how far away I was from collision.
Here's what I came up with.

I did a bunch of trials in which I measured light sensor readings for
both ambient light (no infrared flashing) and while I was broadcasting
an infrared message. I did it first at a series of stationary, fixed
distances from an object (2-24 inches), and then with a robot moving
steadily toward the object from 8 feet. I repeated measurements in a few
different ambient light conditions (all indoors), including a sunny day,
an overcast day, and a dimly lit nighttime room. I logged 40 readings
for each test in the datalog, loaded them up to the computer and into a
spreadsheet, and then played with and charted the results.

The ambient readings were VERY consistent, so the noisiness in the
signal does not seem to be a feature of the light sensor itself. It only
becomes noisy when the RCX is broadcasting infrared messages. The closer
it gets to the object, the noisier it becomes, as measured by a moving
statistical variance of the readings.

I tried many techniques for deriving a measure of distance from the
readings, including moving averages, standard deviation envelopes, first
and second derivatives and filters. I couldn't get any of these to work
in multiple ambient light environments. In bright environments, the
overall level is higher, and the infrared transmission doesn't brighten
it up much more. In dark environments, the difference the signal makes
in the overall light level is many times more pronounced.

What I finally noticed was that, as the bot moved closer to the object,
it got 3 kinds of readings: very bright readings, more-or-less ambient
readings, and in-between readings. The very bright readings got brighter
and brighter as the bot got closer. Thus, if you ignored everything
except the bright readings, you traced a pretty good parabola on the
graph as a function of distance.

My guess is that this occurs because you can't synch the light sensor
read with an on bit in the RCX message in any guaranteed way. Sometimes
you get an on bit, sometimes an off. I think I've read somewhere that
the length of a broadcast bit is 417 micro-secs. Perhaps the light
sensor read is several bits long.
*/

#define RAW_LIGHT    IN_2

#define SAMPLE_COUNT 30

int AVG_AMBIENT,DiffRaw,ThisRaw,DEFCON,MinRaw,RisingMins,LastRaw,DescendingRaw;
int Temp;

task ProximityDriver
// converted from code by Mark R. David        (markdavid@mediaone.net)
{
  Sensor(RAW_LIGHT, IN_CFG(STYPE_LIGHT, SMODE_RAW));
  IRMode(IR_HI);

  Temp = 0;
  repeat (SAMPLE_COUNT) {
    Temp += RAW_LIGHT;
  }
  Temp /= SAMPLE_COUNT;
  AVG_AMBIENT = Temp;                               // average starting ambient
light value

  DEFCON = 0;                                       //    DEFCON - number of
diffs the last min is below ambient
  MinRaw = AVG_AMBIENT;                             // The current minimum
flash read - init to ambient
  RisingMins = FALSE;                               //    Flag that the last
min was higher than the one before
  LastRaw = AVG_AMBIENT;                            // Previous raw reading
  DescendingRaw = FALSE;                            //    Flag that raw
readings are descending

  loop {                                            // monitor forever
    ThisRaw = RAW_LIGHT;                            //      Take ambient
reading ...
    Temp = (AVG_AMBIENT*4 + ThisRaw) / 5;
    AVG_AMBIENT = Temp;                             // ... and keep a moving
avg of it

    DiffRaw = (615-AVG_AMBIENT)/6;                  //    DiffRaw = The diff -
a meaningful difference in light reading
    if (DiffRaw > -6) {                             //         Is negative and
no greater than -5
      DiffRaw = -6;                                 // DiffRaw = Min(-6, (615 -
AVG_AMBIENT) / 6)
    }

    SendMessage(255);                               // Flash
    Sleep(3);
    ThisRaw = RAW_LIGHT;
    if (ThisRaw < MinRaw) {                         //  New minimum!
      MinRaw = ThisRaw;                             // Reset the effective min
      RisingMins = FALSE;                           //     Clear the rising
mins flag
      DescendingRaw = TRUE;                         //     Set the descending
flag
      Temp = (MinRaw-AVG_AMBIENT) / DiffRaw;
      DEFCON = Temp;                                // DEFCON = (MinRaw -
AVG_AMBIENT) / DiffRaw
    } else {
      if (ThisRaw > LastRaw) {                      //   Ascending
        if (DescendingRaw==TRUE) {                  //      Was descending must
be a higher min
          if (RisingMins==TRUE) {                   //       It's the second
one! Reset the effective min
            MinRaw = LastRaw;                       // Reset the effective min
            Temp = (MinRaw-AVG_AMBIENT) / DiffRaw;
            DEFCON = Temp;                          // Calculate DEFCON again
          } else {
            RisingMins = TRUE;
          }
        }
        DescendingRaw = FALSE;
      } else {
        DescendingRaw = TRUE;                       //        Descending
      }
    }

    LastRaw = ThisRaw;
  } //loop forever
}

/*
The basic strategy is to measure DEFCON.

The variables used are:

AVG_AMBIENT - Maintains the initial ambient light value, and a moving
average of same

DEFCON - The higher DEFCON gets, the closer we are to the object.

DiffRaw - The difference - a number that represents how much brighter
the raw reading has to be to raise DEFCON one level.

ThisRaw - the latest light sensor raw reading

MinRaw - The current effective minimum (brightest) raw reading

RisingMins - Flag that indicates that our most recent minimum was
actually higher (darker) than the currently effective minimum. We might
no longer be getting closer to the object, but we'll give it one more
chance.

LastRaw - the reading prior to ThisRaw, used to determine if things are
getting brighter or darker

DescendingRaw - a flag that readings are currently descending (getting
brighter)

Temp - temporary variable


First, it takes a few samples of the ambient light and calculates the
average in AVG_AMBIENT. Next, based on the ambient light level, it
calculates difference in DiffRaw. It initializes the rest of the
variables, and then begins to loop. Within the loop, it first measures
the ambient light again, storing it in ThisRaw. It then calculates a
pseudo-exponential 5-period moving average of the ambient level in case
we move from light into dark or something, and stores it in AVG_AMBIENT.
For the same reason, it also recaclulates difference into DiffRaw.

Next, it flashes and takes a reading into ThisRaw. MinRaw has stored in
it our most recent local minimum (brightest raw) reading. If we just got
a brighter one then we a) store it in MinRaw instead, b)clear RisingMins
to indicate that minimum readings are definitely getting brighter, c)
set DescendingRaw to indicate that sequential readings are descending d)
calculate DEFCON as the number of difference levels (DiffRaw) that we
are below (brighter than) ambient.

If the latest reading wasn't brighter than our minimum, than a number of
things could be happening. If it was brighter than the previous reading
(but not bright enough to set a new min), than let's just loop and see
what develops. If it was darker than the last reading (ascending), but
we used to be getting lighter (ascending), then we have just detected a
local minimum, and that minimum must be higher (darker) than the current
effective brightest minimum in MinRaw. Check RisingMins - if it's set
then this is the second time in a row that that's happened, and we
conclude that we are no longer moving toward the object (it moved, we
turned, whatever) and we reset MinRaw to LastRaw's value, the minimum we
just detected, and lower DEFCON. If this is only the first time,
however, we don't want to be too hasty; just set RisingMins and try
again.

With the parameters I've used, DEFCON 3 seems pretty reliably reached at
a head-on distance of 12-18 inches, DEFCON 4 at 3-6 inches. The higher
end of those ranges occurs in darker environments - I need to play with
parameters some more to eliminate this bias. Basically, difference is
calculated linearly from the ambient light level - a much more
simplistic solution than many I tried, but it seems to work most
reliably. The calculation shown ends up with a difference of -6 raw
units at an ambient reading of 651 (sunny room) or brighter, and -35
units at 825 (really dark).

As a note, the moving average calculation is credited to Welles Wilder,
a commodities market technical analysis guru from the 80's. It's great
for smoothing noisy data, doesn't exhibit large discontinuities like a
linear moving average, and is easy to calculate. Basically, for an
n-period average on period t - A(n,t) - with a current datapoint Ot:
A(n,t) =( (A(n,t-1) * (n - 1) ) + Ot ) / n
Thus, in a 5-period average, as above, the most recent value counts for
1/5 of the new average, and the old average counts for 4/5.

Have fun!
*/

--
John & James Cooper, Wallington, UK


--
Did you check the web site first?: http://www.crynwr.com/lego-robotics



Message is in Reply To:
  Re: New RIK-user hints, bumpers, many topics
 
(...) Where might this code be found. It sounds interesting, and I don't recall finding this anywhere on my journeys through the net. Thanks. (26 years ago, 16-Apr-99, to lugnet.robotics)

7 Messages in This Thread:



Entire Thread on One Page:
Nested:  All | Brief | Compact | Dots
Linear:  All | Brief | Compact
    

Custom Search

©2005 LUGNET. All rights reserved. - hosted by steinbruch.info GbR