Ultrasonic - Fading LED based on distance - Need pointers to improve this code.

Blazemaguire

Senior Member
Hi,

I'm experimenting with fading an LED based on the distance from an ultasonic range finder unit. - I've got the code working in principle, but its not quite working as nicely as I want

When the distance is at maximum extents (about 285mm) the LEDs should be be on minimum brightness, and then as you reduce the distance to the sensor, the brightness increases, upto about 30mm from the sensor. (If I go closer than 30mm, I get messy readings from the sensor)

The problem at the moment is that the LEDs seem to flicker, as though they're turning on and off, although they are giving the correct brightness levels. - The flickering is far more pronounced at further distances (i.e, when the brightness should be lowest), and less pronounced the closer I get to the sensor.

Is it something to do with the 20us recharge period for the ultrasonic reading? - Does this shut down the pulseout command every time it takes a reading?

If so, does anyone have a workaround? I'm using a 20m2 chip

Also, am I barking up the wrong tree by keeping the duty cycle the same throughout at 150,150? - Using 150,150 throughout worked fine when I did the same experiment with a potentiometer - as in, minimum brightness at one end of the pot's travel and max brightness at the other, exactly as needed, with no flicker


Any help, as always, greatly received.

Rob


Code:
symbol ultrain =b.5
symbol ultraout=b.4
symbol red=c.2              'Red RGB pin
'symbol green=c.3  		'Green RGB pin
'symbol blue=c.5			'blue RGB pin

symbol range=w0
symbol range_neg=b3


main:
			
	pulsout ultraout,2 			; produce 20uS trigger pulse (must be minimum of 10uS)
	pulsin ultrain,1,range 		; measures the range in 10uS steps
	pause 20			; recharge period after ranging completes


	let range = range * 100 / 58	; multiply by 10 then divide by 58 to convert range to mm
	
if range>285 then  'had to add 30 to range to get full range of dimness to brightness (see line 42)
	
	range=285
	range_neg=1
	'sertxd(#range," mm, Neg:",#range_neg,cr,lf)  'for debugging readings
	pwmout red,150,150
	pwmduty red,range_neg
	goto main

elseif range<30 then     '
	
	range=30   'checking to see if the reading is too close a distance
	range_neg=255
	pwmout red,150,150
	pwmduty red,range_neg
	'sertxd(#range," mm, Neg:",#range_neg,cr,lf)  'for debugging readings
	goto main

	
else
	range_neg=-range ' convert the range to 'opposite' so that brightness increase the closer you get.
	range_neg=range_neg+30  'compensating for the fact you can't get to within the last 30mm, otherwise, LED would never fade all the way to 255 (max brightness)
	pwmout red,150,150
	pwmduty red,range_neg
	'sertxd(#range," mm, Neg:",#range_neg,cr,lf) 'for debugging readings
	endif

	goto main
 

Blazemaguire

Senior Member
Thanks Hippy,

I moved the pwmout to the start and it seems FAR better! - Such a simple thing, but if you don't know these things, then they can really stump you.

I'm now just working on a further improvement for when the object 'suddenly' dissapears from the sensor (as in, exits sideways) it will gradually fade out, rather than just turn fully off as it does at the moment... like wise if an object suddenly enters the sonic range, I want it to fadeup softly, rather than just come on.

Anyway, the amended code so far, if it helps anyone else:

Code:
symbol ultrain =b.5
symbol ultraout=b.4
symbol red=c.2              'Red RGB pin
'symbol green=c.3  		'Green RGB pin
'symbol blue=c.5			'blue RGB pin

symbol range=w0
symbol range_neg=b3

pwmout red,150,150

main:
			
	pulsout ultraout,2 			; produce 20uS trigger pulse (must be minimum of 10uS)
	pulsin ultrain,1,range 		; measures the range in 10uS steps
	pause 30			; recharge period after ranging completes


	let range = range * 100 / 58	; multiply by 10 then divide by 58 to convert range to mm

	
	
if range>285 then  'had to add 30 to range to get full range of dimness to brightness (see line 42)
	
	range=285
	range_neg=1
	
	pwmduty red,range_neg
	goto main

elseif range<30 then     '
	
	range=30   'checking to see if the reading is too close a distance
	range_neg=255
	
	pwmduty red,range_neg
	
	goto main

	
else
	range_neg=-range ' convert the range to 'opposite' so that brightness increase the closer you get.
	range_neg=range_neg+30  'compensating for the fact you can't get to within the last 30mm, otherwise, LED would never fade all the way to 255 (max brightness)
	pwmduty red,range_neg
endif

	goto main
 

vttom

Senior Member
Your code had a bit of an inefficiency. You can take the pwmduty and goto commands outside of the if/else clauses...

Code:
if (some condition) then

 range = blah
 range_neg = blah

elseif (some other condition) then

 range = blah
 range_neg = blah

else

 range = blah
 range_neg = blah

endif

pwmduty red, range_neg
goto main
The reason I bring this up is that in order to do the smoothing, rather than using "range_neg" directly in the pwmduty command, introduce a new variable, eg. "symbol duty = b4".

In the main loop, conditionally increment or decrement the new variable if it's smaller or larger than the target value of range_neg each time through the loop, and use THAT as the value you give to pwmduty....

Code:
' Instead of this
' pwmduty red, range_neg

' Do something like this
if duty > range_neg then
  duty = duty - 1
elseif duty < range_neg then
  duty = duty + 1
endif

pwmout red, duty
 

g6ejd

Senior Member
The LED brightness response will be non-linear with distance, you may find a better alternative is to vary the time between LED flashes so that at extreme range the time between flashes is long and when close up it approaches constant on, where the time between flashes is short.
 

Blazemaguire

Senior Member
Cheers VTTOM,

Based on your advice, I now have this, which works great for a soft fadeup and out... I 'think' this is what you meant, though I'm not entirely sure how the code works now - either way, it's quite cool. - The only issue I have is that it seems to take forever to 'wind up' to max brightness and then back down again (as in, I have to hold my hand at the closest range for a good 15 seconds for it to reach peak brightness.... when I take my hand away, it then takes another 15 seconds for it to dim back to minimum levels.

Is there anyway to increase the rate of acceleration'. - I've tried making duty increase/decrease by larger amounts than 1, but this just causes flickering. - I wish I understood how my code now works! ( I am a bit of a code newbie, so please go easy!) - I can't see anything else that would cause a response time change.


Code:
symbol ultrain =b.5
symbol ultraout=b.4
symbol red=c.2              'Red RGB pin
symbol green=c.3  		'Green RGB pin
symbol blue=c.5			'blue RGB pin
symbol range=w0
symbol range_check=w1
symbol range_check_neg=b4
symbol range_neg=b5
symbol duty = b6
pwmout red,150,150    'set initial PWM duty cycles
pwmout green,150,150
pwmout blue,150,150


main:
	pulsout ultraout,2 			; produce 20uS trigger pulse (must be minimum of 10uS)
	pulsin ultrain,1,range 
	pause 20

	let range = range * 100 / 58	; multiply by 10 then divide by 58 to convert range to mm

if duty > range_neg then
  duty = duty - 1
elseif duty < range_neg then
  duty = duty + 1
endif


	
if range>285 then

 range = 285
 range_neg = 1

elseif range<30 then

 range = 30
 range_neg = 255
 
else
 range_neg = -range
 range_neg=range_neg+30
endif



pwmduty red,duty
pwmduty green,duty
pwmduty blue,duty



goto main
 
Last edited:

vttom

Senior Member
To speed up the rate at which is fades in or out, increase the amount you add to or subtract from duty...

Code:
symbol fade_rate = b7

' Increase fade_rate to fade up/down faster
' Decrease fade_rate to fade up/down slower
fade_rate = 5

if duty > range_neg then
  if duty - range_neg > fade_rate then
    duty = duty - fade_rate
  else
    duty = range_neg
  endif
elseif duty < range_neg then
  if range_neg - duty > fade_rate then
    duty = duty + fade_rate
  else
    duty = range_neg
  endif
endif
 
Top