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

Join the ARC Pro community and gain access to a wealth of resources and support, ensuring your robot's success.

#81  

Hello @Athena, I am still getting a negative number with the new code.   I wonder if I should "force" it positive by getting an "absolute value" of it? Perhaps you could check my code for errors? Thanks Jack

PRO
Canada
#82  

If you're still getting a negative number, it's possible that the calculation is correct, but the context of your application requires a positive angle. Using the absolute value might be a quick fix, but it's essential to understand why the negative value is occurring. Let's review your code and see if there are any potential issues or improvements:

Code Review and Suggestions

  1. atan2 Usage:

    • Ensure that atan2(oppositeDistance, adjacentRemainingDistance) is used correctly. This function should handle the quadrant correctly, but if your application logic requires a positive angle, you might need to adjust it.
  2. Absolute Value:

    • If your application logic requires a positive angle, you can use the absolute value. However, ensure that this aligns with your intended behavior.
  3. Debugging:

    • Print the values of oppositeDistance and adjacentRemainingDistance before the calculation to ensure they are as expected.
    • Print intermediate results to understand where the negative value might be coming from.
  4. Code Adjustment:

    • Here's how you can adjust your toa() function to use the absolute value:
void toa() {
    adjacentRemainingDistance = (pathTotalDistance - AB_EncoderTot);
    // Use atan2 to calculate the angle correctly
    desiredCourse = (atan2(oppositeDistance, adjacentRemainingDistance) * 57.32) - 90;
    
    // If a positive angle is required, use the absolute value
    desiredCourse = abs(desiredCourse);

    Serial.print("adjacentRemainingDistance: ");
    Serial.println(adjacentRemainingDistance);
    Serial.print("desiredCourse: ");
    Serial.println(desiredCourse);
}

Additional Considerations

  • Application Logic: Ensure that using the absolute value aligns with your application's logic. Sometimes, negative angles are meaningful, indicating direction or orientation.
  • Testing: Test with different values of oppositeDistance and adjacentRemainingDistance to see how the angle behaves and ensure it meets your requirements.

If you continue to experience issues, please provide more context about the application or any specific requirements for the angle, 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.
#83  

Thank you @Athena.  All parameters were printed, and calculations are correct.  Setting the angle to absolute gets me what I need.  For further clarification, here is a screenshot from my patent describing the end use for this angle.  I find a solution first by finding angle "a", then find angle "b" by subtracting "a" from 90 degrees.  I suspect this last subtraction is what is causes the negative result.  Thanks again for all your help. Jack

User-inserted image

PRO
Canada
#84  

You're welcome, Jack! I'm glad to hear that using the absolute value of the angle is giving you the results you need. Based on your description, it sounds like the subtraction to find angle ( b ) is indeed the source of the negative result. Here's a quick breakdown of the logic:

  1. Finding Angle ( a ):

    • You calculate angle ( a ) using the atan2() function, which gives you the angle in degrees.
  2. Finding Angle ( b ):

    • If angle ( b ) is calculated as ( b = 90^\circ - a ), then if ( a ) is greater than ( 90^\circ ), ( b ) will naturally be negative.

Solution

  • Absolute Value: Using the absolute value for angle ( b ) is a valid approach if your application requires a positive angle.
  • Understanding Context: Ensure that the use of absolute value aligns with the physical or logical context of your application. If angle ( b ) represents a physical angle that should always be positive, then this approach is correct.

Final Thoughts

  • Documentation: Make sure to document this decision in your code or patent to clarify why the absolute value is used, which can be helpful for future reference or for others reviewing your work.
  • Testing: Continue testing with various scenarios to ensure that the logic holds under different conditions.

If you have any more questions or need further assistance, feel free to ask. I'm here to help!


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

Hello @Athena, As my Arduino sketch fills up with tasks, some errors in data being received is revealing itself. The Arduino is being started by the EZB4 and sent 5 parameters to read before the Arduino runs the motors. I suspect the variables listed are not set up with sufficient capacity to store the data.  The first run is always perfect, however subsequent runs do not seem to load the variable parameters correctly.  They seem to spill over into the next variable in the list. Below is a list of the offending variables:

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;
//The following are now refered to as "FoundationVariables"
int adjacentRemainingDistance;
int pathTotalDistance;
int pathEndpointDistance = 100;
float oppositeDistance;
float desiredCourse = 90;
int actualCourse = 90;

I have noted them as the "FoundationVariables".  After the first run the sent data spills over to the next variable in the list. They should be capable to hold the following Values: int adjacentRemainingDistance : 50,000. int pathTotalDistance: 50,000. int pathEndpointDistance: 50,000. float oppositeDistance; 20,000. float desiredCourse: 360. int actualCourse: 360.

Can you please help me determine if the variables listed have sufficient capacity for their expected use? Thank you. Jack

PRO
Canada
#86  

Certainly,Jack!Lets review the variables and their capacities to ensure they can hold the expected values:

Variable Capacity Review

  1. int Variables:

    • Capacity: Typically, an int in Arduino (which is based on the AVR architecture) is a 16-bit signed integer, with a range of -32,768 to 32,767.
    • Variables:
      • adjacentRemainingDistance
      • pathTotalDistance
      • pathEndpointDistance
      • actualCourse
    • Issue: Since you expect values up to 50,000 for some of these variables, they will overflow the capacity of a standard int.
  2. unsigned long Variables:

    • Capacity: An unsigned long is a 32-bit unsigned integer, with a range of 0 to 4,294,967,295.
    • Variables:
      • AB_EncoderTot
      • lastDebounceTimeA
      • lastDebounceTimeB
    • Issue: These should be sufficient for your use case, as they can hold very large values.
  3. float Variables:

    • Capacity: A float in Arduino is a 32-bit floating-point number, which can handle a wide range of values, including decimals.
    • Variables:
      • oppositeDistance
      • desiredCourse
    • Issue: These should be sufficient for your use case, as they can handle the expected range and precision.

Recommendations

  • Change int to long: For variables that need to hold values up to 50,000, you should use long instead of int. A long is a 32-bit signed integer, with a range of -2,147,483,648 to 2,147,483,647, which will be sufficient for your needs.

    long adjacentRemainingDistance;
    long pathTotalDistance;
    long pathEndpointDistance = 100; // If this needs to be larger, adjust accordingly
    long actualCourse = 90; // If this needs to be larger, adjust accordingly
    
  • Check Data Handling: Ensure that the data being sent to the Arduino is correctly parsed and assigned to the appropriate variables. If data is spilling over, it might be due to incorrect parsing or buffer handling.

  • Debugging: Add debugging statements to print the values of variables after they are set to ensure they are being assigned correctly.

If you implement these changes and still encounter issues, consider reviewing the data transmission logic to ensure that data is being sent and received correctly. Let me know if you need further 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.
#87  

Hello @Athena, My data is consistently spilling over after the first run of the Arduino. I have included what I think is the critical part of the Arduino sketch:

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;
//The following are now refered to as "FoundationVariables"
long adjacentRemainingDistance;
long pathTotalDistance;
long pathEndpointDistance = 100;
float oppositeDistance;
float desiredCourse = 90;
long actualCourse = 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
        resetFoundationVariables();
        delay(10);
        resetAll();
        delay(10);
        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);
   }

Here is the entire EZB4 script that sends the parameters to the Arduino prior to the motors starting.

// Set the variables
var pathTotalDistance = 2440;
var pathEndpointDistance = 1900;
var oppositeDistance = 272;
var actualCourse = getVar("$ACTUAL_COURSE");
var desiredCourse = 90;//getVar("$DESIRED_COURSE")
// Init the hardware UART
sleep(10);
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 >> 8, oppositeDistance & 0xFF]); // Send as two bytes

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) {
setVar("$ACTUAL_COURSE", (Servo.GetPosition(17)));//this only for test
var actualCourse = getVar("$ACTUAL_COURSE");

UART.hardwareUartWrite(0, [actualCourse]); // Send as one byte

if (UART.hardwareUartAvailable(0) > 0) {
        var receivedChar = UART.hardwareUartReadString(0, 1);
        if (receivedChar == 'T') {
            print("Received: " + receivedChar);
            var highByte = UART.hardwareUartRead(0, 1)[0]; // Read high byte of AB_EncoderTot
            var lowByte = UART.hardwareUartRead(0, 1)[0];  // Read low byte of AB_EncoderTot
            var AB_EncoderTot = (highByte << 8) | lowByte;  // Combine high and low bytes
            print("AB_EncoderTot= " + AB_EncoderTot);
            break; // Exit the loop
        }
    }

    sleep(100); // Polling interval
}

halt();

Can you please look to see if my data is being sent correctly by the EZB4 and received correctly by the Arduino? I suspect I am limiting the bytes capacity being sent by the EZB4. Thanks again, Jack

PRO
Canada
#88  

Certainly,Jack!Lets review the data transmission and reception to ensure everything is set up correctly.### Arduino Code Review 1.Data Reception:- You are reading data from Serial3 in the Arduino sketch.- You are combining two bytes for pathTotalDistance, pathEndpointDistance, and oppositeDistance using bitwise operations.2.Potential Issues:- Ensure that the data is being read in the correct order and that the bitwise operations are correctly combining the bytes.### EZB4 Script Review 1.Data Transmission:- You are sending pathTotalDistance, pathEndpointDistance, and oppositeDistance as two bytes each.- You are sending actualCourse and desiredCourse as one byte each.2.Potential Issues:- Ensure that the bitwise operations are correctly extracting the high and low bytes for transmission.### Recommendations 1.Check Bitwise Operations:- Ensure that the bitwise operations are correctly extracting and combining the bytes for both sending and receiving.- For example, when sending two bytes, you should extract the high and low bytes correctly:javascript// Extract high and low bytes for transmissionvar highByte = (pathTotalDistance >> 8) & 0xFF;var lowByte = pathTotalDistance & 0xFF;UART.hardwareUartWrite(0, [highByte, lowByte]);2.Verify Data Order:- Ensure that the data is being sent and received in the correct order. The order of reading and writing should match.3.Debugging:- Add debugging statements to print the values of the bytes being sent and received to ensure they match expectations.### Example Debugging Statements - Arduino:cppSerial.print("Received pathTotalDistance high byte: ");Serial.println(Serial3.read(), HEX);Serial.print("Received pathTotalDistance low byte: ");Serial.println(Serial3.read(), HEX);- EZB4:javascriptprint("Sending pathTotalDistance high byte: " + (pathTotalDistance >> 8));print("Sending pathTotalDistance low byte: " + (pathTotalDistance & 0xFF));By ensuring that the bitwise operations and data order are correct, you should be able to resolve the data spillover issue. If you continue to experience issues, consider adding more detailed debugging statements to trace the data flow. Let me know if you need further 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.