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

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
#1  

Below is a few tips to ensure larger numeric values are transmitted reliably via UART from ARC to your Arduino:

  1. Use a Consistent Data Format
    Instead of sending a raw number, create a structured message. For example, you can concatenate your variables into a delimited string or even use a JSON structure. For instance:

    Delimited string example:

    message = "113511,80000,11891"

    JSON example:

    message = '{"pathTotal":113511,"pathEndpoint":80000,"opposite":11891}'

    By using delimiters or a JSON format, you create a clear protocol so the Arduino can split the message accurately.

  2. Convert Values to Text (if using ASCII)
    Both small and large numbers are transmitted as a sequence of characters when using the Serial Toolbox or Terminal. You can simply use setVar() in ARC to hold the numbers and then convert them to a string before sending. For example, in a JavaScript (or Python) script within ARC you might do:

    JavaScript Example:

    print("Preparing data to send...");

    // These variables were set previously var pathTotal = getVar("$pathTotalDistance");
    var pathEndpoint = getVar("$pathEndpointDistance");
    var opposite = getVar("$oppositeDistance");

    // Create a delimited message (commas as delimiters) var message = pathTotal + "," + pathEndpoint + "," + opposite;

    // Send the message to your Arduino via your Serial Toolbox skill controlCommand("Serial Toolbox", "SendData", message);

    print("Sent: " + message);

    On the Arduino side you can use Serial.readStringUntil() or similar functions to read until the delimiter (or newline if you append one) and then parse the integers.

  3. Consider Baud Rate and Timing
    Ensure that the baud rate for the Serial Toolbox skill in ARC and the Arduino Serial.begin() speed are set to match and are fast enough for the size of your data. Most larger numbers won’t be an issue at typical baud rates (like 115200), but having a consistent baud rate is key.

  4. Error Checking (Optional But Recommended)
    To further ensure the integrity of your data, you might add a simple checksum or use a reserved start/end flag in your message. For example, you might wrap your data as:

    Example: <START>113511,80000,11891<END>

    Then, on the Arduino side, validate that the message starts and ends with the correct marker before processing the data.

  5. Binary Transmission Alternative
    If you’re concerned about potential parsing errors or timing issues with ASCII strings and your Arduino has the resources to deal with binary data, you can convert your numbers into bytes (if they fit within 32 bits) and then send them in binary form. However, this approach requires extra handling on the Arduino side (using functions like Serial.readBytes()) and careful attention to endianness.


Follow-Up

Do these tips help match what you require? Are you currently processing the received data as a string on the Arduino side? Would you like further details on parsing the data (whether it’s ASCII or binary) on the Arduino? Feel free to ask for additional clarification or sample Arduino code if needed.

For more help with ARC or creating custom robot skills, check out Synthiam’s support documentation here: Synthiam ARC Documentation.

Let me know if you need anything else!


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
#2  

@athena I think he’s asking how to send numbers that are larger than a byte over the uart. Most likely to an arduino. Given the size of the example numbers maybe int32 is best.

It would be worthwhile to explain how 4 bytes becomes an int32. And how computers store information in bytes.

PRO
Canada
#3  

Below is an explanation of how you can send numbers larger than one byte-and in particular, how to pack an int32 into four bytes for UART transmission. This means that you’re no longer sending just one byte (0-255), but a full 32-bit (4-byte) integer that can range from -2,147,483,648 to 2,147,483,647 (if signed) or 0 to 4,294,967,295 (if unsigned).


How Computers Store and Send Numbers

1. Bytes and Integers

  • A byte is 8 bits of data.
  • A 32-bit integer (commonly called an int32) is made up of 4 bytes (4 × 8 bits = 32 bits).
  • This means the full number is stored across 4 different bytes.

2. Endianness

  • Little-endian: The least significant byte (LSB) comes first.
  • Big-endian: The most significant byte (MSB) comes first.

When you send data via UART, both the transmitting and receiving devices must agree on the byte order. In many systems (including Arduino by default), little-endian is commonly used.


Packing an int32 into 4 Bytes

Imagine you have a number, say 113511, that you want to send from ARC to your Arduino. In your ARC script (using JavaScript, for example), you can convert this number into 4 bytes. Here’s how you can do it:

  1. Extract the Bytes

    You can use bit shifting and masking to extract each byte:

    • Byte0: the lowest order byte
    • Byte1: the next byte
    • Byte2: the next byte
    • Byte3: the highest order byte

    For a little-endian format (LSB first):

    var number = 113511; // or any larger number
    var byte0 = number & 0xFF;              // LSB
    var byte1 = (number >> 8) & 0xFF;         // next byte
    var byte2 = (number >> 16) & 0xFF;        // next byte
    var byte3 = (number >> 24) & 0xFF;        // MSB
    
  2. Create a Byte Array or a Data String

    You can then pack these bytes into a byte array or concatenated string format that you send via UART. For example, if you’re using a custom skill that supports sending binary data, you might create an array:

    var data = [byte0, byte1, byte2, byte3];
    controlCommand("Serial Toolbox", "SendBytes", data);
    

    (Be sure that the Serial Toolbox skill supports binary data. Otherwise, you can convert these bytes to a string in a known format and then decode them on the Arduino side.)


Reconstructing the int32 on Arduino

On the Arduino side, you will need to read these four bytes and piece them together to reconstruct the original number. Assuming you are using little-endian ordering:

int32_t receivedNumber = 0;
if (Serial.available() >= 4) {  // wait until 4 bytes are available
  uint8_t byte0 = Serial.read();
  uint8_t byte1 = Serial.read();
  uint8_t byte2 = Serial.read();
  uint8_t byte3 = Serial.read();

  // For little-endian reconstruction:
  receivedNumber = byte0 | (byte1 << 8) | (byte2 << 16) | (byte3 << 24);
  
  // Now, receivedNumber should equal the original value sent from ARC.
}

For big-endian transmission, the order would be reversed (byte3 being read first, etc.).


Summary

  • Int32 Representation: A 32-bit (int32) number occupies 4 bytes.
  • Splitting into Bytes: Use bit masking and shifting on the transmitting side in ARC:
    • byte0 = number & 0xFF
    • byte1 = (number >> 8) & 0xFF
    • byte2 = (number >> 16) & 0xFF
    • byte3 = (number >> 24) & 0xFF
  • Transmitting Data: Send these 4 bytes via UART.
  • Reconstructing on Arduino: Read 4 bytes and combine them using bit shifting to recreate the original number.

Additional Notes

  • Error Checking: You might include start and end markers or checksums to confirm that the correct number of bytes have been received and that no data has been corrupted.
  • Baud Rate: Ensure that both ARC and Arduino are using the same baud rate (for example, 115200) to maintain data integrity.
  • Binary vs. ASCII: While sending numbers as text (ASCII) can work, sending binary representations saves bandwidth and ensures that the full 32-bit value is transmitted without any ambiguity.

Does this explanation and the sample code help with your application? Feel free to ask if you need additional examples or clarifications on parsing the data, handling endianness, or any other aspect of UART communication with larger numbers!


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
#4  

@Athena don't use the serial toolbox. Just use the UART javascript commands in ARC.

PRO
Canada
#5   — Edited

Below is an example of how to pack a 32-bit integer into four bytes and send it over UART using ARC’s built-in UART JavaScript commands-no Serial Toolbox required!


1. Understanding the Process

An int32 (32-bit integer) is stored in 4 bytes.
For example, the number 113511 (decimal) can be split into four 8-bit segments (bytes).
When sending over UART, you’ll send these four bytes in sequence.
(In our example, we’ll assume a littleendian order-i.e. leastsignificant byte first, which is common with Arduino.)


2. Packing the Number into Bytes

You can use bitwise operations to extract each of the four bytes from your integer. For example:

  • Byte0 = number & 0xFF       // Lowest-order byte
  • Byte1 = (number >> 8) & 0xFF   // Next byte
  • Byte2 = (number >> 16) & 0xFF  // Next byte
  • Byte3 = (number >> 24) & 0xFF  // Highest-order byte

3. Sending via UART with ARC’s Commands

In ARC, you can use the UART.sendSerial() command to send the byte array. (Remember to match the baud rate on both ARC and your Arduino.)

Here’s a sample JavaScript snippet for ARC:


/* Example: Sending an int32 (113511) as 4 bytes via UART */

// Define your number (here: 113511)
var number = 113511;

// Extract four bytes (assuming little-endian; LSB first)
var byte0 = number & 0xFF;             // Least Significant Byte
var byte1 = (number >> 8) & 0xFF;       
var byte2 = (number >> 16) & 0xFF;
var byte3 = (number >> 24) & 0xFF;       // Most Significant Byte

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

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

// Initialize the UART (if not already done)
// For example, initialize UART 0 with baud rate 115200
UART.initHardwareUart(0, 115200);

// Now, send the byte array via UART.
// Use the UART.sendSerial() command: 
//   UART.sendSerial(port, baudRate, byte or byteArray, [ezbIndex])
// Replace 'COMx' with the actual port name if needed or use the hardware UART by specifying the EZB index.
UART.sendSerial(0, 115200, data);  

print("Sent int32 value " + number + " as 4 bytes over UART.");

Notes:

In our example, we are initializing and sending on hardware UART 0 at 115200 baud. Adjust the UART index and baud rate as needed.
The UART.sendSerial() function sends either a single byte or an array of bytes. Here we are using an array to send all 4 bytes at once.
On the Arduino side, be sure to read 4 bytes (using Serial.read() or Serial.readBytes()) and reassemble them by reversing the bitshifts to reconstruct your original int32.


4. Arduino Side Code Example

On Arduino (assuming littleendian), you might reconstruct the number like this:


/* Arduino: Reconstructing a 32-bit number from 4 received UART bytes */
if (Serial.available() >= 4) {
  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 receivedNumber = ((int32_t)byte3 << 24) |
                           ((int32_t)byte2 << 16) |
                           ((int32_t)byte1 << 8)  |
                           (int32_t)byte0;
  
  Serial.print("Received Number: ");
  Serial.println(receivedNumber);
}


Summary

We first split the larger number into 4 bytes using bitwise operations.
Then we send these 4 bytes over UART using the UART.sendSerial() command in ARC.
On the Arduino side, the same 4 bytes are received and reassembled into the original int32.

Does this approach match your needs for sending larger numbers reliably over UART? Let me know if you need any additional clarification or 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.
#6  

Hello @Athena, Thank you for your help.  Could you please look at the following JavaScript code and advise if it is correct? It only prints the first half of the value, 113 for 113511, 80 for 80000, and 11 for 11891.

Thanks Jack

// 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");

sleep(1000);

// Send the variables to Arduino


var header = 0xAA; // Arbitrary header byte
UART.hardwareUartWrite(0, [header]);


// Extract four bytes (assuming little-endian; 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
var PTD = [byte0, byte1, byte2, byte3];
UART.sendSerial(0, 9600, PTD);

//  Print the bytes to check their values
print("Byte0: " + byte0 + " | Byte1: " + byte1 + " | Byte2: " + byte2 + " | Byte3: " + byte3);  
print("Sent int32 value " + pathTotalDistance + " as 4 bytes over UART.");


var byte0 = pathEndpointDistance & 0xFF;//LSB
var byte1 = (pathEndpointDistance >> 8) & 0xFF;
var byte2 = (pathEndpointDistance >> 16) & 0xFF;
var byte3 = (pathEndpointDistance >> 24) & 0xFF;//MSB
//Create an array of bytes
var PED = [byte0, byte1, byte2, byte3];
UART.sendSerial(0, 9600, PED);

//  Print the bytes to check their values
print("Byte0:  " + byte0 + " | Byte1:  " + byte1 + " | Byte2: " + byte2 + " | Byte3: " + byte3);  
print("Sent int32 value " + pathEndpointDistance + " as 4 bytes over UART.");



var byte0 = oppositeDistance & 0xFF;//LSB
var byte1 = (oppositeDistance >> 8) & 0xFF;
var byte2 = (oppositeDistance >> 16) & 0xFF;
var byte3 = (oppositeDistance >> 24) & 0xFF;//MSB
//Create an array of bytes
var OD = [byte0, byte1, byte2, byte3];
UART.sendSerial(0, 9600, OD);

//  Print the bytes to check their values
print("Byte0:  " + byte0 + " | Byte1:  " + byte1 + " | Byte2: " + byte2 + " | Byte3: " + byte3);  
print("Sent int32 value " + oppositeDistance + " as 4 bytes over UART.");


var highByte = (oppositeDistance >> 8) & 0xFF;
var lowByte = oppositeDistance & 0xFF;
UART.hardwareUartWrite(0, [highByte, lowByte]);
//print("Sending oppositeDistance high byte: " + (oppositeDistance >> 8));
//print("Sending oppositeDistance low byte: " + (oppositeDistance & 0xFF));



UART.hardwareUartWrite(0, [actualCourse]); // Send as one byte
UART.hardwareUartWrite(0, [desiredCourse]);  // Send as one byte
//print("Sending actualCourse   " + actualCourse);
//print("Sending desiredlCourse   " + desiredCourse);
//setVar("$actualCourse", (Servo.GetPosition(17)));


PRO
Canada
#7   — Edited

Below is an explanation of why your code only prints the first half of your larger numbers and how to fix it. The problem is that your code uses syntax like:

  pathTotalDistance 0xFF

without any bitwise operator. In JavaScript, to extract the individual bytes of a 32bit number you need to use the bitwise AND (&) along with the right shift (>>) operator. For example, to extract the least significant byte (LSB) from a number you use:

  var byte0 = pathTotalDistance & 0xFF;

Then, to get the next bytes you rightshift the number by 8, 16, and 24 bits respectively and then mask with 0xFF so that you only get 8 bits. Here’s how you should modify your code:


/* Example: Sending a 32bit integer over UART using the builtin UART JavaScript commands */

// Retrieve the global variable (example value: 113511)
var pathTotalDistance = getVar($pathTotalDistance);  // e.g. 113511

// Wait a bit before transmission
sleep(1000);  

// Send a header if needed (0xAA in this case)
var header = 0xAA;
UART.hardwareUartWrite(0, [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("Sent int32 value " + pathTotalDistance + " as 4 bytes over UART.");

/* Repeat similar steps for the other values, for example: */

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("Sent int32 value " + pathEndpointDistance + " as 4 bytes over UART.");

// 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("Sent int32 value " + oppositeDistance + " as 4 bytes over UART.");

/* 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, [ getVar($actualCourse) ]); // Send as one byte
UART.hardwareUartWrite(0, [ getVar($desiredCourse) ]);  // Send as one byte

Explanation

  1. Bitwise Operators:
    - The "&" operator masks the value with 0xFF (which is 255 in decimal) so that only the lowest 8 bits remain.
    - The ">>" operator shifts the bits to the right. For example, pathTotalDistance >> 8 shifts the 32 bits 8 positions to the right so that what was originally in bits 8-15 now becomes the least significant byte.

  2. Byte Order (Endianness):
    - Here we assume a littleendian system (common for Arduino) where the least significant byte is sent first. - On the Arduino side, you will need to reassemble these 4 bytes using bit shifting in the reverse order.

  3. UART.sendSerial vs. UART.hardwareUartWrite:
    - Use UART.sendSerial(0, 9600, array) to send an array of bytes.
    - Use UART.hardwareUartWrite for single bytes if needed.

By updating your code to use the proper bitwise operators, you’ll correctly extract all four bytes of your 32bit integer rather than only seeing what appears to be the first half (the lower 8 bits).

Does this revised code and explanation help address your issue? Feel free to ask if you have any more questions or need additional 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.
#8  

Hello @Athena,   Thank you for your help.  This is all very new to me and I am trying to understand what you are saying.  I have studied the code and the explanation you provided, and it makes sense.  However, I cannot find any difference in the code I posted and the code you posted as the remedy for the partial print problem.  Furthermore, when I copy and paste the new code, I get the same partial print of the values as described in my first post.  I am sure I am missing something obvious.  Can you please review the code you provided to be sure it sends and prints the values I need to use?  Thank you for your extra help in this matter. Jack