Dynamixel icon Dynamixel Open-source ARC plugin to control Robotis Dynamixel servos (XL-320, AX-12, XL430) via EZ-B, Arduino or Robotis. Supports position, speed, accel. Try it →
Asked — Edited
Resolved Resolved by Athena!

UART Byte Array Communication Explained

Hi @Athena,

I'm asking about the best way to communicate via UART between an EZB4 (JavaScript running on the EZB) and an Arduino Mega (C++). I'm a beginner and want to keep the implementation simple but reliable. My understanding is that sending a String is not necessary and that sending an array of bytes would be a better approach. I'm using the EZB4 hardware UART functions (UART.hardwareUart*) on the EZB side and Serial3 on the Arduino Mega side.

To clarify the hardware/ARC context: the Arduino Mega is connected to the EZB4 UART (hardware UART lines). The EZB is handling the real-time hardware UART I/O, and this runs inside an ARC project where ARC scripts manage the higher-level logic. The EZB code is a single JavaScript script running on the EZB (built-in ARC/EZB scripting). The Arduino code is standard C++ running on the Mega. This is not using a separate robot skill for the serial link; the UART I/O is performed by the EZB firmware calls from the script.

I have included my C++ (Arduino) TX and RX code and my JavaScript (EZB4) TX/RX code below for your evaluation. Could you rewrite the code to reliably send data using an array-of-bytes format?

Notes:

  • The Arduino C++ TX and RX must be separate sketches (not combined).
  • The EZB4 code runs as a single JavaScript script on the EZB (using built-in ARC/EZB scripting).
  • This is part of an ARC project where the EZB handles the real-time hardware UART and ARC scripts manage higher-level logic.

C++
Data TX

if (run == 1) {
   bufferFlush();
   totalStepsTaken = (abs(combinedStepsTaken));
   delay(50);
   int byte0 = totalStepsTaken & 0xFF;
   int byte1 = (totalStepsTaken >> 8) & 0xFF;
   int byte2 = (totalStepsTaken >> 16) & 0xFF;
   int byte3 = (totalStepsTaken >> 24) & 0xFF;
   Serial3.write('T');  //Header for Total Steps Taken
   // Send the four bytes one by one.
   Serial3.write(byte0);
   Serial3.write(byte1);
   Serial3.write(byte2);
   Serial3.write(byte3);
   Serial.print("Sent   ");
   Serial.println('T'); 
   Serial.print("Left F+B Steps:  ");
   Serial.println(abs(LeftFrontWheel.currentPosition()) + abs(LeftBackWheel.currentPosition()));
   Serial.print("Right F+B Steps:  ");
   Serial.println(abs(RightFrontWheel.currentPosition()) + abs(RightBackWheel.currentPosition()));
   Serial.print("Sent combinedStepsTaken:  ");
   Serial.println(totalStepsTaken);
   Serial.println("  ");
   delay(100);
   }

C++
Data RX

 
while ( run == 1) {
if (Serial3.available() >= 1 ) {
     int incomingByte = Serial3.peek(); // do not remove it yet
     // Check if this byte is our STOP command (assume 'x' is the stop command)

    if ( incomingByte == 'm') {
    Serial3.read();
    miss = true;
    actualCourse = desiredCourse;
    }

  if (incomingByte == 'x') {
     // Consume the byte and stop motors
     Serial3.read();  
     Serial.print("Received STOP command: ");
     Serial.println('x');
     stopMotors();
     goto Main; // jump out to the Main section
     }
 if ( incomingByte == 'c') {
    Serial3.read();
    Serial.print( "(Received obs scan complete) command  ");
    Serial.println('c');
    }
    }

  if (Serial3.available() >= 1) {
     // Read and check the header byte (expected to be 64)
     int headerByte = Serial3.read();

  if (headerByte == 64) { 
     int32_t b0 = Serial3.read();
     int32_t scaledValue = (b0);   
     actualCourse = scaledValue;
     Serial.print(" ..............----------------------------  rec'd actualCourse:  ");
     Serial.println( actualCourse,4); 

     lastActualCourse = actualCourse;
     initial = true;    
     miss = false;
     loopct = 0;
     } 
     }      

  if (miss == true ) {
     Serial.print( "                                     Received Missed command:  ");
     Serial.println('m');
      actualCourse = lastActualCourse;
  }

    combinedStepsTaken = abs(LeftFrontWheel.currentPosition()) + abs(LeftBackWheel.currentPosition())
    + abs(RightFrontWheel.currentPosition()) + abs(RightBackWheel.currentPosition());

    if (abs(combinedStepsTaken) > combinedStepsDesired) {
    stopMotors();
    goto Main;
    }
    loopct++;
    }

JavaScript Data TX and RX (single script on the EZB)

var lastActualCourse = null;
setVar("$obsDet", 0);
setVar("$missedIR", 0);
setVar("$obsScanEnd", 0);

while(true) { 
 

//Data RX

 if (UART.hardwareUartAvailable(0) >= 5) {  //5
       var header = UART.hardwareUartReadString(0,1); 
       
      if (header == 'D'){  
       var desiredCourseScaled = UART.hardwareUartRead(0, 1);  
       setVar("$desiredCourse", desiredCourseScaled[0]);  
       print("rec'd desiredCourse:  " +  getVar("$desiredCourse")+ "    cyc:  " + getVar("$cycleCount"));
       
       } else if (header == 'T') {
       print("Header: " + header);
       // read all 4 bytes from uart #0 that we need for this condition into the array tmpRead
       var TSTRead = UART.hardwareUartRead(0, 4);
       // tmpRead[3,2,1,0] are denoted as they were sent 0,1,2,3
       var totalStepsTaken = (( TSTRead[3] << 24) | ( TSTRead[2] << 16) | ( TSTRead[1] << 8) | TSTRead[0]);
       print("totalStepsTaken: " + totalStepsTaken);
       print( "CYC: " + getVar("$cycleCount") + "   $desiredCourse: " + getVar("$desiredCourse") + "   $actualCourse: " + getVar("$actualCourse"));
       sleep(100); 
       
       controlCommand("$IR_1", "PauseOff");
       sleep( 10 );
       controlCommand("IR_STEP", "ScriptStop");
       sleep( 10 );
       controlCommand("NRS_71.8_58_TEST", "ScriptStop");
       sleep( 10 );
       halt();
       }
       }   
       
   
        
        
        
   // Data TX     
        
        if (getVar("$obsDet") == 1) {
         UART.hardwareUartWrite(0, ['x'.charCodeAt(0)]); 
         sleep(5);
         print( "sent to ARDU...obsDet:  " + getVar("$obsDet"));
       print("OBS IR STOP:  " + getVar("$IRADC"));  
       }
       
       
       if ( getVar("$missedIR") == 1) {
           UART.hardwareUartWrite(0, ['m'.charCodeAt(0)]); 
           print("sent to ARDU...missedIR:  " + getVar("$missedIR"));
           }
       
       
       if ( getVar("$obsScanEnd") == 1 ) {
           UART.hardwareUartWrite(0, ['c'.charCodeAt(0)]); 
           print("sent to ARDU...Scan for obs ended:  " + getVar("$obsScanEnd"));
          }
        
       
        if(getVar("$actualCourse") != lastActualCourse) { 
        var scaledValue = getVar("$actualCourse");  
        //Send as whole number to Arduino:
        var byte0 = scaledValue & 0xFF;
        var header = [64];
        // Combine the header with the 4 bytes and send via UART
        UART.hardwareUartWrite(0, header.concat([byte0]));
       lastActualCourse = getVar("$actualCourse"); 
       print(" $actualCourse:  " + getVar("$actualCourse"));  
       }         
            
        sleep(200); 
       }


Related Hardware (view all EZB hardware)
EZ-B V4 by EZ-Robot
EZ-B v4/2 robot controller: dual Cortex ARM, Wi-Fi, audio/video, 24 servo/digital ports, I2C/UART, camera and Synthiam ARC control for custom robots
Wi-Fi / USB
Servos 24
Camera
Audio
UART 3
I2C
ADC 8
Digital 24

Related Robot Skills (view all robot skills)
Add custom EZ-Script functions in C# or JS; intercept unknown calls, parse parameters and return values via AdditionalFunctionEvent.
Script by Synthiam
Multi-language ARC Script: build, run and debug Blockly, JavaScript, EZ-Script or Python with Intellisense, run/save/load and Roboscratch support

ARC Pro

Upgrade to ARC Pro

Stay at the forefront of robot programming innovation with ARC Pro, ensuring your robot is always equipped with the latest advancements.

#41  

Hi @Athena, I am very happy with the ARC and ARDUINO UART code that you provided.  They communicate very well together and a big thanks to @DJ for the guidance he gave early on to steer this thread.  I am working on putting my criteria together for the PWM and Desired Bearing portions of the Arduino sketch and will submit them in a few days on a new thread.  Thanks for your wonderful assistance to robot imagineers! Jack

📚 This thread has been preserved as a helpful resource!

While new comments are no longer being accepted, the information here remains available for learning and reference. Check the most recent comment for additional details.