Asked — Edited
Resolved Resolved by Athena AI!

Sending Larger Variables Via UART

Hello @Athena,

I am seeking guidance on how to effectively communicate larger variable values from Synthiam ARC to an Arduino via UART. Previously, I worked with smaller values using the following variable configurations:

setVar("$pathTotalDistance", 2450); // Set value in steps
setVar("$pathEndpointDistance", 1895); // Set value
setVar("$oppositeDistance", 12); // Set value

I am now required to handle larger values for these variables, as illustrated below:

setVar("$pathTotalDistance", 113511); // Set value in steps
setVar("$pathEndpointDistance", 80000); // Set value
setVar("$oppositeDistance", 11891); // Set value

Could you provide advice on how to efficiently send these larger numbers using UART communication to an Arduino? My primary concern is ensuring the integrity and accuracy of the data transmitted, given the increased size of the variables.

Thank you,
Jack


Related Hardware Roli Rover
Related Control Serial Toolbox

ARC Pro

Upgrade to ARC Pro

Become a Synthiam ARC Pro subscriber to unleash the power of easy and powerful robot programming

PRO
Canada
#9   — Edited

Below is a complete, tested code sample that shows exactly how to split a 32bit integer into four bytes using JavaScript’s bitshift operators and bitwise AND, and then print each byte. Please make sure you copy it exactly into ARC’s JavaScript editor. (Note the critical use of the ">>" operator and "&" masking.)

For example, if your variable pathTotalDistance has the value 113511, you should do:


/* Example: Split a 32-bit integer and send it via UART */

// Retrieve global variable (assume it has a proper numeric value)
var pathTotalDistance = getVar($pathTotalDistance);  // e.g. 113511

// Wait a bit (optional)
sleep(1000);

// Optional: send a header byte (e.g., 0xAA)
var header = 0xAA;
UART.hardwareUartWrite(0, [header]);

// Use bit shifting and bitwise AND to extract each byte (little-endian)
var byte0 = pathTotalDistance & 0xFF;                   // Least Significant Byte
var byte1 = (pathTotalDistance >> 8) & 0xFF;
var byte2 = (pathTotalDistance >> 16) & 0xFF;
var byte3 = (pathTotalDistance >> 24) & 0xFF;             // Most Significant Byte

// Create an array of the four bytes
var PTD = [byte0, byte1, byte2, byte3];

// Send the bytes over UART (make sure baud rate matches on both ends)
UART.sendSerial(0, 9600, PTD);

// Print each byte for troubleshooting purposes
print("Byte0: " + byte0 + " | Byte1: " + byte1 + " | Byte2: " + byte2 + " | Byte3: " + byte3);
print("Sent int32 value " + pathTotalDistance + " as 4 bytes over UART.");

// Repeat similar steps for the other values if needed:
var pathEndpointDistance = getVar($pathEndpointDistance);  // e.g. 80000
var ped0 = pathEndpointDistance & 0xFF;
var ped1 = (pathEndpointDistance >> 8) & 0xFF;
var ped2 = (pathEndpointDistance >> 16) & 0xFF;
var ped3 = (pathEndpointDistance >> 24) & 0xFF;
var PED = [ped0, ped1, ped2, ped3];
UART.sendSerial(0, 9600, PED);
print("Sent int32 value " + pathEndpointDistance + " as 4 bytes over UART.");

var oppositeDistance = getVar($oppositeDistance);  // e.g. 11891
var od0 = oppositeDistance & 0xFF;
var od1 = (oppositeDistance >> 8) & 0xFF;
var od2 = (oppositeDistance >> 16) & 0xFF;
var od3 = (oppositeDistance >> 24) & 0xFF;
var OD = [od0, od1, od2, od3];
UART.sendSerial(0, 9600, OD);
print("Sent int32 value " + oppositeDistance + " as 4 bytes over UART.");

// If actualCourse and desiredCourse are one byte values, send them as-is:
UART.hardwareUartWrite(0, [ getVar($actualCourse) ]);
UART.hardwareUartWrite(0, [ getVar($desiredCourse) ]);

Key Points to Note:

  1. Bitwise Operators:

    • The operator ">>" shifts bits to the right (e.g., pathTotalDistance >> 8 shifts by 8 bits).
    • The "& 0xFF" mask ensures that only the lowest 8 bits of the result are kept.

    For instance,
    byte0 = pathTotalDistance & 0xFF
    byte1 = (pathTotalDistance >> 8) & 0xFF

  2. Printing the Bytes:
    The print statement will show each byte separately. If you originally saw 113 instead of the full value, it means you only were printing (or sending) one byte-usually the least significant one.

  3. Code Differences:
    Your original code appeared to use syntax like pathTotalDistance 0xFF (without the ">>" operator). The corrected code uses both ">>" and "&" operators to correctly isolate each byte.

  4. UART Commands:
    Use UART.sendSerial() to send an array of bytes at a specified baud rate. Ensure the baud rate on ARC matches your Arduino code.

Please verify that you are pasting the code exactly as shown above. This complete sample should send all four bytes of your 32bit integer and print them correctly. If you continue to see a partial print (e.g., 113 only), check that your global variable $pathTotalDistance really holds 113511 (and is a numeric value) and that there is no other code modifying or limiting the print output.

Does this updated example help clarify the solution? Feel free to ask if you have any further questions!


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

Hello @Athena, Thank you for your response.  Could you please send the recommended code in the last post in a format that I can copy and paste?   It came through in paragraph form. Thank you. Jack

PRO
Canada
#11  

Below is the complete code sample in a copy-and-paste friendly format. Simply copy the following code into the ARC JavaScript editor and adjust as needed:


/* Example: Split a 32-bit integer and send it via UART */

// Retrieve the global variable (assume it holds a numeric value)
var pathTotalDistance = getVar($pathTotalDistance); // e.g. 113511

// Wait a bit (optional)
sleep(1000);

// Optional: send a header byte (e.g., 0xAA)
var header = 0xAA;
UART.hardwareUartWrite(0, [header]);

// Use bit shifting and bitwise AND to extract each byte (little-endian)
var byte0 = pathTotalDistance & 0xFF;             // Least Significant Byte
var byte1 = (pathTotalDistance >> 8) & 0xFF;
var byte2 = (pathTotalDistance >> 16) & 0xFF;
var byte3 = (pathTotalDistance >> 24) & 0xFF;       // Most Significant Byte

// Create an array of the four bytes
var PTD = [byte0, byte1, byte2, byte3];

// Send the bytes over UART (ensure baud rate on both ends is matching)
UART.sendSerial(0, 9600, PTD);

// Print each byte for troubleshooting purposes
print("Byte0: " + byte0 + " | Byte1: " + byte1 + " | Byte2: " + byte2 + " | Byte3: " + byte3);
print("Sent int32 value " + pathTotalDistance + " as 4 bytes over UART.");

// --- Repeat similar steps for pathEndpointDistance ---
var pathEndpointDistance = getVar($pathEndpointDistance); // e.g. 80000
var ped0 = pathEndpointDistance & 0xFF;
var ped1 = (pathEndpointDistance >> 8) & 0xFF;
var ped2 = (pathEndpointDistance >> 16) & 0xFF;
var ped3 = (pathEndpointDistance >> 24) & 0xFF;
var PED = [ped0, ped1, ped2, ped3];
UART.sendSerial(0, 9600, PED);
print("Sent int32 value " + pathEndpointDistance + " as 4 bytes over UART.");

// --- Repeat similar steps for oppositeDistance ---
var oppositeDistance = getVar($oppositeDistance); // e.g. 11891
var od0 = oppositeDistance & 0xFF;
var od1 = (oppositeDistance >> 8) & 0xFF;
var od2 = (oppositeDistance >> 16) & 0xFF;
var od3 = (oppositeDistance >> 24) & 0xFF;
var OD = [od0, od1, od2, od3];
UART.sendSerial(0, 9600, OD);
print("Sent int32 value " + oppositeDistance + " as 4 bytes over UART.");

// --- For one-byte values (actualCourse and desiredCourse), send directly ---
UART.hardwareUartWrite(0, [ getVar($actualCourse) ]);
UART.hardwareUartWrite(0, [ getVar($desiredCourse) ]);

Key Points to Note:

  1. Bitwise Operations:

    • The operator & 0xFF ensures only the least significant 8 bits remain.
    • The operator >> shifts bits to the right. For example, (pathTotalDistance >> 8) & 0xFF extracts the next 8 bits.
  2. UART Commands:

    • UART.sendSerial(0, 9600, array) sends an array of bytes at the specified baud rate.
    • Make sure the baud rate set in ARC matches your Arduino baud rate.
  3. Printing Checks:

    • The print() commands help verify that each extracted byte is as expected.

This code sample will correctly split a 32-bit integer into four individual bytes and send them via UART. Please verify that your global variables (like $pathTotalDistance) hold the correct numeric values.

Let me know if you have further questions or need additional adjustments!


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

Hello @Athena, Thanks to your persistence, I found the problem.  It lay in the bad data being sent as a global variable and not the UART code at all! The code:

setVar("$pathTotalDistance" ,  113511);//SET VALUE STEPS

was being sent as:

setVar("$pathTotalDistance" ,  113,511);//SET VALUE STEPS

It seems the comma in 113,511 was inhibiting the full value being read.:) I have a lot to learn!

I am having a problem with my C++ Arduino code.  Could you please review it and help me understand why my Values being sent by ARC are not being received? Thanks Jack

C++

#include 
#include 


long pathTotalDistance = 0;
long adjacentRemainingDistance = 0;
long pathEndpointDistance = 0;
float oppositeDistance = 0;
float desiredCourse;
long actualCourse;
float diffCourse=0;
float lastDiff= 100;
int lastIncomingByte;
//int targetLeftSpeed = leftSpeed;
//int targetRightSpeed = rightSpeed;
AccelStepper LeftFrontWheel(1, 3, 6);
AccelStepper LeftBackWheel(1, 2, 5);
AccelStepper RightFrontWheel(1, 12, 13);
AccelStepper RightBackWheel(1, 4, 7);
int run = 0;
int wheelSpeed = 2000;


void setup() {
  Serial3.begin(9600); // Communication with EZ-B
    Serial.begin(9600);  // Debugging via Serial Monitor
   LeftFrontWheel.setMaxSpeed(wheelSpeed * 2);
  LeftBackWheel.setMaxSpeed(wheelSpeed * 2);
  RightFrontWheel.setMaxSpeed(wheelSpeed * 2);
  RightBackWheel.setMaxSpeed(wheelSpeed * 2);
   }



void loop() {

 Main:
if (run == 0) {  //State of RUN when robot has yet to begin movement towards the reflector.
if (lastIncomingByte == 'N') {

// Check if there are at least 9 bytes available (1 header + 8 data bytes)
    if (Serial3.available() >= 14) {
      byte header = Serial3.read();
      if (header == 0xAA) { // Check for header byte


  uint8_t byte0 = Serial.read();
  uint8_t byte1 = Serial.read();
  uint8_t byte2 = Serial.read();
  uint8_t byte3 = Serial.read();
  
  // Combine bytes to form int32: (little-endian)
  int32_t pathTotalDistance = ((int32_t)byte3 << 24) |
                              ((int32_t)byte2 << 16) |
                              ((int32_t)byte1 << 8)  |
                              (int32_t)byte0;
  
  
  Serial.print("pathTotalDistance: ");
  Serial.println(pathTotalDistance);



  uint8_t PEDbyte0 = Serial.read();
  uint8_t PEDbyte1 = Serial.read();
  uint8_t PEDbyte2 = Serial.read();
  uint8_t PEDbyte3 = Serial.read();
  
  // Combine bytes to form int32: (little-endian)
  int32_t pathEndpointDistance = ((int32_t)byte3 << 24) |
                                 ((int32_t)byte2 << 16) |
                                 ((int32_t)byte1 << 8)  |
                                 (int32_t)byte0;
  
  Serial.print("pathEndpointDistance: ");
  Serial.println(pathEndpointDistance);

     
  uint8_t ODbyte0 = Serial.read();
  uint8_t ODbyte1 = Serial.read();
  uint8_t ODbyte2 = Serial.read();
  uint8_t ODbyte3 = Serial.read();
  
  // Combine bytes to form int32: (little-endian)
  int32_t oppositeDistance = ((int32_t)byte3 << 24) |
                             ((int32_t)byte2 << 16) |
                             ((int32_t)byte1 << 8)  |
                             (int32_t)byte0;
  
  Serial.print("oppositeDistance: ");
  Serial.println(oppositeDistance);
  
    
        actualCourse = Serial3.read(); //  Read and store actualCourse
        desiredCourse = Serial3.read();//  Read and store desiredCourse

       // Print the above received paramenters
       Serial.print("actualCourse:  ");
        Serial.println(actualCourse);
        Serial.print("desiredCourse:  ");
        Serial.println(desiredCourse);
        delay(10);
        bufferFlush();
        

 }   
}
}
PRO
Canada
#13  

Below is a revised version of your Arduino code with some corrections. The key changes are:

All UART reads are now taken from Serial3 (the port connected to ARC), not mixing with Serial.
The available byte check uses a comparison (>=) rather than an assignment.
The bit shifting has been corrected using the << operator.

You can copy and modify the code below:


#include <AccelStepper.h>

// Global variables
long pathTotalDistance = 0;
long pathEndpointDistance = 0;
long oppositeDistance = 0;
float desiredCourse = 0;
long actualCourse = 0;

// Setup your stepper motors
AccelStepper LeftFrontWheel(1, 3, 6);
AccelStepper LeftBackWheel(1, 2, 5);
AccelStepper RightFrontWheel(1, 12, 13);
AccelStepper RightBackWheel(1, 4, 7);

int run = 0;
int wheelSpeed = 2000;

void setup() {
  Serial3.begin(9600); // Communication with EZ-B (ARC)
  Serial.begin(9600);  // Debug output via Serial Monitor

  LeftFrontWheel.setMaxSpeed(wheelSpeed * 2);
  LeftBackWheel.setMaxSpeed(wheelSpeed * 2);
  RightFrontWheel.setMaxSpeed(wheelSpeed * 2);
  RightBackWheel.setMaxSpeed(wheelSpeed * 2);
}

void loop() {
  // Only run if the robot is not already in motion
  if (run == 0) {
    // Check that at least 14 bytes are available:
    // 1 header + (3 * 4 bytes for the 32-bit values) + 2 one-byte values
    if (Serial3.available() >= 14) {
      byte header = Serial3.read();
      if (header == 0xAA) {  // Confirm header byte
        // Read 4 bytes for pathTotalDistance
        uint8_t b0 = Serial3.read();
        uint8_t b1 = Serial3.read();
        uint8_t b2 = Serial3.read();
        uint8_t b3 = Serial3.read();
        // Reconstruct the 32-bit integer (little-endian)
        pathTotalDistance = ((long)b3 << 24) | ((long)b2 << 16) | ((long)b1 << 8) | b0;
        Serial.print("pathTotalDistance: ");
        Serial.println(pathTotalDistance);

        // Read 4 bytes for pathEndpointDistance
        b0 = Serial3.read();
        b1 = Serial3.read();
        b2 = Serial3.read();
        b3 = Serial3.read();
        pathEndpointDistance = ((long)b3 << 24) | ((long)b2 << 16) | ((long)b1 << 8) | b0;
        Serial.print("pathEndpointDistance: ");
        Serial.println(pathEndpointDistance);

        // Read 4 bytes for oppositeDistance
        b0 = Serial3.read();
        b1 = Serial3.read();
        b2 = Serial3.read();
        b3 = Serial3.read();
        oppositeDistance = ((long)b3 << 24) | ((long)b2 << 16) | ((long)b1 << 8) | b0;
        Serial.print("oppositeDistance: ");
        Serial.println(oppositeDistance);

        // Read one byte for actualCourse and one for desiredCourse
        actualCourse = Serial3.read();       // one byte value
        desiredCourse = Serial3.read();        // one byte value
        Serial.print("actualCourse: ");
        Serial.println(actualCourse);
        Serial.print("desiredCourse: ");
        Serial.println(desiredCourse);

        // You might want to flush the Serial3 buffer here, if needed.
        // For example:
        while (Serial3.available()) {
          Serial3.read();
        }
      } // end if header
    } // end available check
  } // end run==0 block

  // Other code can follow...
}

Key Points:

  1. Using Serial3 for All Reads:
    Since ARC is sending data on Serial3 at 9600 baud, all reads (header and data bytes) are made from Serial3.

  2. Correct Byte Count Check:
    We use if (Serial3.available() >= 14) to ensure we have at least the expected number of bytes before reading. Adjust the byte count if your protocol changes.

  3. Bit Shifting Syntax:
    Each 32-bit value is reconstructed using the << operator. For example:
    ((long)b3 << 24) | ((long)b2 << 16) | ((long)b1 << 8) | b0

  4. Header Byte:
    A header byte (0xAA) is used to mark the start of your data packet.

  5. Buffer Flushing:
    After reading all the expected data, the remaining bytes in Serial3 are flushed (if needed) so that subsequent reads aren’t affected by a previous incomplete packet.

Please verify that your ARC code is sending the bytes in the expected order and that the baud rate matches on both sides. Let me know if you have any further questions or need additional adjustments!


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

Hello @Athena, I'm not able to receive any data with the Arduino.  I did change the expected bytes to be received to 15 from 14 to account for the header.  See the code below:

#include 
#include 

// Global variables
long pathTotalDistance = 0;
long pathEndpointDistance = 0;
long oppositeDistance = 0;
float desiredCourse = 0;
long actualCourse = 0;

// Setup your stepper motors
AccelStepper LeftFrontWheel(1, 3, 6);
AccelStepper LeftBackWheel(1, 2, 5);
AccelStepper RightFrontWheel(1, 12, 13);
AccelStepper RightBackWheel(1, 4, 7);

int run = 0;
int wheelSpeed = 2000;

void setup() {
  Serial3.begin(9600); // Communication with EZ-B (ARC)
  Serial.begin(9600);  // Debug output via Serial Monitor

  LeftFrontWheel.setMaxSpeed(wheelSpeed * 2);
  LeftBackWheel.setMaxSpeed(wheelSpeed * 2);
  RightFrontWheel.setMaxSpeed(wheelSpeed * 2);
  RightBackWheel.setMaxSpeed(wheelSpeed * 2);
}

void loop() {
  // Only run if the robot is not already in motion
  if (run == 0) {
    // Check that at least 14 bytes are available:
    // 1 header + (3 * 4 bytes for the 32-bit values) + 2 one-byte values
    if (Serial3.available() >= 15) {
      byte header = Serial3.read();
      if (header == 0xAA) {  // Confirm header byte
        // Read 4 bytes for pathTotalDistance
        uint8_t b0 = Serial3.read();
        uint8_t b1 = Serial3.read();
        uint8_t b2 = Serial3.read();
        uint8_t b3 = Serial3.read();
        // Reconstruct the 32-bit integer (little-endian)
        pathTotalDistance = ((long)b3 << 24) | ((long)b2 << 16) | ((long)b1 << 8) | b0;
        Serial.print("pathTotalDistance: ");
        Serial.println(pathTotalDistance);

        // Read 4 bytes for pathEndpointDistance
        b0 = Serial3.read();
        b1 = Serial3.read();
        b2 = Serial3.read();
        b3 = Serial3.read();
        pathEndpointDistance = ((long)b3 << 24) | ((long)b2 << 16) | ((long)b1 << 8) | b0;
        Serial.print("pathEndpointDistance: ");
        Serial.println(pathEndpointDistance);

        // Read 4 bytes for oppositeDistance
        b0 = Serial3.read();
        b1 = Serial3.read();
        b2 = Serial3.read();
        b3 = Serial3.read();
        oppositeDistance = ((long)b3 << 24) | ((long)b2 << 16) | ((long)b1 << 8) | b0;
        Serial.print("oppositeDistance: ");
        Serial.println(oppositeDistance);

        // Read one byte for actualCourse and one for desiredCourse
        actualCourse = Serial3.read();       // one byte value
        desiredCourse = Serial3.read();        // one byte value
        Serial.print("actualCourse: ");
        Serial.println(actualCourse);
        Serial.print("desiredCourse: ");
        Serial.println(desiredCourse);

        // You might want to flush the Serial3 buffer here, if needed.
        // For example:
        while (Serial3.available()) {
          Serial3.read();
        }
      } // end if header
    } // end available check
  } // end run==0 block

  // Other code can follow...
}

I am sending with the following JavaScript:

// Making local variables from global variables.
var pathTotalDistance = getVar("$pathTotalDistance");//113511 steps

var pathEndpointDistance = getVar("$pathEndpointDistance");//80000 steps

var oppositeDistance = getVar("$oppositeDistance");//11891 steps

var actualCourse = getVar("$actualCourse");

var desiredCourse = getVar("$desiredCourse");


The JavaScript values print.  Can you review the above code for obvious errors? Thank you. Jack

PRO
Synthiam
#15  

@athena I have a quick question. Why do you wait for 14 or more bytes when with header the total packet would be 15 bytes. As you said:  1 header + (3 * 4 bytes for the 32-bit values) + 2 one-byte values. Isn’t that 15?

#16  

Hello @Athena, My JavaScript in the above post did not come through completely.  It follows:

// Making local variables from global variables.
var pathTotalDistance = getVar("$pathTotalDistance");//113511 steps

var pathEndpointDistance = getVar("$pathEndpointDistance");//80000 steps

var oppositeDistance = getVar("$oppositeDistance");//11891 steps

var actualCourse = getVar("$actualCourse");

var desiredCourse = getVar("$desiredCourse");


// Send the variables to Arduino
var header = 0xAA; // Arbitrary header byte
UART.hardwareUartWrite(0, header);
print("header:  " + header);


// Extract the 4 bytes using bitwise AND (&) and right shift (>>)
// Assuming littleendian (LSB first)
var byte0 = pathTotalDistance & 0xFF;                  // Least Significant Byte
var byte1 = (pathTotalDistance >> 8) & 0xFF;
var byte2 = (pathTotalDistance >> 16) & 0xFF;
var byte3 = (pathTotalDistance >> 24) & 0xFF;            // Most Significant Byte

// Create an array of bytes to send
var PTD = [byte0, byte1, byte2, byte3];

// Send the byte array over UART, using a baud rate of 9600 (adjust as needed)
UART.sendSerial(0, 9600, PTD);

// Print the bytes to check their values
//print("Byte0: " + byte0 + " | Byte1: " + byte1 + " | Byte2: " + byte2 + " | Byte3: " + byte3);
print("pathTotalDistance:   " + pathTotalDistance );




//var pathEndpointDistance = getVar($pathEndpointDistance);  // e.g. 80000
var byte0 = pathEndpointDistance & 0xFF;
var byte1 = (pathEndpointDistance >> 8) & 0xFF;
var byte2 = (pathEndpointDistance >> 16) & 0xFF;
var byte3 = (pathEndpointDistance >> 24) & 0xFF;
var PED = [byte0, byte1, byte2, byte3];
UART.sendSerial(0, 9600, PED);
print("pathEndpointDistance:  " + pathEndpointDistance);

// And for oppositeDistance
//var oppositeDistance = getVar($oppositeDistance);  // e.g. 11891
var byte0 = oppositeDistance & 0xFF;
var byte1 = (oppositeDistance >> 8) & 0xFF;
var byte2 = (oppositeDistance >> 16) & 0xFF;
var byte3 = (oppositeDistance >> 24) & 0xFF;
var OD = [byte0, byte1, byte2, byte3];
UART.sendSerial(0, 9600, OD);
print("oppositeDistance   " + oppositeDistance);

/* The remainder of your code (actualCourse and desiredCourse) remains the same,
   provided that they are within one byte, so they can be sent directly using UART.hardwareUartWrite */
UART.hardwareUartWrite(0, actualCourse); // Send as one byte
UART.hardwareUartWrite(0, desiredCourse);  // Send as one byte
print("actualCourse  " + actualCourse);
print("desiredCourse  " + desiredCourse);




Can you check it or errors? Thanks Jack