Using an analog input if it changes by +-10 or more

Morning All

I am building some stepper motor dials, they will be controlled by an analog input, I have them working to the point where the needle will move in relation to the potentiometer but it has some chatter, I have used a a little bit of code to only read once every 500 milliseconds which has helped
if (!(millis() % 500)) {
but it does have some side effects,
what id like to do is update the needle position if the analog input changes by a value of 10 either way but i'm struggling to write this,
the dials will show temperature and fuel levels so don't need the rapid response

below is the code i have that works with the delay,
and below that is what i'm struggling to put together,

[code]
//02/01/23, adding reset button for dials

#include <SwitecX25.h>
// standard X25.168 range 315 degrees at 1/3 degree steps
#define STEPS1 (230)
#define STEPS2 (945)
// For motors connected to digital pins 5, 6, 7, 8   9, 10, 11, 12,. 
SwitecX25 motor1(STEPS1, 9, 10, 11, 12);
SwitecX25 motor2(STEPS2, 5, 6, 7, 8);

#define BatteryLED 2
#define HiBeamLED 3
#define IndiacatorLED 4
#define LED_backlight 5
#define ResetButton A4    //reset buton on pin A4
int sensorValue1 = A0;
int sensorValue2 = A1;


void WarningLightTest(){
  digitalWrite(BatteryLED, HIGH);
  digitalWrite(HiBeamLED, HIGH);
  digitalWrite(IndiacatorLED, HIGH);  
  delay(2000);
  digitalWrite(BatteryLED, LOW);
  digitalWrite(HiBeamLED, LOW);
  digitalWrite(IndiacatorLED, LOW);  
}

void setup() {
  Serial.begin(9600);
  motor1.zero();  // run the motor against the stops
  motor2.zero();  // run the motor against the stops 
  pinMode(BatteryLED, OUTPUT);
  pinMode(HiBeamLED, OUTPUT);
  pinMode(IndiacatorLED, OUTPUT); 
  pinMode(LED_backlight, OUTPUT);
  digitalWrite(LED_backlight, HIGH);
  WarningLightTest(); 
}

void loop() { 
  int stepPosition1;
  int stepPosition2;
  
  // get the sensor value every 5 seconds

    if (!(millis() % 400)) {    //creates a delay for the sensor read, 
    stepPosition1 = (map( analogRead(sensorValue1), 0, 1023, 0, 230 ) );
}
  motor1.update();
  motor1.setPosition(stepPosition1);
  
if (!(millis() % 400)) {
  stepPosition2 = (map( analogRead(sensorValue2), 0, 1023, 0, 945 ) );
}
  motor2.update();
  motor2.setPosition(stepPosition2);
  
  delay (3); //delay to dampen the inertia of the needle.

 }
}

[/code]
[code]
int sensorValue1 = A0;
int valueX =0;

void setup() {
   Serial.begin(9600);

}

void loop() {
  int valueA;
 
  int valueY;
valueA = (map( analogRead(sensorValue1), 0, 1023, 0, 230 ) );


 if (valueA > (valueX + 10)){
   valueX = valueA;
 }
  Serial.print("Value A  ");
  Serial.println(valueA);
  //Serial.print("Value Y  ");
 // Serial.println(valueY);
  Serial.print("Value X  ");
  Serial.println(valueX);

 delay (500);
}
[/code]

Take one reading and store the value as a reference. Then, when reading the pot, check if the new reading differs from the ref by 10 or more. If it does, give the new value to ref and perform the action.

@Wastedspark you may find the abs() function to be of service.

   if (abs(oldValie - newValie) > 5) {... 

a7

Hi thank you both for your replies,

RailRoader,

that sound like what i have in my head but I'm struggling to write it, i'm not pretending to be any good at this most of my code is pieced together from other code.

alto777

thanks, i'll look up the abs function, with that little bit of code you posted i get that if the old value minus the new value is greater than 5 then it'll perform an action, in this case to move my needle forward, but I need to move either way, so if my old value - new value gives a negative value it wont be greater than 5 but may be greater than -5,

You should do that first. abs() is for absolute value, something you might have come acrosss in maths class, unless you missed that day. :wink:

And is perfect for doing exactly what you want, in exactly the way I wrote it, I do certainly hope, but it is tired and I'm getting late, so.

a7

hi i usually use an ai to help solve my problems and i think it found the solution
if you want to use it in the futur to help it is called chat GPT.

It looks like you're trying to make the motor only update when the analog input changes by a certain amount. Here's how you can do that:

  1. Declare a global variable to store the previous value of the analog input.
  2. In the loop function, read the current value of the analog input and store it in a local variable.
  3. Compare the current value to the previous value. If the difference is greater than or equal to the threshold (in your case, 10), then update the motor position and store the current value as the previous value.
  4. If the difference is less than the threshold, then do not update the motor position.

Here's the modified code:

Copy code

#include <SwitecX25.h>
// standard X25.168 range 315 degrees at 1/3 degree steps
#define STEPS1 (230)
#define STEPS2 (945)
// For motors connected to digital pins 5, 6, 7, 8   9, 10, 11, 12,. 
SwitecX25 motor1(STEPS1, 9, 10, 11, 12);
SwitecX25 motor2(STEPS2, 5, 6, 7, 8);

#define BatteryLED 2
#define HiBeamLED 3
#define IndiacatorLED 4
#define LED_backlight 5
#define ResetButton A4    //reset buton on pin A4
int sensorValue1 = A0;
int sensorValue2 = A1;
int previousValue1 = 0; // initialize previous value to 0
int previousValue2 = 0;

void WarningLightTest(){
  digitalWrite(BatteryLED, HIGH);
  digitalWrite(HiBeamLED, HIGH);
  digitalWrite(IndiacatorLED, HIGH);  
  delay(2000);
  digitalWrite(BatteryLED, LOW);
  digitalWrite(HiBeamLED, LOW);
  digitalWrite(IndiacatorLED, LOW);  
}

void setup() {
  Serial.begin(9600);
  motor1.zero();  // run the motor against the stops
  motor2.zero();  // run the motor against the stops 
  pinMode(BatteryLED, OUTPUT);
  pinMode(HiBeamLED, OUTPUT);
  pinMode(IndiacatorLED, OUTPUT); 
  pinMode(LED_backlight, OUTPUT);
  digitalWrite(LED_backlight, HIGH);
  WarningLightTest(); 
}

void loop() { 
  int stepPosition1;
  int stepPosition2;
  
  // get the current value of the analog input
  int currentValue1 = analogRead(sensorValue1);
  int currentValue2 = analogRead(sensorValue2);

  // compare the current value to the previous value
  if (abs(currentValue1 - previousValue1) >= 10) {
    // update the motor position and store the current value as the previous value
    stepPosition1 = (map(currentValue1, 0, 1023, 0, 230));
    previousValue1 = currentValue1;
  }
  if (abs(currentValue2 - previousValue2) >= 10) {
    // update the motor position and store the current value as the previous value
    stepPosition2 = (map(currentValue2, 0, 1023, 0, 945));
    previousValue2 = currentValue2;
 

thanks i'll give those ideas a try,

i was told recently to invest in chat GPT.

thank you all,

so I had a look at the ABS() function and tried the code above and both gave me the result I expected, with the ABS() function turning a negative value into a positive I could only see the needle moving clockwise, so I tried the code above which did almost exactly this, no matter which way I turned the pot the value would increment and the needle would move clockwise, until it reached the end and then it would only move anticlockwise,
this maybe to do with the stepper library I'm using.

so I've carried on with the theory and with what rail roader mentioned and came up with this which seems to work quite well, although it doesn't always go back to zero,

and I had to put in "else if" rather than "else" to make it work??

[code]
//03/01/23, added code to only move the stepper if the analog read is +/-10


#include <SwitecX25.h>
// standard X25.168 range 315 degrees at 1/3 degree steps
#define STEPS1 (230)
#define STEPS2 (945)
// For motors connected to digital pins 5, 6, 7, 8   9, 10, 11, 12,. 
SwitecX25 motor1(STEPS1, 9, 10, 11, 12);
SwitecX25 motor2(STEPS2, 5, 6, 7, 8);

#define BatteryLED 2
#define HiBeamLED 3
#define IndiacatorLED 4
#define LED_backlight 5
#define ResetButton A4    //reset buton on pin A4
int sensorValue1 = A0;
int sensorValue2 = A1;
int valueA;
int valueB;
int valueC;
int valueD;

void WarningLightTest(){
  digitalWrite(BatteryLED, HIGH);
  digitalWrite(HiBeamLED, HIGH);
  digitalWrite(IndiacatorLED, HIGH);  
  delay(2000);
  digitalWrite(BatteryLED, LOW);
  digitalWrite(HiBeamLED, LOW);
  digitalWrite(IndiacatorLED, LOW);  
}

void setup() {
  Serial.begin(9600);
  motor1.zero();  // run the motor against the stops
  motor2.zero();  // run the motor against the stops 
  pinMode(BatteryLED, OUTPUT);
  pinMode(HiBeamLED, OUTPUT);
  pinMode(IndiacatorLED, OUTPUT); 
  pinMode(LED_backlight, OUTPUT);
  digitalWrite(LED_backlight, HIGH);
  WarningLightTest(); 
}

void loop() { 
  
   valueB = (map( analogRead(sensorValue1), 0, 1023, 0, 230 ) );
 if (valueB > (valueA + 10)){
  valueA = valueB;
 }
 else if (valueB < (valueA -10)){
  valueA = valueB;
 }
  motor1.update();
  motor1.setPosition(valueA);


valueD = (map( analogRead(sensorValue2), 0, 1023, 0, 945 ) );
 if (valueD > (valueC + 10)){
  valueC = valueD;
 }
 else if (valueD < (valueC -10)){
  valueC = valueD;
 }
  motor2.update();
  motor2.setPosition(valueC);
  
  delay (3); //delay to dampen the inertia of the needle.
 }



  

[/code]

It's fun but will never be a substitute for knowing how to program, and in the long run will take more of your time than just learning how to yourself would.

Every time you drag chatGPT code into these as yet human orientated fora, I will post a request that you don't, and a count of how many times I have done.

This is number two. Just. Stop.

a7

Ummm, abs() (not ABS()) woukd work if you thought about it.

Besides, both bodies are the same

   valueA = valueB;

That can't be doing much for you, prolly isn't what you meant…

a7

It really is worth your time to play about with writing your own stuff , trying to adapt others code can be frustrating and difficult to modify if you don’t fully under stand it -as in this case.
Often code from the internet is poorly written and often doesn’t work !

Ignore the stepper motor stuff for a moment and just take your analog input and print the value to the serial monitor, then try some of the suggestions here by only printing if the analog value from your pot changes by a certain amount (10?) .
Try that and come back if you have a problem with that .
The IDE also has examples for analog input and printing values to the monitor .

Thanks alto777, unfortunately my brain doesn’t think the right way😀 this is really just a bit of a hobby for me, what effect would the valueA = valueB; have?
My reason for writing it was to update the value to be compared to the analog read.

Hammy

I agree with trying to do it yourself, I’ve been reading and learning a lot lately, I did just as you suggested and wrote the code with just the serial monitor, I got it to work as I wanted with the value only incrementing or decrementing if the analog value was +- 10 then copied it over to my stepper motor sketch,

this is your friend

its not obvious but we use the equals sign for two different things;
ASSIGNMENT

A = B makes A equal to B
and "if A equals B" - a COMPARISON test.

As C doesnt iknow which we mean, we have to show the diference in our code.

the equals sign A=B makes A equal to B; while

if (A==B ) does a comparison - WITHPIUT CHANGING A OR B.

Ok I understand that,

I’m my code I want ValueA to be changed to valueB if B was more than 10 greater than A, so a single = would be correct?

Or am I missing something,

No, sry sry sry, it is my brain that needs, well, whatever. I see your logic and I may be wrong but it looks right.

 if (valueB > (valueA + 10)){
  valueA = valueB;
 }
 else if (valueB < (valueA -10)){
  valueA = valueB;
 }

That's fine now I got the sand out of my ears.

 if (abs(valieA - valieB) > 10)
  valieA = valieB;

shoukd do the same thing. And is, I think, more common.

"only put B into A if the distance is greater than 10"

We use absolute value of the difference as the distance, distances always being positive.

I hope. No sand, but it is very hot here even under the umbrella.

Again, appy polly loggies.

a7

No need to apologise I have a very mechanical mindset.
I tried the abs line but it didn’t work for me,

Could you be less vague? What result did it produce and in what way did that differ from the results your version yielded?

I have placed both version of the test into the wokwi simulator. Please go play with it, then tell me why you didn't get the same thing to work.


absolute value vs. if/else/if      <- link to the simulation of the code below.


// https://wokwi.com/projects/352860710843105281
// https://forum.arduino.cc/t/using-an-analog-input-if-it-changes-by-10-or-more/1072641

void setup() {
  Serial.begin(9600);
}

void loop() {
  static int oldReading1, oldReadig2;
  int reading = analogRead(A0);

//  Serial.print(reading);

  if (abs(oldReading1 - reading) > 50) {
    oldReading1 = reading;

    Serial.print(reading);
    Serial.println(" is different enough! abs version");
  }

 if (reading > (oldReadig2 + 50)) {

  oldReadig2 = reading;

  Serial.print("     ");
  Serial.print(reading); 
  Serial.println(" is different enough! verbose version");
 }
 else if (reading < (oldReadig2 - 50)) {

  oldReadig2 = reading;

  Serial.print("     ");
  Serial.print(reading);
  Serial.println(" is different enough! verbose version");
 }

  delay(333);
}

If you can't read and follow the things ppl say here, and get them correct, keep trying! And supply enough information, code often (!), that will let us see where you are going off the rails, in the cases where you do and it isn't one of us who is water logged and misleading you. :wink:

HTH and enjoy using the wokwi simulator!

a7

Thanks I’ll give that a go, it’ll be a couple of days until I get back to the PC,

A little vague, I had previously mentioned that when I tried the abs() version the stepper motor wouldn’t follow the potentiometer,

No matter if I turned the pot clockwise or anti clockwise the stepper would only move clockwise until it got to the end of its range where it would do the same but anti clockwise,

I’ll go back and try it with just the serial monitor

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.