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

With Synthiam ARC Pro, you're not just programming a robot; you're shaping the future of automation, one innovative idea at a time.

PRO
Canada
#57  

Certainly,Jack!The error message indicates that the UART transmission is not supported on the specified digital port for your EZB4 device.Lets address this issue and ensure the script is correctly configured for your setup.

Updated EZB4 Script

  1. Ensure the correct UART port is used: Make sure you are using a digital port that supports UART transmission on your EZB4 device.
  2. Correct the UART port in the script: If D0 is not the correct port, you may need to use a different port that supports UART.

Here's an updated version of your script with some adjustments:

// Set the target count
var targetCount = 1000; // Change this value as needed

// Send the target count to Arduino
// Ensure the correct UART port is used (e.g., D5 if D0 is not supported)
UART.sendSerialString(D5, 9600, targetCount.toString());

// Set initial motor directions
Digital.set(d21, false, 0);
Digital.set(d22, true, 0);
Digital.set(d20, true, 0);
Digital.set(d19, false, 0);

// Set the PWM output to a value between 0% and 100%
PWM.set(d23, 19, 0);
PWM.set(d18, 15, 0);

// Continuously poll for the character from Arduino
while (true) {
    if (UART.available(D5) > 0) { // Ensure the correct UART port is used
        var receivedChar = UART.readString(D5, 1);
        if (receivedChar == "T") {
            // Shut down the PWM to the motors
            PWM.set(d23, 0); // Set PWM to 0 on the motor control pin
            PWM.set(d18, 0); // Set PWM to 0 on the motor control pin
            break; // Exit the loop
        }
    }
    sleep(100); // Polling interval
}

Key Points:

  • UART Port: Ensure you are using a digital port that supports UART on your EZB4. If D0 is not supported, try using another port like D5 or D6.
  • Check Wiring: Verify that the wiring between the EZB4 and Arduino is correct and matches the ports used in the script.
  • Character Comparison: Ensure the character comparison in the script matches the character sent from the Arduino.

If you continue to experience issues, please verify the EZB4 documentation for supported UART ports and adjust the script accordingly. 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.
#58  

Hello @Athena, I am using UART0 on my EZB4 as in my previous scripts. Any other recommendations to get my script running? Thanks Jack

#59   — Edited

If you're using UART 0, then your UART readstring will be set to 0. Check the manual page for the command here: https://synthiam.com/Support/javascript-api/UART/hardwareUartReadString

and the hardwareUartAvailable manual is here: https://synthiam.com/Support/javascript-api/UART/hardwareUartAvailable

and the sendSerialString needs to specify the UART index as well, which would be 0. manual is here: https://synthiam.com/Support/javascript-api/UART/sendSerialString

while (true) {
    if (UART.hardwareUartAvailable(0) > 0) { // Ensure the correct UART port is used
        var receivedChar = UART.hardwareUartReadString(1, 0);
        if (receivedChar == "T") {
            // Shut down the PWM to the motors
            PWM.set(d23, 0); // Set PWM to 0 on the motor control pin
            PWM.set(d18, 0); // Set PWM to 0 on the motor control pin
            break; // Exit the loop
        }
    }
    sleep(100); // Polling interval
}
#60  

Here is your updated script by referencing the manual pages for the commands to use the correct syntax.

// Set the target count
var targetCount = 1000; // Change this value as needed

// Init the hardware UART
UART.initHardwareUart(0, 9600, 0);

// Send the target count to Arduino
// Ensure the correct hardware UART port is used
UART.hardwareUartWriteString(0, targetCount.toString());

// Set initial motor directions
Digital.set(d21, false, 0);
Digital.set(d22, true, 0);
Digital.set(d20, true, 0);
Digital.set(d19, false, 0);

// Set the PWM output to a value between 0% and 100%
PWM.set(d23, 19, 0);
PWM.set(d18, 15, 0);

// Continuously poll for the character from Arduino
while (true) {
    if (UART.hardwareUartAvailable(0) > 0) { // Ensure the correct UART port is used
        var receivedChar = UART.hardwareUartReadString(0, 1);
        if (receivedChar == "T") {
            // Shut down the PWM to the motors
            PWM.set(d23, 0); // Set PWM to 0 on the motor control pin
            PWM.set(d18, 0); // Set PWM to 0 on the motor control pin
            break; // Exit the loop
        }
    }
    sleep(100); // Polling interval
}
#61  

Thank you so much for the help.   Jack

PRO
Canada
#62  

You're welcome,Jack!I'm glad I could assist you.If you have any more questions or need further help with your project,feel free to ask.Happy building with ARC!


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

Hello @Athena, I am finally taking baby steps towards actually coding my Arduino and EZB4 in their respective programming languages instead of using Blockly.   Thanks to you! I have decided to offload all of the motor control functions to the Arduino and leave the EZB4 to do the main NAV functions of my robot.  I have attached the Arduino Script and the EZB4 Script.   Could you please review my two Scripts and provide me with some feedback?  Don't hold back, I want the good and bad. If after you review the scripts, could you send them back to me corrected?  This is the way I learn best.

Thank you, Jack

ARDUINO:

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;//4
const unsigned long RightMotFwdSensDebounceDelay = 7;//6
unsigned long targetCount = 500; // Default target count

void setup() {
    Serial3.begin(9600); // Communication with EZ-B
    Serial.begin(9600);  // Debugging via Serial Monitor
    pinMode(2, INPUT_PULLUP);
    pinMode(3, INPUT_PULLUP);
    digitalWrite(13,false);//Set motor controller for FORWARD
    digitalWrite(12,true);
    digitalWrite(9,true);
    digitalWrite(8,false);
    attachInterrupt(digitalPinToInterrupt(2), AcountA, RISING);
    attachInterrupt(digitalPinToInterrupt(3), AcountB, RISING); 
}

void loop() {
    // Check if there is data available to read from EZ-B
    if (Serial3.available() > 0) {

        // If data is available do the following:
        targetCount = Serial3.parseInt(); // Read the target count
        lastDebounceTimeA = 0;//Reset lastDebounceTimeA
        lastDebounceTimeB = 0;//Reset lastDebounceTimeB
        AencoderValue_A = 0;//Reset AencoderValue_A
        AencoderValue_B = 0;//Reset AencoderValue_B
        AB_EncoderTot = 0; // Reset the encoder total

        //Set motor controller for FORWARD
        digitalWrite(13,false);
        digitalWrite(12,true);
        digitalWrite(9,true);
        digitalWrite(8,false);

        //Start motors
        analogWrite(11,100); 
        analogWrite(10,80);
    }
     //Print encoder values only if > 0
    if (AB_EncoderTot > 0 ) {
    Serial.print("A=  ");
   Serial.println( AencoderValue_A, DEC);
    Serial.print("B=   ");
    Serial.println(AencoderValue_B, DEC);
    }
     // Get Encoder totals
    AB_EncoderTot += (AencoderValue_A + AencoderValue_B);

    // Check if the total count has reached the target
    if (AB_EncoderTot >= targetCount) {

      //Set motor controller to REVERSE for snappy stop
        digitalWrite(13,true);
        digitalWrite(12,false);
        digitalWrite(9,false);
        digitalWrite(8,true);

        // then start motors
        analogWrite(11,110); 
        analogWrite(10,100);
        delay(100);

        // then stop motors
        analogWrite(11,0); 
        analogWrite(10,0);
        
        Serial3.write('T'); // Send a character to EZ-B
      
        // Send the total count to the EZB4
        Serial3.write((byte)(AB_EncoderTot >> 8)); // High byte
        Serial3.write((byte)(AB_EncoderTot & 0xFF)); // Low byte
        
        //Serial print to arduino monitor
        Serial.print("AB_EncoderTot: ");
        Serial.println(AB_EncoderTot, DEC);

        //Allow motor encoders to fully stop
        delay(5000);

        //Zero out all var
        AencoderValue_A = 0;//Reset AencoderValue_A
        AencoderValue_B = 0;//Reset AencoderValue_B
        AB_EncoderTot = 0; // Reset the encoder total
        lastDebounceTimeA = 0;//Reset lastDebounceTimeA
        lastDebounceTimeB = 0;//Reset lastDebounceTimeB
    
    }
    AencoderValue_A = 0;//Reset AencoderValue_A
    AencoderValue_B = 0;//Reset AencoderValue_B
    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;
    }
}

EZB4:

// Set the target count
var targetCount = 1900; // Change this value as needed

// Init the hardware UART
UART.initHardwareUart(0, 9600, 0);

// Send the target count to Arduino
UART.hardwareUartWriteString(0, targetCount.toString());

// Continuously poll for the character from Arduino
while (true) {
    if (UART.hardwareUartAvailable(0) > 0) {
        var receivedChar = UART.hardwareUartReadString(0, 1);
        if (receivedChar == "T") {
        print("Recieved   " + 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
}
PRO
Canada
#64  

Hi Jack! It's great to see you diving into coding for your Arduino and EZB4. Let's review and refine your scripts for both the Arduino and EZB4.

Arduino Script

  1. Variable Initialization: Ensure that your variables are initialized correctly. For instance, volatile is used correctly for variables modified within an interrupt.

  2. Serial Communication: You're using Serial3 for communication with the EZ-B, which is correct for the Mega. Ensure that the wiring matches this setup.

  3. Debouncing: Your debounce logic seems fine, but ensure that the debounce delay is appropriate for your encoder's speed.

  4. Motor Control Logic: The logic for controlling the motor direction and speed is clear. Ensure that the analogWrite values are suitable for your motor driver.

  5. Encoder Logic: The logic for counting encoder pulses and checking against the target count is sound. Ensure that the targetCount is set appropriately for your application.

  6. Code Cleanup: Consider using functions to encapsulate repeated logic, such as resetting variables or setting motor directions.

Here's a refined version of your Arduino script:

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;
unsigned long targetCount = 500;

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() > 0) {
        targetCount = Serial3.parseInt();
        resetEncoders();
        setMotorDirectionForward();
        startMotors(100, 80);
    }

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

    AB_EncoderTot += (AencoderValue_A + AencoderValue_B);

    if (AB_EncoderTot >= targetCount) {
        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);
        resetEncoders();
    }

    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 resetEncoders() {
    AencoderValue_A = 0;
    AencoderValue_B = 0;
    AB_EncoderTot = 0;
    lastDebounceTimeA = 0;
    lastDebounceTimeB = 0;
}

EZB4 Script

  1. UART Initialization: Ensure that the UART is initialized correctly and matches the baud rate of the Arduino.

  2. Data Handling: The logic for reading and combining the high and low bytes is correct. Ensure that the data is sent and received in the correct order.

  3. Polling Interval: The polling interval is set to 100ms, which should be fine for most applications.

Here's a refined version of your EZB4 script:

// Set the target count
var targetCount = 1900;

// Init the hardware UART
UART.initHardwareUart(0, 9600, 0);

// Send the target count to Arduino
UART.hardwareUartWriteString(0, targetCount.toString());

// Continuously poll for the character from Arduino
while (true) {
    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 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
}

Feedback Summary

  • Arduino: Consider using functions to encapsulate repeated logic, such as resetting variables or setting motor directions. Ensure that the debounce delay is appropriate for your encoder's speed.

  • EZB4: Ensure that the UART initialization and data handling logic are correct. The polling interval is set to 100ms, which should be fine for most applications.

Feel free to ask if you have any questions or need further clarification!


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.