ADC fluctuations

ZOR

Senior Member
I am trying to use a potentiometer to move a stepper back and forth.
However, looking at my ADC values in debug, it fluctuates by plus and minus 1 value on certain parts of the pot. As I am trying to compare the value of b1 against a previously filled in variable b2, and use it to tell me if the pot was turned up or down. But because of the fluctuations its obviously causing problems.

So I was trying to register a change only if the ADC value had changed by 3 units in either direction, and thats where I cannot seem to get it right.

How can register the change if the change from last time is more than a value of 2 or 3, so the ADC fluctuation is ignored unless it's a bigger value change

Hope I am not confusing everybody.
 

Jamster

Senior Member
Code:
readadc C.0,b1
b1 = b1 / 3 'scale down
b1 = b1 * 3 'scale up again at lower resolution
That what you wanted?
Jamster

P.S. A great reason why PICAXE shouldn't have floating point maths actually....
 

g6ejd

Senior Member
A quick and dirty way to reduce reading noise is to do something like:

reading = reading & %11111100

This would remove the two least signficant bits so your readings would step like this 0 4 8 12 16 20 etc or a reading that was dithering around e.g. 127 (such as 126,127,127,128,129) would become 124 and minor changes would not be seen.

There would be a dead band around the reading.

To make it just 1-bit of noise reduction try:

reading = reading & %11111110

Alternate methods are to keep a running average and compare a new reading with that, or use your running average as the value for stepper movement, perhaps a running average of 3 readings.

:) Jamsters achieved the same result, same thinking...different approach.
 

ZOR

Senior Member
Many thanks for both replies. I tried Jamsters idea as it was simplest to paste in, b1 = b1 / 3 'scale down
It works a treat, b1 is very stable and useable now, gives me values 0-85, which I should be able to use. Will keep both methods in my head for next time, thanks again
 

ZOR

Senior Member
Thought I was going to be okay, however lower resolution gives me smaller rotational postioning of my stepper. I tried increasing the loops in motor rotation to make up for lost rotation but then it was moving too far each time.
In addition, I kept the changes in b1 in a variable to compare with each time, and that produced an ever diminishing circle of movement.
All I am trying to do is move my servo with a pot. Any other ways? Thanks
 

MartinM57

Moderator
You need "hysteresis"...doesn't reduce the scaling, but only lets the value move if the difference to last time is bigger than a certain amount. Something like...

Code:
symbol lastTime = b0
symbol thisTime = b1
symbol diff = b2
symbol HYSTERESIS = 3

DO
	get_however_you_want thisTime

	'Hysteresis check - find positive difference
	IF thisTime >= lastTime THEN
		diff = thisTime - lastTime 
	ELSE
		diff = lastTime - thisTime 
	ENDIF
	
	'Keep value as the same as last time if difference is less than hysteresis amount...
	'...otherwise, let the new value continue
	IF diff <= HYSTERESIS THEN
		thisTime = lastTime
	ENDIF

	do_whatever_you_want_with thisTime

	'ready for next loop
	lastTime = thisTime

LOOP
 

ZOR

Senior Member
Thanks Martin.

I realised afterwards what Jamster meant in his second line "b1 = b1 * 3 'scale up again at lower resolution" I added this line in and got my 0 - 255 values. However I now find I cannot achieve 180 degrees control/movement from the pot, unless I increment each step in a loop value to acomplish 180 degrees. But doing that I lose controllability because it moves too far with each step movement of my pot, ie I have to wait for each loop to finish before I can tell it to stop or go in the other direction. Actually, stupidly as I am writing this, maybe I should interfere between my loops with EXIT commands. Always the simple things that are not!

I will relook at it, and look at what you have suggested, useful code, thanks
 

boriz

Senior Member
"it fluctuates by plus and minus 1 value" READADC or READADC10 ? (I'm guessing the former 'coz you're using a byte variable?)

" on certain parts of the pot" Pots are a notorious source of noise. A bit of dust could do that. A slightly worn bit of track could do that. A nearby mains lead could do that.

+ or - 1 is actually a very small noise. A capacitor, or a little software averaging (the big boys call it digital filtering) will fix it. A new pot is unlikely to be any better.
 
Last edited:

boriz

Senior Member
I have no idea how much you know about electronics and components. Please bear with me if this is obvious to you:

A potentiometer is usually made with a strip of resistive material a few cm long (call it a carbon track antenna) and a copper contact that can touch the track at any point.
The sprung contact moves along the track when you turn the shaft. (the knob will come later)

It's a physical push-and-drag effect and every movement wears out the carbon track a little. Although the pot manufacturers try to minimize the noise, there is always some.

Break open a pot and examine the contact. You'll see what I mean.
 
Last edited:

ZOR

Senior Member
Thanks for all the replies. Yes I do have some knowledge of potentiometers, and understand they can be noisey. They are new, audio type with physical stops/steps. They are 10k Linear.

Maybe because it's my first time with steppers that I am wrongly expecting them to behave like servo motors, being responsive to positional change from a potentiometer. In my head I am thinking how fast they move to a position in a printer. Is there a non damaging way to speed it's movement from A-B, so I can stretch out 180 movement without having to wait so long for it to get to a position. Is there a rule of thumb for resting values allowing the motor to cool down or does that depend on each motor type.
I will try and see how many steps it takes to give me 180 degrees movement and relate that to what loop values are needed in each step of my ADC value. Thanks for now, I will just play around myself and do a bit more reading up.
 

ZOR

Senior Member
This is the code I am using, maybe something wrong or can be improved

Code:
DirsB = %11111111

Symbol rest = 3

DP:
readadc C.4,b1
b1 = b1 / 3 'scale down
b1=b1*3

IF b2=0 then
b2=b1
else
if b1>b2 then ' Go forward

b2=b1

FOR b6 =1 TO 2

let PinsB = %00001010  
pause rest
let PinsB = %00010010 
pause rest
let PinsB = %00010100  
pause rest
let PinsB = %00001100 
pause rest  

NEXT

else

if b1<b2 then ' Go reverse
b2=b1

FOR b6 = 1 to 2
 
let PinsB = %00001100  
pause rest 
let PinsB = %00010100  
pause rest
let PinsB = %00010010 
pause rest
let PinsB = %00001010 
pause rest
 
NEXT
 
end if:end if:end if
I have played with my loops to extend the motor travel over 180 degrees, however produces too bigger steps of physical movement.

Thanks
 

srnet

Senior Member
If the reading is on the borderline between;

%11111100
%11111011

And you drop the bottom two bits with a logical AND do you now in effect have 4 bits of noise ?
 

ZOR

Senior Member
Many thanks srnet, but sorry you have lost me in the world of science! My knowledge is not very deep in all this.
 

MFB

Senior Member
Now for a simple hardware approach. You may find that just adding a capacitor between the ADC input and ground will reduce the noise. This will form an RC low-pass filter with the potentiometer. Unfortunately the cut-off frequency will change with the wiper position but this effect can be reduced by adding a resistor at the junction of the ADC input and capacitor. Try starting with a 1K series resistor and 0.1uf capacitor.
 

inglewoodpete

Senior Member
You are ALWAYS going to get a variation of +/- 1. It's taught in "ADC 101". That's because any analogue input, no matter how steady the value is, will not exactly match the steps of it's digital conversion. The ADC will always approximate that last bit.
 
Last edited:

MartinM57

Moderator
readadc C.4,b1
b1 = b1 / 3 'scale down
b1=b1*3

Chosen at random, say b1 has the value 89
/3 then *3 with PICAXE maths gives 29 then 87

..then b1 goes to 90
/3 then *3 with PICAXE maths gives 30 then 90

...so a change of 1 in the readadc gives a change in 3 in the position. Doesn't sound like what you want.

With my hysterisis code, then imagine a noisy b1 series in time...
89 -> 89
90 -> 89
91 -> 89
90 -> 89
93 -> 93
(I might be "out by one" on these)
...you will still get big jumps but the noise should disappear.

The /3 then *3 and even my hysteresis code don't give you fine precision and noise reduction at the same time - you would have to go to something much more complex if you really wanted to pursue this (or use simple hardware noise suppression, but as IWP says, you are still likely to get noise in the least significant bit)
 

ZOR

Senior Member
Sorry I don't know. I got this from code that eclectic was good enough to give me and get my motor moving.


Code:
#picaxe 14M2

DirsB = %11111111

Symbol rest = 5 ; change as required
Symbol degstep = 100 ; change as required

Main:

gosub Clockwise
pause 1000

Gosub Anti
Pause 1000

goto main

Clockwise:

      for b0 = 1 to degstep  
      
     let PinsB = %00001010  '1 
  pause rest
 
 let PinsB = %00010010  '2  
  pause rest
 
 let PinsB = %00010100  '3  
 pause rest
 
 let PinsB = %00001100  '4  
  pause rest  
  
  next

return  

 ANTI:
 
  for b0 = 1 to degstep  
   
 let PinsB = %00001100  '4   
  pause rest 
  
  let PinsB = %00010100  '3  
 pause rest
 
  let PinsB = %00010010  '2  
  pause rest
  
  let PinsB = %00001010  '1 
  pause rest
  
  next
 
return
Thanks
 

eclectic

Moderator
Sorry I don't know. I got this from code that eclectic was good enough to give me and get my motor moving.


Code:
#picaxe 14M2

DirsB = %11111111

Symbol rest = 5 ; change as required
Symbol degstep = 100 ; change as required

Main:

gosub Clockwise
pause 1000

Gosub Anti
Pause 1000

goto main

Clockwise:

      for b0 = 1 to degstep  
      
     let PinsB = %00001010  '1 
  pause rest
 
 let PinsB = %00010010  '2  
  pause rest
 
 let PinsB = %00010100  '3  
 pause rest
 
 let PinsB = %00001100  '4  
  pause rest  
  
  next

return  

 ANTI:
 
  for b0 = 1 to degstep  
   
 let PinsB = %00001100  '4   
  pause rest 
  
  let PinsB = %00010100  '3  
 pause rest
 
  let PinsB = %00010010  '2  
  pause rest
  
  let PinsB = %00001010  '1 
  pause rest
  
  next
 
return
Thanks


See Man. 3, page 15 for the reasoning behind the sequences

e
 

hippy

Ex-Staff (retired)
If the reading is on the borderline between;

%11111100
%11111011

And you drop the bottom two bits with a logical AND do you now in effect have 4 bits of noise ?
I would say that is a fair way to describe it.

You can reduce the number of positions on the pot where the noise will be noticeable but the potential for noise remains. You can minimise the size of the positions on the pot where this noise is observed but even with RC's in the circuit you can never completely remove this noise because whenever the ADC input is on the boundary between returning one value and the next it can still flip between the two with smallest of changes.
 

ZOR

Senior Member
Dont worry folks, I am going to get rid of the pot and go for buttons, hold the button down it moves, let go it stops. Technology up my street.!!
 

eclectic

Moderator
Dont worry folks, I am going to get rid of the pot and go for buttons, hold the button down it moves, let go it stops. Technology up my street.!!
Before you build it, think about adding
an InfraRed remote.

Cheap £1 remote and a cheap IR receiver.

See M.2, p.125

e
 

ZOR

Senior Member
Thanks for the suggestion, I will give that some serious thought as alternative. Best regards
 

Goeytex

Senior Member
ZOR,

Don't give up on the Pot !

I built and tested this and it works fine !

If all you want to do is to "move the stepper back and forth using a pot", then then code below should work fine. Move the pot to the left from center and the stepper goes one direction. Move the pot to the right and the stepper goes the other direction. When the pot is in the center, the stepper is off. ADC noise will not be an issue.

I retained the oddball wiring & sequence, but since you are using pinsB = you might consider swapping the wires around and using the more common software/code sequence format of 1100,0110,0011,1001 for one direction and 0011,0110,1100,1001 for the other.

You did not say what Picaxe you are using so I assumed a 20M2.


Code:
#picaxe 14M2
#no_data


symbol value = b0
symbol counter = b1
symbol rest = 5
setfreq m8
  

dirsB = %00011110

Main: 

do

   readadc C.4,Value
   sertxd (#Value,CR,LF)
      if value >= 175 then
            
         for counter = 1 to 6  ' 24 steps forward
                     
             let PinsB = %10100 : pause rest
             let PinsB = %10010 : pause rest 
             let PinsB = %01010 : pause rest
             let PinsB = %01100 : pause rest
        
         next
                   
         let PinsB = %00000 'Motor off (saves power but no holding torque)  
         pause 2000          
              
      elseif  value <= 80 then   ' 24 steps backward 
      
          for counter = 1 to 6

             let PinsB = %01010 : pause rest
             let PinsB = %10010 : pause rest
             let PinsB = %10100 : pause rest
             let PinsB = %01100 : pause rest 
                              
          next
         
          let PinsB = %00000 ' motor off (saves power)  
          pause 2000
      
      endif      
 loop
 
Last edited:

ZOR

Senior Member
I just looked at the manual referenced by you. I thought it was just how to interface IR into a PICAXE, I did not realize it would offer the permutations from a remote control keypad. One of my cameras is on an outside wall, and I was playing around with 4 channel 433mhz cheap Ebay TX/RX but range not so good.

Is it feaseable to open up a remote control, and remove the TX IR, and stick on the end of a longish cable (screened or whatever). I've got a few remotes lying around, just wondered if anyone else has tried. If thats the case then it offers a lot of options.
 

eclectic

Moderator
I just looked at the manual referenced by you. I thought it was just how to interface IR into a PICAXE, I did not realize it would offer the permutations from a remote control keypad. One of my cameras is on an outside wall, and I was playing around with 4 channel 433mhz cheap Ebay TX/RX but range not so good.

Is it feaseable to open up a remote control, and remove the TX IR, and stick on the end of a longish cable (screened or whatever). I've got a few remotes lying around, just wondered if anyone else has tried. If thats the case then it offers a lot of options.
You could use an IR LED
and the Irout command
M.2, p.127

e
 

ZOR

Senior Member
Thanks Goeytex, I missed seeing your suggestion arrive. I am using a 14M2, just for trial on one stepper, will go up to a 20M2 when I know what I am doing and need to control two steppers. Would it make a performance difference changing my software/code sequence or result in the same? Also, I am not using the "setfreq" command as yet, will look it up. Thanks
 

ZOR

Senior Member
Many thanks eclectic, that is very useful. I have brushed through the manual before, but never read up on that section. Yes you were correct in suggesting IR for a remote stepper direction switches arrangement. I will still try Goeytex's code, but for button arrangements then IR is good. The TX and RX can sit in a tube opposite each other.
 

Goeytex

Senior Member
@ZOR

The code I posted should work fine on a 14m2. Just change the directive to #Picaxe 14m2 ... instead of #Picaxe 20M2. Setfreq M8 speeds things up and reduces processor overhead. Notice that I changed the "rest" value to 5. This could make for a bit smoother stepping.

Changing the sequence / wiring to the more common format will not give you any performance gain. That is just Rev-Ed's way of doing it to allow the use of "toggle" using 2 Picaxe Outputs instead of 4. I recommended the change so that the code looks more "normal" , since you are using 4 outputs with "PinsB =", and not the toggle command.

Just copy and paste the code and make the directive change and try it out.
 

ZOR

Senior Member
I cut and pasted the code in. Changed my motor connections so the motor ran.

It was so slow, the fastest I could make the motor turn was by changing the rest value to 2, changing the pause to 200. And even that it was too slow. The only thing I found useful was being able to stop the motor by going to the pot centre position. However, if I left the pot at one end, then the motor just kept going round, never stopped, even removing the loops it still did not stop.

So I have put my wiring back, and put back eclectic's code.

??
 

Goeytex

Senior Member
You did not need to change your motor connections.

I clearly stated that I left the sequence as you had it. (See the post and the code) . If you changed the connections then you would have had to change the sequence in the code.
 

ZOR

Senior Member
Thanks. I tried the code again and the motor just creeps along, barely moving. I reduced the rest down to 2 in attempt to get more movement but it just jumped from position to position.
Don't know why, but eclectic's code just works fine.
 

Goeytex

Senior Member
Thanks. I tried the code again and the motor just creeps along, barely moving. I reduced the rest down to 2 in attempt to get more movement but it just jumped from position to position.
Don't know why, but eclectic's code just works fine.
Oh Well, It works perfect here for me with both a 20M2 and a 14M2. I am using a 12V, 7.5 degree unipolar stepper motor driven by a ULN2803. Since you have not provided any kind of diagram, motor specs, etc... I can only guess that you have some kind of strange stepper motor or an unusual driver / connection combination.

CORRECTION : I copied the odd sequence wrong from Manual 3 . It is now corrected in the previously posted code. I even changed my wiring to match the code and all is well. You may have to add or subtract some values from "rest" to get it running idealy. I even changed the "rest" (temporarily) to 400 to verify each step.

Good Luck
 
Last edited:
Top