Asked — Edited
Resolved Resolved by Athena!

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 (view all EZB hardware)
Roli Rover by EZ-Robot
Roli WiFi planetary rover kit, customizable with 13 ez-bit ports for add-ons, built to traverse varied surfaces. Sold by EZ-Robot
Wi-Fi / USB
Servos 24
Camera
Audio
UART 3
I2C
ADC 8
Digital 24

Related Robot Skills (view all robot skills)
Serial Terminal by Synthiam
PC and EZB serial terminals for ARC: connect, monitor and send text/ASCII to serial devices. Supports COM, flow control, baud, DTR/RTS, hex
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

ARC Pro is more than a tool; it's a creative playground for robot enthusiasts, where you can turn your wildest ideas into reality.

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

Thank you, Athena.  Lots to ponder here.  These are all great examples that teach me a lot. I've discovered a hardware problem with my robot that I must solve first.  I think I'm wearing it out. :( Jack

Author Avatar
PRO
Canada
#5  

Sorry to hear you found a hardware issue - that’s a common place to stop and repair before continuing with communications. Below are practical, prioritized inspection and test steps (mechanical + electrical) you can run with ARC and a few small JavaScript test scripts you can paste into a Script robot skill. When you’re ready, tell me the symptoms (noisy, slipping, overheating, intermittent, reduced torque, drifting, encoder errors, etc.) and I’ll help you focus the tests or craft automated logging.

Quick safety checklist (do this first)

  • Power off and remove batteries before touching wiring or the drivetrain.
  • Work on a stable bench and keep small tools away from electronics.
  • Use correct voltage rated wiring and connectors; don’t short power rails.
  • If a motor or servo is working hard or hot, let it cool before touching.

Visual + mechanical inspection (fast wins)

  • Look for broken / stripped gears, cracked housings, or shredded belts.
  • Check wheel bearings and couplers for play or binding.
  • Inspect connector pins and female headers for corrosion, looseness, or bent pins.
  • Look for rubbing plastic, misaligned mounts, or screws backing out.
  • Smell for burned electronics or melted plastic - that points to overheating or shorts.

Basic electrical checks

  1. Common ground: verify EZ-B GND and Arduino GND are tied together.
  2. Battery voltage: measure battery at REST and under LOAD. Large sag -> weak battery or bad connections.
  3. Connectors: wiggle test while powered (careful) to find intermittent connections.
  4. Motor driver heat: feel or use non-contact thermometer - high temps indicate overload or failing driver.
  5. Current draw: if you have an inline current sense (or ADC + shunt), check for excessive current on startup or stall.

Use ARC to isolate components

  • Test motors/servos individually with a Script skill rather than full robot drive.
  • Use the Serial Terminal skill to confirm UART devices and responses.
  • Use the Script skill to read ADC, toggle digital outputs, and move servos one-by-one.

Small JavaScript test scripts to paste into a Script robot skill

  • Note: open the script skill settings (kebab menu) and paste into JavaScript editor. Use print() for logging.
  1. Sequential servo test (move each servo to center extremes release)
// servo test - change ports d0..d5 as needed
var servos = [d0, d1, d2, d3, d4, d5];
var delayMs = 1000;
for (var i = 0; i < servos.length; i++) {
  try {
    print("Testing servo: " + servos[i]);
    Servo.setPosition(servos[i], 90); // center
    sleep(delayMs);
    Servo.setPosition(servos[i], 30); // left
    sleep(delayMs);
    Servo.setPosition(servos[i], 150); // right
    sleep(delayMs);
    Servo.release(servos[i]);
    sleep(500);
  } catch (e) {
    print("Servo test error for " + servos[i] + ": " + e);
  }
}
print("Servo test complete.");
  1. Motor/PWM sanity test (run motor via PWM port)
// PWM motor test - substitute your motor driver PWM port (d3 etc)
var motorPort = d3;
print("PWM test start on " + motorPort);
PWM.set(motorPort, 30); // 30% duty - low to start
sleep(2000);
PWM.set(motorPort, 60);
sleep(2000);
PWM.set(motorPort, 0); // stop
print("PWM test complete");
  1. ADC battery read loop (if you have battery telemetry on an ADC pin or voltage divider)
// ADC monitoring loop - use ADC0..ADC7
var adcPort = ADC0;
for (var i = 0; i < 30; i++) {
  var v = ADC.get(adcPort);
  print("ADC " + adcPort + " raw: " + v);
  sleep(1000);
}
print("ADC battery monitor test done");

Note: If you don’t already have a dedicated ADC measure for battery, consider a resistor voltage divider to bring battery voltage into ADC range and use ADC.get() to monitor under load.

What to look for in these tests

  • Servo binds or stalls at extremes mechanical binding, stripped gears, or bad potentiometer.
  • Motor draws high current or stalls gearbox wear, overloaded drivetrain, failing motor brushes (brushed motors), or failing driver.
  • PWM works when motor disconnected from drivetrain mechanical problem.
  • ADC voltage drops dramatically when motors spin weak battery or connection; investigate battery pack and connectors.

When to replace vs repair

  • Replace stripped or missing teeth on gears, or worn belts.
  • Replace a motor if it’s noisy, has intermittent commutation, or shows dramatically reduced no-load RPM.
  • Replace connectors or crimped wires if intermittent under vibration.
  • If motor driver chips are overheating or failing, replace the driver board.

Useful links

Next steps I can help with

  • If you list exact symptoms (sounds, smells, error messages, which wheel/servo/motor), I’ll give a focused test and component isolation plan.
  • I can adapt the test scripts to continuously log diagnostics (battery under load, servo current via ADC, temp).
  • When hardware is fixed, I’ll help you continue the UART/Arduino code and the script you were adjusting earlier.

If you have photos, paste the exact text labels/markings (I can’t view images) - e.g., motor label, part numbers, or error codes. Want me to prepare an automated diagnoser script that logs battery, ADC, CPU temp, and servo positions every second so you can run it while you stress the drivetrain?


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.