Asked — Edited

UART Communication Between EZ-B And Arduino

Hi @Athena,

I am seeking assistance for a project where I need to establish UART communication between an EZ-Robot EZ-B v4 controller and an Arduino Mega 2560. My objective is to send and receive integer values in the range of 0 to 180 between these two devices.

On the EZ-B v4 side, I will be utilizing JavaScript within the Synthiam ARC environment. Meanwhile, the Arduino Mega 2560 will be programmed using C++.

Could you please provide a sample code or guidance on how to effectively set up this communication?

Thank you for your help, Jack


Related Hardware Roli Rover
Related Controls Serial Toolbox Serial Terminal

ARC Pro

Upgrade to ARC Pro

Unleash your creativity with the power of easy robot programming using Synthiam ARC Pro

Author Avatar
PRO
Canada
#1  

Good - this is straightforward to do. Below I’ll give:

  • wiring and safety notes,
  • two recommended data formats (binary single-byte and ASCII line),
  • ARC (JavaScript) examples you can drop into a Script robot skill,
  • Arduino Mega (C++) examples to match each format,
  • quick test steps and how to configure robot skills via the kebab menu.

If you prefer one format over the other (binary vs ASCII), tell me which and which EZ-B UART index (0,1,2) you want to use and I’ll adapt the code.

Important wiring & safety

  • Cross TX/RX: EZ-B TX -> Arduino RX, EZ-B RX -> Arduino TX.
  • Common ground: connect EZ-B GND to Arduino GND.
  • Voltage levels: confirm both sides use compatible TTL voltage. EZ-B v4 and Arduino Mega typically both use 5V TTL, but if your hardware differs, use a logic level shifter. Don’t rely on USB ground alone - tie grounds together.
  • Choose a UART index on the EZ-B (0, 1 or 2). On the Arduino Mega you’ll use Serial1/Serial2/Serial3 pins (TX/RX pairs).
  • Pick a baud rate (matching on both sides). I’ll use 115200 in examples but 9600 or 38400 are fine.

ARC (JavaScript) - recommended approach

  • Add a Script robot skill to your project (Project -> Add robot skill -> choose Script/JavaScript).
  • Open the skill settings with the kebab (three lines) on the top-right of that robot skill window if you need skill-specific settings. (Kebab menu = the three horizontal lines on the skill).
  • Use the built-in UART functions. Prefer sending either a single binary byte 0..180, or an ASCII decimal followed by newline (easier to debug).

Example A - Binary single-byte (compact, fastest)

  • Sends a single byte value (0..180). On Arduino use SerialX.read() to get 0..255.

ARC JavaScript (binary)

// Set your UART index and baud
var uart = 1; // 0,1,2
var baud = 115200;

// initialize UART (ezb index default 0)
UART.initHardwareUart(uart, baud);
print("UART initialized on index " + uart + " at " + baud);

// send numeric value as single binary byte
function sendValueByte(value) {
  if (value < 0) value = 0;
  if (value > 255) value = 255; // safety
  UART.hardwareUartWrite(uart, [value]); // send as byte array
  print("Sent byte: " + value);
}

// example: send 90 every second
for (var i = 0; i < 5; i++) {
  sendValueByte(90 + i); // send 90,91,...
  sleep(1000); // milliseconds
}

// read any incoming bytes
var available = UART.hardwareUartAvailable(uart);
if (available > 0) {
  var data = UART.hardwareUartReadStringAvailable(uart); // returns string, but binary may contain non-printables
  print("Received (as string): " + data);
}

Arduino Mega C++ (binary)

// Example using Serial1 (pins: RX1=19, TX1=18).
// Match uart index and wiring to your EZ-B connection.

void setup() {
  Serial.begin(115200); // debug to PC
  Serial1.begin(115200); // connection to EZ-B
  Serial.println("Arduino Serial1 started");
}

void loop() {
  // Read incoming byte(s) from EZ-B
  while (Serial1.available() > 0) {
    int v = Serial1.read(); // 0..255 (or -1 if none)
    Serial.print("Got byte from EZ-B: ");
    Serial.println(v);
  }

  // Example: send a value 0..180 to EZ-B
  int sendVal = 100;
  Serial1.write((uint8_t)sendVal); // binary single byte
  Serial.print("Sent byte to EZ-B: ");
  Serial.println(sendVal);

  delay(1000);
}

Example B - ASCII decimal with newline (easier to test with terminals)

  • Send human-readable "123\n". Simpler when troubleshooting via Serial Terminal skill or PC.

ARC JavaScript (ASCII / newline)

var uart = 1;
var baud = 115200;
UART.initHardwareUart(uart, baud);
print("UART initialized on index " + uart + " at " + baud);

// send ascii decimal followed by newline
function sendValueAscii(value) {
  var s = "" + value + "\n"; // newline-terminated
  UART.hardwareUartWriteString(uart, s);
  print("Sent ASCII: " + s);
}

// example send
sendValueAscii(120);

// read lines (if any)
var incoming = UART.hardwareUartReadStringAvailable(uart);
if (incoming && incoming.length > 0) {
  print("Incoming raw: " + incoming);
  // parse numbers if your Arduino sends "123\n"
  var parts = incoming.split("\n");
  for (var i = 0; i < parts.length; i++) {
    var p = parts[i].trim();
    if (p.length > 0) {
      var n = parseInt(p, 10);
      if (!isNaN(n)) print("Parsed number: " + n);
    }
  }
}

Arduino Mega C++ (ASCII / newline)

// Example using Serial1
void setup() {
  Serial.begin(115200); // debug
  Serial1.begin(115200); // to EZ-B
  Serial.println("Arduino Serial1 started (ASCII mode)");
}

String inputBuffer = "";

void loop() {
  // Read incoming ascii from EZ-B
  while (Serial1.available() > 0) {
    char c = (char)Serial1.read();
    if (c == '\n') {
      inputBuffer.trim();
      if (inputBuffer.length() > 0) {
        int val = inputBuffer.toInt();
        Serial.print("Received number from EZ-B: ");
        Serial.println(val);
        // do something with val (0..180)
      }
      inputBuffer = "";
    } else {
      inputBuffer += c;
    }
  }

  // Example: send a number
  int toSend = 75;
  Serial1.print(toSend);
  Serial1.print('\n');
  Serial.print("Sent to EZ-B: ");
  Serial.println(toSend);

  delay(1000);
}

Testing steps

  1. Wire TX/RX crossed and GND common.
  2. Upload Arduino sketch and open Serial Monitor (for debugging).
  3. In ARC, add a Script robot skill (Project -> Add Robot Skill).
  4. Paste one of the JavaScript examples; set uart index and baud to match the Arduino sketch.
  5. Run the script. Watch the Arduino Serial Monitor and ARC Script output (print()).
  6. If you want to inspect raw bytes visually, you can add the Serial Terminal (PC) or Serial Terminal (EZB) skill - open the skill window and use its kebab menu (three lines top-right) to configure settings (port or UART) for manual testing. For programmatic control, scripts are better.

Configure robot skills via the kebab menu (quick)

  • Open the robot skill window (e.g., Serial Terminal, your Script skill).
  • Click the kebab (three horizontal lines) at the skill’s top-right.
  • Choose Settings or Configure (depending on the skill).
  • Adjust parameters (UART index, baud, COM port, etc.), Save/OK.
  • For Script skills there’s typically an Edit or Open button to paste code.

Relevant links

Follow-ups / questions

  • Which UART index on the EZ-B will you use (0,1 or 2)?
  • Do you prefer binary single-byte (compact) or ASCII newline-terminated values (easier to debug)?
  • Which Arduino Serial port will you wire to (Serial1/2/3)?
  • Would you like me to prepare a single combined test script that sends values from ARC and echoes back from the Arduino with ACKs?

Tell me the UART index and format you prefer and I’ll give you a tailored script + wiring diagram for your exact setup.


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

Ok let me show you a code snippet and please help me rewrite it to meet my requirements.

 if (UART.hardwareUartAvailable(0) >= 5) {  //5
       var header = UART.hardwareUartReadString(0,1); 
       sleep(10);

       if (header == 'D'){
       var DCSRead = UART.hardwareUartRead(0, 1);
       var desiredCourseScaled = (( DCSRead[3] << 24) | (  DCSRead[2] << 16) | ( DCSRead[1] << 8) | DCSRead[0]);
       setVar("$desiredCourse", desiredCourseScaled);   
       print("rec'd desiredCourse:  " + getVar("$desiredCourse")+ "    cyc:  " + 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: " + cycleCount + "   $desiredCourse: " + Math.round( getVar("$desiredCourse")) + "   $actualCourse: " + getVar("$actualCourse"));
       sleep(100);
       
       controlCommand("$IR_1", "PauseOff");
       halt();
       }
       }   

My requirements:  If header "D" is available, read it as an inbound number 0-180.  I do not need to parse it from 4 bytes. Can you rewrite header D to only receive 1 byte? No need to change header "T", it will remain the same as it is coming from the Arduino in 4 bytes. Thanks, Jack

Author Avatar
PRO
Canada
#3  

Thanks - this is a small, safe change. Below I:

  • give a ready-to-paste ARC JavaScript Script skill that:
    • initializes the EZ-B UART,
    • reads a single-byte payload for header "D" (0-180),
    • leaves the "T" behavior exactly as you had (4 bytes),
    • does basic checks and helpful prints.
  • include a short Arduino example showing how to send the single-byte "D" payload and how to send the existing 4-byte "T" payload.
  • explain the important details and a couple of small recommendations.

ARC JavaScript (paste into a Script robot skill)

  • Make sure you open the skill settings (kebab menu) and add this Script. Ensure you call UART.initHardwareUart(...) once before reading if you haven't already.
// UART index and baud - change if needed
var uart = 0;    // your code used uart 0
var baud = 115200;

// Initialize the hardware UART (call once)
UART.initHardwareUart(uart, baud);
print("UART initialized on index " + uart + " @ " + baud);

// Main loop - runs forever inside the Script skill
while (true) {
  // Only proceed if there's at least 1 byte available
  if (UART.hardwareUartAvailable(uart) > 0) {
    // Read 1 byte as header (returns a string of length 1)
    var header = UART.hardwareUartReadString(uart, 1);
    // small pause to allow payload bytes to arrive (ms)
    sleep(10);

    if (header == 'D') {
      // D header expects a single byte payload (0..180)
      if (UART.hardwareUartAvailable(uart) >= 1) {
        var DCSRead = UART.hardwareUartRead(uart, 1); // returns byte array
        var desiredCourse = DCSRead[0]; // numeric 0..255
        // clamp to your desired range 0..180
        if (desiredCourse > 180) desiredCourse = 180;
        setVar("$desiredCourse", desiredCourse);
        print("rec'd desiredCourse: " + getVar("$desiredCourse") + " cyc:" + cycleCount);
      } else {
        print("Header 'D' received but waiting for 1 payload byte...");
      }
    }
    else if (header == 'T') {
      // T header expects 4 payload bytes (little-endian as in your code)
      if (UART.hardwareUartAvailable(uart) >= 4) {
        var TSTRead = UART.hardwareUartRead(uart, 4);
        // Build unsigned 32-bit value from 4 bytes (low -> high)
        var totalStepsTaken = (((TSTRead[3] << 24) | (TSTRead[2] << 16) | (TSTRead[1] << 8) | TSTRead[0]) >>> 0);
        print("totalStepsTaken:" + totalStepsTaken);
        print("CYC:" + cycleCount + "$desiredCourse:" + Math.round(getVar("$desiredCourse")) + "$actualCourse:" + getVar("$actualCourse"));
        sleep(100);
        controlCommand("$IR_1", "PauseOff");
        halt();
      } else {
        print("Header 'T' received but waiting for 4 payload bytes...");
      }
    }
    else {
      print("Unknown header: " + header);
    }
  }

  // short sleep so this loop isn't busy-waiting (milliseconds)
  sleep(20);
}

Notes on the ARC code

  • I read the header first and then verify the required payload bytes are available before calling UART.hardwareUartRead(...). This avoids partial reads.
  • For header "D" we read only 1 byte and set $desiredCourse to that byte (clamped to 0..180).
  • For header "T" I left your original 4-byte logic intact but made the 32-bit assembly unsigned with >>> 0 so negative values are not produced by JS bitwise behavior.
  • Keep UART.initHardwareUart(uart, baud) in your project init code (or at the top of the script) so the EZ-B UART is ready.

Arduino examples (Mega)

  • Send one-byte payload after 'D' header:
// Example: send single-byte D payload on Serial1 (pins TX1=18, RX1=19)
void sendD(uint8_t val) {
  Serial1.write('D');        // header
  Serial1.write(val);        // single byte payload (0..180)
}
  • Send the existing 4-byte little-endian payload after 'T' header (matching your earlier parse order):
void sendT(uint32_t steps) {
  Serial1.write('T');            // header
  Serial1.write((uint8_t)(steps & 0xFF));       // byte 0 (LSB)
  Serial1.write((uint8_t)((steps >> 8) & 0xFF));  // byte 1
  Serial1.write((uint8_t)((steps >> 16) & 0xFF)); // byte 2
  Serial1.write((uint8_t)((steps >> 24) & 0xFF)); // byte 3 (MSB)
}

Important wiring / timing reminders

  • TX/RX cross: EZ-B TX -> Arduino RX, EZ-B RX -> Arduino TX.
  • Common ground required.
  • Match baud rate on both sides and use UART.initHardwareUart(...) on the ARC side.
  • If you send 'D' then the Arduino should immediately send the one-byte payload after the header. The script expects the payload to arrive soon (we use sleep(10) to give a small window). If you have a longer gap before payload, increase the sleep or change the available checks logic.

Follow-ups I can help with

  • Do you want the value mapped or transformed (e.g., mapped from 0..180 to a servo range)?
  • Would you prefer ASCII/text values (e.g. "D120\n") for easier debugging, or the compact binary approach shown here?
  • Want me to prepare a minimal combined test (ARC <-> Arduino) that echoes back an ACK so you can verify round-trip?

Useful docs & links

If you paste the Arduino send routine you're using I can confirm it matches this parsing (little-endian vs big-endian) and adjust accordingly.


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.