Picaxe optical radar for robots.

boriz

Senior Member
Picaxe optical radar for robots.

Here’s the idea: A sharp GP2D12 IR Range Sensor on a mini servo, with positional feedback and a scanning routine. The scanning routine must sidestep the conflict problem with SERVO commands and serial TX commands. The positional feedback must be accurate and repeatable, and hopefully easy to implement without requiring addition sensors/encoders. The Picaxe, hopefully an 08M ultimately, though I’m prototyping with a 14M, will operate independently of the main robot ‘brain’ and send object detection and ranging data serially.

This is what I have so far: The scanning routine simply lets the servo go as fast as it can on each sweep. So it’s a single SERVO command to one extreme, then another to the other extreme, then repeat. But after the command has been issued, and the servo is moving (approx half second for one sweep left-to-right), the analogue output from the range sensor is being read by ADC0 in a loop, placing each reading into consecutive RAM locations using POKE.

Without a delay in the loop, the available ram will be full with readings before the sensor head has panned more than a few degrees. So a balance has to be struck with the number of samples you want and how long you wait between samples, bearing in mind that the sweep will finish in about half a second. For my test rig I’m using 20 samples for one left-to-right sweep, though I plan on doubling that eventually.

This works upto a point, but the problem is that no two servos are exactly alike, and even a single servo will vary it’s sweep time according to battery conditions etc. So while you now have a nice record of distance information from the sweep, you don’t have a good record of directional information. Enter positional feedback.

If you dismantle the servo, you can access the centre terminal (wiper) of the integrated feedback pot. It’s fairly easy to solder a connecting wire and feed it out of the servo to your circuit.

For the mini servo I’m using at the moment, this output (referenced to zero volts, common with the servo and Picaxe), carries a voltage which varies from about 1 volt at the left extreme, to about 2.2v at the right extreme. The extremes I’m using are SERVO 5,80 and SERVO 5,220. Not quite 180 degrees, but plenty good enough for the robot application.

Now during a sweep, I have two analogue signals. One from the positional feedback, the other from the distance reading. If you rescale the positional ADC reading, you can use that number as the memory address into which you POKE the distance information. You can also use it to determine exactly when the sweep has reached it’s end.

Once you have the data in RAM, it can be passed serially to the main ‘brain’ of your robot at the end of each sweep. A single burst containing all the range data for one complete sweep.

So far it’s working out pretty well. I’ll update this thread when I get the software sorted. I just have a few proof-of-principle routines and a GP2D12 Blu-Tacked onto a mini servo ATM. I’ve also ordered a small RC tank from ebay (sold as faulty) that I’m going to gut and use as an experimental robot base.

Ultimately I hope to have a free roving autonomous robot that can continue moving while scanning and object avoiding.
 

lanternfish

Senior Member
Without seeing your code, if you are using a for - next loop (or similar) using the servopos command you can easily do 10, 20 ,30 positions of the servo. By taking a reading after each movement you automatically have a reference without having to use an readadc command. Or am I on the wrong track?

Cheers
 

boriz

Senior Member
@lanternfish

Hi. Welcome to the forum.

I think you have missed the point. You seem to think that I am using a series of SERVOPOS commands to continually update the position. This is not the case. I want the servo to sweep at its own natural maximum speed. I issue only one SERVO pin,80 command to take the servo to its extreme left, then another single SERVO pin,220 command to move it to its extreme right.

The servo signals are transmitted continually in the background and it takes approximately half a second to get from one extreme to the other. During this ‘sweep time’, I could just have a pause, say PAUSE 600. Or indeed any Picaxe code that takes about half a second to execute. No further SERVOPOS commands are required. The servo will continue to move until it reaches its destination position.

In my routine, during the half second after issuing the SERVO command, while the servo is moving, I read the ADC range info in a loop, POKEing the results into RAM.

Here’s a quick example of what I mean (pseudo code):
Code:
‘’’first move the servo to its starting position
servo 5,80 ‘’’start servo moving to extreme left position
pause 600 ‘’’wait for it to get there

do
	servo 5,220 ‘’’start servo moving to extreme RIGHT position
	do
		readadc 0,b0 ‘’’get range sample from sensor
		readadc 4,b1 ‘’’read position of that sample from servo pot
		POKE aaa,b0 ‘’’store range sample
		PAUSE ppp
	loop until end-of-sweep ‘’’continue sampling until the servo reaches end position
	gosub send-sweep-data ‘’’serially transmit all the range data from this sweep
	servo 5,80 ‘’’start servo moving to extreme LEFT position
	do
		readadc 0,b0 ‘’’get range sample from sensor
		readadc 4,b1 ‘’’read position of that sample from servo pot
		POKE aaa,b0 ‘’’store range sample
		PAUSE ppp
	loop until end-of-sweep ‘’’continue sampling until the servo reaches end position
	gosub send-sweep-data ‘’’serialy transmit all data from this sweep
loop
The address ‘aaa’ is derived from the servo pot position reading b1. That’s what I’m working on right now. It’s easier said than done. The delay ‘ppp’ is also hard to work out, but I’m getting there with experimentation. With no delay, I get about 200 samples. This would be fine if I had 200 bytes of RAM, but I don’t. So I have to somehow scale this data into 40 bytes.

I’m also having the old ‘Picaxe too slow’ problem. It’s just taking too long to transmit 40 bytes serially at the end of each sweep.

I’ll keep you posted.
 

Andrew Cowan

Senior Member
Putting a 'setfreq m8' at the beginning will help.

You will have to go back down for the servo commands (setfreq m4), but overall, this should spped everything up.

A
 

lanternfish

Senior Member
That is clearer. My suggestion is that if you only have/need say 30 reference points then a simple FOR-NEXT loop containg an incrementing SERVOPOS command will allow you duplicate each reference point accurately on every sweep (with some minor error).

And you could probably serially transmit each single position and distance data after each SERVOPOS command and before the loop increments.I feel this is a simpler solution.

Though you did mention in your initial post something about the conflict between servo and serial commands. Not knowing what this conflict is (internal timer?) may be the undoing of my suggestion.

Cheers
 

SilentScreamer

Senior Member
It is as a result of the internal timer, see manual two's explanation of the servo command.

The servo pulses are also temporarily disabled during timing sensitive commands like serin, serout, sertxd, debug etc.
 

boriz

Senior Member
"I feel this is a simpler solution."

Perhaps. But certainly much slower. The idea is to get this ‘radar’ info as quickly as possible so that the robot need not stop to look around. Even the servo max speed isn’t quite fast enough for me, but I’ll have to compromise.

I did consider using a stepper for speed, but it would add extra complexity and additional external driver components. The servo has it all integrated.
 

boriz

Senior Member
I have found that unless you cut the servo signals off, buy issuing a ‘LOW pin’ command, the servo will jitter about the place randomly when you use SERTXD.

I did think of using SETFREQ immediately before and after SERTX, and may end up doing so, but I’m not quite upto that place in the project yet.
 

Wrenow

Senior Member
Hmmmm. My personal thought on how I would tackle this.

You want to read an angle and a range, then go to the next angle and read the range, etc.

You can get the angle relatively precise by using either the Servo command or a pulsout every about 20ms. The servo command does not require you to adjust a pause in the do loop, as it does this in the background - BUT it is sensitive to other commands, like the serial communications.

So, what I would do is do a pulsout for a given position, read the rangefinder, send the data, pause the appropriate amount of time, increment/decrement the pulsout to the next angle, and then rinse and repeat.

Cheers,

Wreno
 
Last edited:

boriz

Senior Member
"So, what I would do is do a pulsout for a given position, read the rangefinder, send tghe data, pause the appropriate amount of time, increment/decrement the pulsout to the next angle, and then rinse and repeat."

I'm sure that would work. But it will be several times slower than the solution I'm working towards. I'm after the fastest possible method.
 

BeanieBots

Moderator
Have you considered the response time of the optical sensor?
AFIK, they are fairly heavily filtered so although there is nothing to stop you reading them as fast as possible, the data returned might not equate to the real-time angle at the time the reading is taken. Worth testing!
 

slurp

Senior Member
With a typical sweep on the servo of 0.19sec / 60 deg you'll get about 4 to 7(ish) measurements from this device over a 60deg angle - typically the GP2D12 requires 38.3ms (+/- 9.6ms) per output.

If this was point based measurement then we are looking at a resolution between 15 and 8.6 degrees but we must also beware the effects of shapes upon the analogue value - ref Fig.8 in the data sheet.

I'm aware of people using the servo sensor mechanism to to try an find and lock on to an object to track, narrowing the movement to keep the signal at it's peak but general scanning produces a wider range of problems.

I've got a few similar sensors I've been playing with for minisumo opponent detection, the problem for me is moving tragets may dissapear to be in a completely different location by the time the sensor has reacted. Low speed servo based robots aren't too much of a problem.... it's the faster robots based on that rreaction time between sensor outputs.

regards,
Colin
 

boriz

Senior Member
Hmmm. That could explain why I’m getting some puzzling results. This code should, in theory, be exactly what I’m after. It should work perfectly. But it doesn’t. The self-calibration-at-runtime function solved some problems, but I think the integer maths is spoiling positional accuracy.

Code:
#picaxe 14m
#terminal 4800 '''auto open the terminal window

symbol n=b0 '''general purpose counter
symbol posmin=b1 '''minimum servo pot reading
symbol posmax=b2 '''maximum servo pot reading
symbol pstep=b3 '''step size, calibrated at runtime
symbol threshold=b4 '''position of next measurement interval
symbol pos=b5 '''position ADC reading
symbol range=b6 '''range ADC reading

rem First calibrate posmin and posmax
servo 5,220 '''move servo to right extreme
pause 700 '''wait until it's there
readadc 4,posmax '''read the maximum ADC servo position
servo 5,80 '''move servo to left extreme
pause 700 '''wait until it's there
readadc 4,posmin '''read the minimum ADC servo position
pstep=posmax-posmin/40 '''calculate the required step size for 40 samples

rem main loop
do
	servo 5,220 '''start servo moving to exreme right
	for n=80 to 120 '''40 consecutive memory addresses
		threshold=n-79*pstep+posmin '''calculate threshold of next range reading position
		do:readadc 4,pos:loop until pos>threshold '''wait until servo position reaches threshold
		readadc 0,range '''read the ADC range from rangefinder
		poke n,range '''store the range in RAM
	next n
	gosub readout '''serially transmit the range samples
	servo 5,80 '''start servo moving to extreme left
	for n=120 to 80 step -1 '''40 consecutive memory addresses
		threshold=n-79*pstep+posmin '''calculate threshold of next range reading position
		do:readadc 4,pos:loop until pos<threshold '''wait until servo position reaches threshold
		readadc 0,range '''read the ADC range from rangefinder
		poke n,range '''store the range in RAM
	next n
	gosub readout '''serially transmit the range samples
loop

readout: '''transmit
low 5 '''ensure that the servo signal is cut off
for n=80 to 120 '''40 consecutive memory addresses
	peek n,range '''recover the range info from RAM
	sertxd (#range,32) '''transmit the range for this position
next n
sertxd (13,10,13,10) '''space out the lines in the terminal window
return
Here is a typical readout copied from the terminal window during a test:
32 32 41 41 41 41 41 42 27 26 26 27 26 27 31 30 31 31 31 30 31 31 25 24 25 25 25 25 25 25 12 10 11 10 10 10 11 11 15 14 15

(Higher number = shorter range)

As you can see, several portions seem to be either repeating or very close in magnitude, prolly a result of the limited update rate of the sensor. Here it is again, split up into the repeating patterns (for clarity):

32 32 * 41 41 41 41 41 42 * 27 26 26 27 26 27 * 31 30 31 31 31 30 31 31 * 25 24 25 25 25 25 25 25 * 12 10 11 10 10 10 11 11 * 15 14 15

Rather than getting 40 good range samples, it looks like I’m getting more like 7!. It seems very likely that my fast panning method will not work with this sensor. Oh bum. I might have to bite the bullet and use a much slower method. Or get another sensor and combine the readings. (Prolly not).
 

Wrenow

Senior Member
Ok, I think I see what you are doing.

You do realize, of course, that the servo has a PID routine in it, so moving from side to side does not necessarily have either the same velocity throughout the travel range, nor from one scan to the next. Using the pulsout to get to the next position, slicght pause to settle, and then taking a measurement still seems to me to be a more accurate methodology, assuming that accurate positioning is required.

Also, I am still concerned that the background operation of the servo command might be having other adverse effects your other routines, but perhaps not.

Cheers,

Wreno
 

boriz

Senior Member
"You do realize, of course, that the servo has a PID routine in it, so moving from side to side does not necessarily have either the same velocity throughout the travel range, nor from one scan to the next."

Exactly why I soldered a wire onto the servo pot. For accurate positional information. Using the positional feedback to derive the memory address means that each unique address always relates exactly to one unique angle of pan. Regardless of PID or motor speed etc.
 
Top