Asked — Edited
Resolved Resolved by Athena AI!

Wheel Counting With Arduino

Hello @Athena,

Could you please review the following code that I am using on my Arduino Mega 2560 to count motor pulses? I am encountering an issue with the output on the Serial Monitor.

int encoderValue_A = 0;
int encoderValue_B = 0;

void setup() {
  Serial.begin(9600);
  pinMode(2, INPUT);
  pinMode(3, INPUT);
  attachInterrupt(digitalPinToInterrupt(2), countA, RISING);
  attachInterrupt(digitalPinToInterrupt(3), countB, RISING);
}

void loop() {
  // Check if there is data available to read
  if (Serial.available() > 0) {
    // Read the incoming data from the EZ-B
    int incomingByte = Serial.read();
    Serial.print("Received: ");
    Serial.println((char)incomingByte);

    // Command 'a' indicates transmitting the current values and resetting the counters
    if (incomingByte == 'a') {
      delay(50);

      // Send the encoder values
      Serial.write(encoderValue_A);
      Serial.write(encoderValue_B);

      // Print the encoder values to the Serial Monitor
      Serial.print("Encoder A: ");
      Serial.println(encoderValue_A);
      Serial.print("Encoder B: ");
      Serial.println(encoderValue_B);

      // Reset the encoder values
      encoderValue_A = 0;
      encoderValue_B = 0;
    }
  }
}

void countA() {
  encoderValue_A++;
}

void countB() {
  encoderValue_B++;
}

Here is the output that appears on the Serial Monitor:

Received: a
XXEncoder A: 0
Encoder B: 0

The "XX" in front of "Encoder A" are displayed as square boxes, almost like placeholders. Could you help me understand what these characters are and how I can remove them?

Thank you,
Jack


Related Hardware Arduino Due/Mega
Related Control Wheel Encoder Counter

ARC Pro

Upgrade to ARC Pro

Get access to the latest features and updates before they're released. You'll have everything that's needed to unleash your robot's potential!

PRO
Canada
#73  

Thank you,@DJ_Sures,for the detailed explanation!Let's break it down further to ensure clarity.

Understanding Binary vs. String Transmission

  1. Binary Transmission:

    • What It Is: Sending data as raw numerical values.
    • How It Works: Each number is sent as a single byte (or multiple bytes if the number is large).
    • Example: If you send the number 65, it is transmitted as a single byte with the value 65.
    • Use Case: Ideal for numerical data, such as sensor readings or control signals, where efficiency and precision are crucial.
  2. String Transmission:

    • What It Is: Sending data as a sequence of characters.
    • How It Works: Each character in the string is converted to its ASCII value and sent as a byte.
    • Example: The string "65" is sent as two bytes: 54 (for '6') and 53 (for '5').
    • Use Case: Suitable for text data where human readability is important, such as messages or commands.

Why Binary is Preferred for Numerical Data

  • Efficiency: Binary transmission uses fewer bytes, reducing the amount of data sent over the communication channel.
  • Precision: Avoids conversion errors that can occur when interpreting strings as numbers.
  • Speed: Faster transmission and processing, as there's no need to convert between strings and numbers.

Practical Example

Let's say you want to send the number 123:

  • As a Binary Number: You send a single byte with the value 123.
  • As a String: You send three bytes: 49 (for '1'), 50 (for '2'), and 51 (for '3').

Conclusion

For numerical data, always prefer binary transmission to ensure efficiency and accuracy. Strings are best reserved for text data where readability is a priority.

If you have any more questions or need further clarification, feel free to ask!


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.
#74  

Thank you @Athena for the clarification. I still need to ponder this new information to be sure I understand.   In the mean time, I am having trouble compiling my Arduino code.  Can you find the errors?

volatile int AencoderValue_A = 0;
volatile int AencoderValue_B = 0;
volatile unsigned long AB_EncoderTot = 0;
volatile unsigned long lastDebounceTimeA = 0;
volatile unsigned long lastDebounceTimeB = 0;
const unsigned long LeftMotFwdSensDebounceDelay = 5;
const unsigned long RightMotFwdSensDebounceDelay = 7;
volatile unsigned long adjacentDistance = 0;
int pathTotalDistance = 0;
int pathEndpointDistance = 1;
int oppositeDistance = 0;
int actualCourse;
volatile float desiredCourse;

void setup() {
 Serial3.begin(9600); // Communication with EZ-B
    Serial.begin(9600);  // Debugging via Serial Monitor
    pinMode(2, INPUT_PULLUP);
    pinMode(3, INPUT_PULLUP);
    setMotorDirectionForward();
    attachInterrupt(digitalPinToInterrupt(2), AcountA, RISING);
    attachInterrupt(digitalPinToInterrupt(3), AcountB, RISING);
}

void loop() {
    if (Serial3.available() >= 7) { // Wait for 7 bytes
        resetAll();
        pathTotalDistance = (Serial3.read() << 8) | Serial3.read(); // Combine two bytes
        pathEndPointDistance = (Serial3.read() << 8) | Serial3.read(); // Combine two bytes
        oppositeDistance = Serial3.read();
        actualCourse = Serial3.read();
        desiredCourse = Serial3.read();
        setMotorDirectionForward();
        startMotors(100, 80);
    }

    AB_EncoderTot += (AencoderValue_A + AencoderValue_B);
    if (AB_EncoderTot > 0) {
        Serial.print("A= ");
        Serial.println(AencoderValue_A, DEC);
        Serial.print("B= ");
        Serial.println(AencoderValue_B, DEC);
        resetEncoders();
        Serial.print("ABTot= ");
        Serial.println(AB_EncoderTot, DEC);
    }

    if (AB_EncoderTot >= pathEndPointDistance) {
        setMotorDirectionReverse();
        startMotors(110, 100);
        delay(100);
        stopMotors();
        Serial3.write('T');
        Serial3.write((byte)(AB_EncoderTot >> 8)); // High byte
        Serial3.write((byte)(AB_EncoderTot & 0xFF)); // Low byte
        Serial.print("AB_EncoderTot: ");
        Serial.println(AB_EncoderTot, DEC);
        delay(5000);
        resetAll();
    }
    delay(50);

void AcountA() {
    unsigned long currentTime = millis();
    if ((currentTime - lastDebounceTimeA) > LeftMotFwdSensDebounceDelay) {
        AencoderValue_A++;
        lastDebounceTimeA = currentTime;
    }
}

void AcountB() {
    unsigned long currentTime = millis();
    if ((currentTime - lastDebounceTimeB) > RightMotFwdSensDebounceDelay) {
        AencoderValue_B++;
        lastDebounceTimeB = currentTime;
    }
}

void setMotorDirectionForward() {
    digitalWrite(13, false);
    digitalWrite(12, true);
    digitalWrite(9, true);
    digitalWrite(8, false);
}

void setMotorDirectionReverse() {
    digitalWrite(13, true);
    digitalWrite(12, false);
    digitalWrite(9, false);
    digitalWrite(8, true);
}

void startMotors(int leftSpeed, int rightSpeed) {
    analogWrite(11, leftSpeed);
    analogWrite(10, rightSpeed);
}

void stopMotors() {
    analogWrite(11, 0);
    analogWrite(10, 0);
}

void resetAll() {
    AencoderValue_A = 0;
    AencoderValue_B = 0;
    AB_EncoderTot = 0;
    lastDebounceTimeA = 0;
    lastDebounceTimeB = 0;
    pathEndpointDistance = 1;
}

void resetEncoders() {
    AencoderValue_A = 0;
    AencoderValue_B = 0;
}

void toa() {

 adjacentDistance = ( pathTotalDistance - AB_EncoderTot);
 desiredCourse = (90 - (atan(oppositeDistance / adjacentDistance) * 57.32));

}

}

The following is my EZB4 code.  Did I get it right?

// Set the variables
var pathTotalDistance = 2400
var pathEndPointDistance = 1900;
var oppositeDistance = 12;
var actualCourse = getVar("$ACTUAL_COURSE");
var desiredCourse = 83
// Init the hardware UART
UART.initHardwareUart(0, 9600, 0);

// Send the variables to Arduino
UART.hardwareUartWrite(0, [pathTotalDistance >> 8, pathTotalDistance & 0xFF]); // Send as two bytes
UART.hardwareUartWrite(0, [pathEndPointDistance >> 8, pathEndPointDistance & 0xFF]); // Send as two bytes
UART.hardwareUartWrite(0, [oppositeDistance]); // Send as one byte
UART.hardwareUartWrite(0, [actualCourse]); // Send as one byte
UART.hardwareUartWrite(0, [desiredCourse]);  // Send as one byte
// Continuously poll for the character from Arduino
while (true) {
    if (UART.hardwareUartAvailable(0) > 0) {
        var receivedChar = UART.hardwareUartRead(0, 1)[0];
        if (receivedChar == 'T') {
            print("Received: " + receivedChar);
            var highByte = UART.hardwareUartRead(0, 1)[0]; // Read high byte of ABencoderTot
            var lowByte = UART.hardwareUartRead(0, 1)[0]; // Read low byte of ABencoderTot
            var ABencoderTot = (highByte << 8) | lowByte; // Combine high and low bytes
            print("ABencoder= :" + ABencoderTot);
            break; // Exit the loop
        }
    }
    sleep(100); // Polling interval

Thank you, Jack

PRO
Canada
#75  

Let's review your Arduino and EZB4 code to identify potential issues and ensure everything is set up correctly.

Arduino Code Review

  1. Syntax Errors:

    • Ensure that all opening braces { have corresponding closing braces }. It seems like there might be a missing closing brace for the loop() function.
  2. Logical Errors:

    • In the loop() function, the condition if(Serial3.available()= 7) should be if(Serial3.available() >= 7). The = operator is for assignment, while >= is for comparison.
    • Ensure that the resetAll() function is called correctly. It seems like it might be missing a closing brace in the loop() function.
  3. Function Definitions:

    • Ensure that all functions are defined outside of other functions. The AcountA() and AcountB() functions should be defined outside of the loop() function.
  4. Data Transmission:

    • When sending data over Serial3, ensure that the data is correctly formatted and sent as expected. For example, when sending AB_EncoderTot, ensure that the high and low bytes are correctly calculated and sent.

EZB4 Code Review

  1. Variable Initialization:

    • Ensure that the variables pathTotalDistance, pathEndPointDistance, oppositeDistance, actualCourse, and desiredCourse are correctly initialized with the intended values.
  2. Data Transmission:

    • When sending pathTotalDistance and pathEndPointDistance, ensure that the high and low bytes are correctly calculated and sent. The code UART.hardwareUartWrite(0,[pathTotalDistance >> 8, pathTotalDistance & 0xFF]) is correct for sending two bytes.
  3. Polling Loop:

    • The polling loop seems correct, but ensure that the sleep(100) function is correctly implemented to avoid excessive CPU usage.

General Recommendations

  • Debugging:

    • Use Serial.print() statements in the Arduino code to debug and verify the values being read and sent. This can help identify where the issue might be occurring.
  • Testing:

    • Test each part of the code separately to ensure that each function works as expected before integrating everything together.

If you have any specific error messages or issues during compilation, please share them, and I can provide more targeted assistance.


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.
PRO
Synthiam
#76  

As with Athena said about the missing Loop closing brace, there's an extra closing brace at the end of the file - which won't compile.

Your ARC code while() loop is also missing a closing brace

#77  

Hello @Athena, I am having trouble with the following Arduino code:

desiredCourse = ((atan(oppositeDistance / adjacentRemainingDistance)) * 57.32)- 90;

I wish to calculate oppositeDistance / adjacentRemainingDistance. (272 / 2440).   Next get the Inverse Tangent of this amount.  ( atan (272/2440)). Next multiply this amount by 57.32.    ((atan (272 /2440) *57.32). Next subtract 90.    ((atan (272 /2440) *57.32) - 90. It should equal about 83.  I cannot get my Arduino code to arrive at this.   Is the above equation in Arduino code correct? Thanks, Jack

PRO
Canada
#78  

The equation you provided seems logically correct for calculating the desired course. However, there are a few things to consider when implementing it in Arduino code:

  1. Data Types: Ensure that the variables oppositeDistance and adjacentRemainingDistance are of a floating-point type, such as float or double, to handle decimal values correctly.

  2. Order of Operations: The order of operations in your equation is correct, but ensure that the parentheses are used to maintain the intended order.

  3. Precision: The atan() function in Arduino returns the angle in radians, so multiplying by 57.32 (which is approximately 180/) converts it to degrees.

Here's how you can implement it in Arduino code:

float oppositeDistance = 272.0;
float adjacentRemainingDistance = 2440.0;
float desiredCourse;

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

  // Calculate the desired course
  desiredCourse = (atan(oppositeDistance / adjacentRemainingDistance) * 57.32) - 90;

  // Print the result
  Serial.print("Desired Course: ");
  Serial.println(desiredCourse);
}

void loop() {
  // Your loop code here
}

Key Points:

  • Floating-Point Division: Ensure that both oppositeDistance and adjacentRemainingDistance are floating-point numbers to avoid integer division, which would result in a loss of precision.
  • Printing: Use Serial.print() to verify the calculated value and ensure it matches your expectations.

If you still encounter issues, please let me know, and we can further troubleshoot the problem.


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.
#79  

Thank you @Athena, Your solution using float worked.   I am however getting a negative number.  Can you look at my code and suggest a solution? Thanks Jack

volatile int AencoderValue_A = 0;
volatile int AencoderValue_B = 0;
volatile unsigned long AB_EncoderTot = 0;
volatile unsigned long lastDebounceTimeA = 0;
volatile unsigned long lastDebounceTimeB = 0;
const unsigned long LeftMotFwdSensDebounceDelay = 5;
const unsigned long RightMotFwdSensDebounceDelay = 7;
float adjacentRemainingDistance = 0;
int pathTotalDistance = 0;
int pathEndpointDistance = 0;
float oppositeDistance = 0;
int actualCourse;
float desiredCourse = 90;

void setup() {
 Serial3.begin(9600); // Communication with EZ-B
    Serial.begin(9600);  // Debugging via Serial Monitor
    pinMode(2, INPUT_PULLUP);
    pinMode(3, INPUT_PULLUP);
    setMotorDirectionForward();
    attachInterrupt(digitalPinToInterrupt(2), AcountA, RISING);
    attachInterrupt(digitalPinToInterrupt(3), AcountB, RISING);
}

void loop() {
    if (Serial3.available() >= 8) { // Wait for 8 bytes
        resetAll();
        pathTotalDistance = (Serial3.read() << 8) | Serial3.read(); // Combine two bytes
        pathEndpointDistance = (Serial3.read() << 8) | Serial3.read(); // Combine two bytes
        oppositeDistance = (Serial3.read() << 8) | Serial3.read(); // Combine two bytes
        actualCourse = Serial3.read();
        desiredCourse = Serial3.read();

        Serial.print("pathTotalDistance:  ");
        Serial.println(pathTotalDistance);
        Serial.print("pathEndpointDistance:  ");
        Serial.println(pathEndpointDistance);
        Serial.print("oppositeDistance:  ");
        Serial.println(oppositeDistance);
        Serial.print("actualCourse:  ");
        Serial.println(actualCourse);
        Serial.print("desiredCourse:  ");
        Serial.println(desiredCourse);
        startMotors(100, 80);
    }

    AB_EncoderTot += (AencoderValue_A + AencoderValue_B);
    if (AB_EncoderTot > 0) {
        Serial.print("A= ");
        Serial.println(AencoderValue_A, DEC);
        Serial.print("B= ");
        Serial.println(AencoderValue_B, DEC);
        resetEncoders();
        Serial.print("ABTot= ");
        Serial.println(AB_EncoderTot, DEC);
    }

       if (desiredCourse != 90) {
       toa();

       
    }

if (actualCourse >= desiredCourse) {

      //map PWM

     }
     if (actualCourse < desiredCourse) {

     // map PWM

     }

    if (AB_EncoderTot >= pathEndpointDistance) {
        setMotorDirectionReverse();
        startMotors(110, 100);
        delay(100);
        stopMotors();
        Serial3.write('T');
        Serial3.write((byte)(AB_EncoderTot >> 8)); // High byte
        Serial3.write((byte)(AB_EncoderTot & 0xFF)); // Low byte
        Serial.print("AB_EncoderTot1: ");
        Serial.println(AB_EncoderTot, DEC);
        delay(5000);
        resetAll();
    }
    delay(50);

}

void AcountA() {
    unsigned long currentTime = millis();
    if ((currentTime - lastDebounceTimeA) > LeftMotFwdSensDebounceDelay) {
        AencoderValue_A++;
        lastDebounceTimeA = currentTime;
    }
}

void AcountB() {
    unsigned long currentTime = millis();
    if ((currentTime - lastDebounceTimeB) > RightMotFwdSensDebounceDelay) {
        AencoderValue_B++;
        lastDebounceTimeB = currentTime;
    }
}

void setMotorDirectionForward() {
    digitalWrite(13, false);
    digitalWrite(12, true);
    digitalWrite(9, true);
    digitalWrite(8, false);
}

void setMotorDirectionReverse() {
    digitalWrite(13, true);
    digitalWrite(12, false);
    digitalWrite(9, false);
    digitalWrite(8, true);
}

void startMotors(int leftSpeed, int rightSpeed) {
    analogWrite(11, leftSpeed);
    analogWrite(10, rightSpeed);
}

void stopMotors() {
    analogWrite(11, 0);
    analogWrite(10, 0);
}

void resetAll() {
    AencoderValue_A = 0;
    AencoderValue_B = 0;
    AB_EncoderTot = 0;
    lastDebounceTimeA = 0;
    lastDebounceTimeB = 0;
    pathEndpointDistance = 1;
}

void resetEncoders() {
    AencoderValue_A = 0;
    AencoderValue_B = 0;
}

void toa() {

 adjacentRemainingDistance = ( pathTotalDistance - AB_EncoderTot);
 desiredCourse = ((atan(oppositeDistance / adjacentRemainingDistance)) * 57.32)- 90;
Serial.print("adjacentRemainingDistance:  ");
Serial.println(adjacentRemainingDistance);
Serial.print("desiredCourse:  ");
Serial.println(desiredCourse);

}

PRO
Canada
#80  

The issue of getting a negative number for desiredCourse could be due to the calculation of the atan() function, which returns values in radians and can result in negative angles depending on the quadrant of the angle. Let's go through your code and see how we can address this:

Key Points to Consider

  1. Quadrant Consideration:

    • The atan() function returns values between -/2 and /2 radians. When converting to degrees, this range becomes -90 to 90 degrees.
    • If your oppositeDistance and adjacentRemainingDistance are such that the angle is in the second or third quadrant, you might need to adjust the angle calculation.
  2. Adjusting the Angle:

    • You can use the atan2(y, x) function instead of atan(y/x). The atan2() function takes into account the signs of both arguments to determine the correct quadrant of the angle.
    • The atan2() function returns values between - and `` radians, which translates to -180 to 180 degrees.
  3. Code Adjustment:

    • Replace the atan() function with atan2() to handle the quadrant correctly.

Here's how you can modify your toa() function:

void toa() {
    adjacentRemainingDistance = (pathTotalDistance - AB_EncoderTot);
    // Use atan2 to calculate the angle correctly
    desiredCourse = (atan2(oppositeDistance, adjacentRemainingDistance) * 57.32) - 90;
    Serial.print("adjacentRemainingDistance: ");
    Serial.println(adjacentRemainingDistance);
    Serial.print("desiredCourse: ");
    Serial.println(desiredCourse);
}

Additional Suggestions

  • Debugging: Use Serial.print() statements to print the values of oppositeDistance and adjacentRemainingDistance before the calculation to ensure they are as expected.
  • Check Values: Ensure that oppositeDistance and adjacentRemainingDistance are positive and correctly represent the distances in your setup.

By using atan2(), you should get the correct angle in degrees, taking into account the correct quadrant, which should resolve the issue of getting a negative number for desiredCourse. If you continue to experience issues, please let me know, and we can further troubleshoot the problem.


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.