
Extra Hardware Serial + JSON servo control
2025.09.22 23:05
It gets message from Orange Pi 5 via UART in JSON format.
Then, it control 3 servos.
The connection setting is as this :

======== ESP32-S3 Code ==========
#include <ESP32Servo.h>
#include <ArduinoJson.h>
#include <HardwareSerial.h>
// Define the UART pins for the Orange Pi 5 (Communication Bus)
#define COMM_RX_PIN 11
#define COMM_TX_PIN 10
// Define the UART pins for the LiDAR (Data Bus)
#define LIDAR_RX_PIN 13
#define LIDAR_TX_PIN 12
// Servo pin definitions
const int servoPinRW = 5;
const int servoPinLW = 6;
const int servoPinLidar = 7;
// Servo objects
Servo servoRW;
Servo servoLW;
Servo servoLidar;
// Custom neutral points
const int leftServoNeutralPoint = 1480;
const int rightServoNeutralPoint = 1500;
// HardwareSerial instances
HardwareSerial myCommSerial(1); // For Orange Pi 5
HardwareSerial myLidarSerial(2); // For LiDAR
// Define the safe movement range for the LiDAR servo
const int LidarMinAngle = 20; // Tilts to the floor (front)
const int LidarMaxAngle = 110; // Tilts backward. (Do not go over this)
void setServoSpeeds(int leftSpeed, int rightSpeed, int lidarAngle) {
// --- WHEEL SERVO LOGIC ---
int leftPWM = map(leftSpeed, -100, 100, 1200, 1760);
int rightPWM = map(rightSpeed, -100, 100, 1240, 1760);
servoLW.writeMicroseconds(leftPWM);
servoRW.writeMicroseconds(rightPWM);
// --- LIDAR SERVO SAFEGUARD ---
int safeLidarAngle = constrain(lidarAngle, LidarMinAngle, LidarMaxAngle);
int lidarPWM = map(safeLidarAngle, 0, 180, 2500, 500);
servoLidar.writeMicroseconds(lidarPWM);
// Print the values for debugging
Serial.print("Left Speed: ");
Serial.print(leftSpeed);
Serial.print(" | Right Speed: ");
Serial.print(rightSpeed);
Serial.print(" | Lidar Angle: ");
Serial.println(safeLidarAngle);
}
void setup() {
Serial.begin(115200);
// Initialize communication with Orange Pi 5
myCommSerial.begin(115200, SERIAL_8N1, COMM_RX_PIN, COMM_TX_PIN);
// Initialize communication with LiDAR
myLidarSerial.begin(115200, SERIAL_8N1, LIDAR_RX_PIN, LIDAR_TX_PIN);
servoRW.attach(servoPinRW);
servoLW.attach(servoPinLW);
servoLidar.attach(servoPinLidar);
Serial.println("ESP32-S3 ready. Waiting for commands from Orange Pi 5...");
}
void loop() {
// Check for commands from the Orange Pi 5
if (myCommSerial.available()) {
String jsonString = myCommSerial.readStringUntil('\n');
DynamicJsonDocument doc(200);
DeserializationError error = deserializeJson(doc, jsonString);
if (error) {
Serial.print(F("deserializeJson() failed: "));
Serial.println(error.f_str());
return;
}
int leftSpeed = doc["leftSpeed"];
int rightSpeed = doc["rightSpeed"];
int lidarAngle = doc["lidarAngle"];
setServoSpeeds(leftSpeed, rightSpeed, lidarAngle);
}
}
// Custom map function
long map(long x, long in_min, long in_max, long out_min, long out_max) {
return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
}
============ Python Code from Orange Pi 5 ==============
import serial
import time
import json
# Configure the serial port and baud rate
# Make sure the baud rate (115200) matches what you set in the ESP32 code.
serial_port = serial.Serial('/dev/ttyS0', 115200)
print("Robot Controller Starting...")
def send_command(left_speed, right_speed, lidar_angle):
"""
Sends a JSON command to the ESP32-S3 over the serial port.
"""
command = {
"leftSpeed": left_speed,
"rightSpeed": right_speed,
"lidarAngle": lidar_angle
}
# Convert the dictionary to a JSON string
json_string = json.dumps(command)
# Add a newline character to signify the end of the command
message = json_string + "\n"
print(f"Sending: {message.strip()}")
# Encode the message and send it over the serial port
serial_port.write(message.encode('utf-8'))
try:
while True:
# --- TEST 1: Forward Arc Turn ---
print("Commanding a right arc turn...")
send_command(50, 25, 100)
time.sleep(4) # Run for 4 seconds
# --- TEST 2: Stop ---
print("Commanding a full stop...")
send_command(0, 0, 90)
time.sleep(2) # Wait for 2 seconds
# --- TEST 3: Backward Arc Turn ---
print("Commanding a left backward arc turn...")
send_command(-25, -50, 30) # 30 for lidar will make it 100% forward.
time.sleep(4) # Run for 4 seconds
# --- TEST 4: Stop ---
print("Commanding a full stop...")
send_command(0, 0, 90)
time.sleep(5) # Wait for 2 seconds
except KeyboardInterrupt:
print("Communication stopped by user.")
finally:
# Close the serial port when finished
serial_port.close()
print("Serial port closed.")
=============================================================
Comment 0
| No. | Subject | Author | Date | Views |
|---|---|---|---|---|
| Notice | For the first time user of ESP32-S3 super mini users. | me | 2025.04.25 | 806 |
| 16 | Other Approach proposed by Gemini | me | 2025.10.02 | 96 |
| 15 | Data Route | me | 2025.10.02 | 100 |
| » |
Extra Hardware Serial + JSON servo control
| me | 2025.09.22 | 139 |
| 13 |
Wheel Arc movement with continous servos
| me | 2025.09.21 | 154 |
| 12 |
3 Servo Test
| me | 2025.09.21 | 131 |
| 11 |
Object Pascal App getting data from ESP32-S3 (Parsing)
| me | 2025.04.29 | 592 |
| 10 |
Sound Sensor Test
| me | 2025.04.27 | 603 |
| 9 |
Laser distance sensor VL53L0X
| me | 2025.04.27 | 626 |
| 8 |
9DOF : Getting Pitch & Roll with ICM20948 v2
| me | 2025.04.27 | 604 |
| 7 |
Formating output
| me | 2025.04.27 | 592 |
| 6 | Blinking Built-in RGB without delay() | me | 2025.04.25 | 3802 |
| 5 | Built-in RGB led Demo | me | 2025.04.25 | 683 |
| 4 | Servo Demo | me | 2025.04.25 | 585 |
| 3 |
HMC5883L Compass demo
| me | 2025.04.25 | 648 |
| 2 |
I2C Address Search
| me | 2025.04.25 | 632 |
| 1 |
Serial Sample (ASCII Table)
| me | 2025.04.25 | 673 |