Virtual Robot icon Virtual Robot Display robot image with real-time servo position readouts and basic servo management including servo deletion Try it →
Asked — Edited
Resolved Resolved by Athena!

Arduino Loop Increment Issue Fix

@Athena,

I am currently running the following code on an Arduino Mega to adjust a variable iteratively:

float psudoActCrs = 90.7550;
float actualCourse = 92;

while (true) {
  if (psudoActCrs < actualCourse) {
    psudoActCrs += 0.1;
  }
  if (psudoActCrs > actualCourse) {
    psudoActCrs -= 0.1;
  }
  Serial.print("psudoActCrs:  ");
  Serial.println(psudoActCrs, 4);
  Serial.print("actualCourse:  ");
  Serial.println(actualCourse, 4);

  if (psudoActCrs == actualCourse) {
    break;
  }
}

My aim is to increment 'psudoActCrs' by 0.1 in each iteration of the loop until it matches or exceeds 'actualCourse'. However, I want to avoid triggering both conditions (< and >) at the same time. How can I properly manage the loop so it exits correctly when 'psudoActCrs' equals or exceeds 'actualCourse'?

Thanks,
Jack



Related Hardware (view all EZB hardware)
Synthiam ARC enables Arduino Mega 2560 control with 8 ADC, 13 PWM, 21 digital ports and 24 servos; includes firmware, shield and tutorials
USB
Servos 24
Camera
Audio
UART 3
I2C
ADC 8
Digital 21

Related Robot Skills (view all robot skills)
Serial Terminal by Synthiam
PC and EZB serial terminals for ARC: connect, monitor and send text/ASCII to serial devices. Supports COM, flow control, baud, DTR/RTS, hex
Arduinocoms by ShadowStudios
EZB v4-Arduino I2C bridge for ARC: supports custom C# code and reads gamepad or Wii controller inputs for robot control

ARC Pro

Upgrade to ARC Pro

Unleash your creativity with the power of easy robot programming using Synthiam ARC Pro

Author Avatar
PRO
Canada
Twitter YouTube GitHub
#1  

Good question - this is a classic floating-point loop issue. Two points to keep in mind:

  • Never rely on exact equality with floats (e.g., psudoActCrs == actualCourse) - binary floating point rarely hits decimal steps exactly.
  • Prefer a loop condition that directly represents your stopping criteria (e.g., loop while psudoActCrs < actualCourse), or use an integer/tenth representation to avoid rounding problems.

Below are two robust solutions for Arduino (Mega/Due) you can use.

  1. Keep floats, use an epsilon and explicit loop condition
  • Loop while psudoActCrs is less than actualCourse.
  • Use a small tolerance (epsilon) to detect "close enough".
  • Optionally clamp to actualCourse when you exceed it.
float psudoActCrs = 90.7550;
float actualCourse = 92.0;
const float step = 0.1f;
const float EPS = 0.0005f; // tolerance

while (psudoActCrs + EPS < actualCourse) {   // loop until we reach (within EPS) actualCourse
  psudoActCrs += step;

  // if we overshot, clamp to exact value
  if (psudoActCrs > actualCourse) psudoActCrs = actualCourse;

  Serial.print("psudoActCrs: ");
  Serial.println(psudoActCrs, 4);
  Serial.print("actualCourse: ");
  Serial.println(actualCourse, 4);

  delay(10); // optional, prevents hammering serial/CPU
}
  1. Best: use integer math (avoid float rounding)
  • Multiply values by 10 (or 100) and use integers.
  • This avoids floating-point rounding entirely when stepping by 0.1.
float psudoActCrs_f = 90.7550;
float actualCourse_f = 92.0;

int psudoTenths = (int)round(psudoActCrs_f * 10.0f);  // e.g. 907
int actualTenths = (int)round(actualCourse_f * 10.0f); // e.g. 920

while (psudoTenths < actualTenths) {
  psudoTenths += 1; // one tenth
  float psudoActCrs = psudoTenths / 10.0f; // for printing or use

  Serial.print("psudoActCrs: ");
  Serial.println(psudoActCrs, 4);
  Serial.print("actualCourse: ");
  Serial.println(actualCourse_f, 4);

  delay(10);
}

// convert back if needed
psudoActCrs_f = psudoTenths / 10.0f;

Notes and tips

  • Use while(psudoActCrs < actualCourse) rather than while(true) so the loop termination is explicit.
  • If your start value can be greater than actualCourse, handle both directions (increment or decrement) or normalize using the integer method with comparison operators (< or >).
  • Add a safety counter or timeout if the values could be modified elsewhere to avoid infinite loops.
  • If you need the variable to exactly equal actualCourse at the end, clamp it (psudoActCrs = actualCourse) after exiting the loop.

If you want, I can:

  • Show the version that supports both incrementing and decrementing depending on start vs target.
  • Convert this into a small ARC-compatible JavaScript/Python script if you plan to run the iteration inside an ARC script instead of the Arduino firmware.

Also: since you mentioned Arduino Due/Mega EZB firmware, here’s the Synthiam support page in case you want to review firmware details: https://synthiam.com/Support/Hardware/Arduino-Due-Mega

Which behavior do you want if psudoActCrs starts above actualCourse - decrement or still increment?


I am a customer support GPT-powered AI and still learning. If you have doubts about my response, please use the support documentation to verify my answer.
#2  

Thank you @Athena.  I am using your 2nd recommendation.

Best: use integer math (avoid float rounding) Multiply values by 10 (or 100) and use integers.

Jack

Author Avatar
PRO
Canada
Twitter YouTube GitHub
#3  

Nice choice - integer math will make this robust and simple. Below are compact, safe examples you can drop into your Arduino Mega sketch. They use a multiplier (10 for 0.1 steps, 100 for 0.01, etc.), handle both incrementing and decrementing, include a safety counter, and clamp the final value to the exact target if you want an exact match.

Important notes:

  • Use lround() (or round()) when converting floats to integers to avoid truncation bias.
  • Use long (or int32_t) for the integer representation to avoid overflow if you scale by 100+.
  • Add a safety timeout to avoid infinite loops if something else changes the values or they never converge.
  1. Basic tenths (0.1 steps) - handles both directions
float psudoActCrs = 90.7550;
float actualCourse = 92.0;

// Multiply by 10 to step by 0.1
long psudoTenths = lround(psudoActCrs * 10.0);
long actualTenths = lround(actualCourse * 10.0);

// Determine step direction
int step = (psudoTenths < actualTenths) ? 1 : -1;

// Safety counter
unsigned long safety = 0;
const unsigned long SAFETY_LIMIT = 100000UL;

while ((step > 0 && psudoTenths < actualTenths) ||
       (step < 0 && psudoTenths > actualTenths))
{
  psudoTenths += step; // one "tenths" per loop -> +/-0.1
  float psudoActCrs_now = psudoTenths / 10.0f;

  Serial.print("psudoActCrs: ");
  Serial.println(psudoActCrs_now, 4);
  Serial.print("actualCourse: ");
  Serial.println(actualCourse, 4);

  delay(10); // throttle loop / friendly to CPU & Serial

  if (++safety > SAFETY_LIMIT) {
    Serial.println("Safety limit reached, breaking loop");
    break;
  }
}

// Optional: clamp to exact target if you require exact equality
psudoActCrs = actualCourse;
Serial.print("Final psudoActCrs (clamped): ");
Serial.println(psudoActCrs, 4);
  1. If you need higher resolution (0.01 steps) - multiply by 100
// same pattern but use multiplier = 100
long psudoHundredths = lround(psudoActCrs * 100.0);
long actualHundredths = lround(actualCourse * 100.0);
int step = (psudoHundredths < actualHundredths) ? 1 : -1;
// loop same as above, divide by 100.0 when printing

Why this fixes your original problem

  • Floating point addition/subtraction by 0.1 rarely lands exactly on decimal values due to binary representation. Integer math (stepping tenths/hundredths) avoids that.
  • The loop condition uses < or > on integers, so you won't miss the target or get stuck expecting exact float equality.
  • Clamping at the end guarantees the final variable equals actualCourse if you need that.

Want this as an ARC-compatible JavaScript/Python snippet instead?

  • I can convert the same logic to an ARC script (JavaScript preferred per Synthiam guidance) if you intend to run the loop inside ARC rather than on the Arduino firmware.

Also: are psudoActCrs and actualCourse only local variables on the Arduino, or do they get updated from sensors/ARC while the loop runs? If values can change externally, that affects whether you should use a loop like above or a step-per-timer approach.


I am a customer support GPT-powered AI and still learning. If you have doubts about my response, please use the support documentation to verify my answer.