Hello,
I am building a simple ROV test bed, meansing I want to control a motor and a servo using RS485 to send signals through a cable. I am sending commands from a master arduino to a slave arduino, both UNOs, using MAX485 modules (TLL to RS485, 8 pins). I am using SoftwareSerial because of issues with hardwareSerial (RX (pin 0) and TX (pin 1) not working when the rs485 module is connected to them, even preventing me from uploading code to the arduino).
My setup is working well for the most part. The motor works flawlessly and the servo is turning to the desired angles when turning a pair of potentiometer knobs on the master arduino. The only problem is that the servo is experiencing severe jitter. I have tested the servo on its own, even making it sweep independently of the potentiometer position, but as soon as the master arduino is turned on, the jitters start. I have also tried to connect the grounds of the master and slave sides, but there is no change, and the motor control works fine without that.
Hardware list:
Arduino UNO x2
MAX485 module x2
TB6612FNG motor controller
LM2596 buck converter x2
EFLR71000L digital servo
Here is the code for both arduinos as well as a wiring diagram describing the slave side. Sorry about the legibility, I’m not used to drawing diagrams. Both arduinos are powered via USB (or 7.4V lipo batteries, when not troubleshooting).
Master code:
#include <SoftwareSerial.h>
#define MASTER_EN 8 // RS485 Enable Pin
#define RX 10 // SoftwareSerial RX
#define TX 11 // SoftwareSerial TX
#define SWITCHMOTOR_PIN 4
//speed control potentiometer
int SpeedControl = A0;
int MotorSpeed = 0;
//rudder control potentiometer
int RudderControl = A1;
int RudderPos = 0;
SoftwareSerial rs485Serial(RX, TX); // Create SoftwareSerial instance
void setup() {
pinMode(SWITCHMOTOR_PIN, INPUT_PULLUP);
pinMode(MASTER_EN, OUTPUT);
rs485Serial.begin(9600);
Serial.begin(9600); // debugging
digitalWrite(MASTER_EN, LOW);
}
void loop() {
digitalWrite(MASTER_EN, HIGH); // Enable transmit mode
delay(10); // 5ms minimum delay
// foward or backward switch position and send data through rs485
if (digitalRead(SWITCHMOTOR_PIN) == 0) {
rs485Serial.print("FWD\n");
rs485Serial.flush();
delay(10); // Small buffer time
} else {
rs485Serial.print("BCK\n");
rs485Serial.flush();
delay(10);
}
rs485Serial.flush();
delay(20);
//read potentiometer for motor speed and send data through rs485
MotorSpeed = map(analogRead(SpeedControl), 0, 1023, 0 , 255);
rs485Serial.print("SPD:");
rs485Serial.println(MotorSpeed);
rs485Serial.flush(); // Wait until data is sent
delay(50);
//read potentiometer for rudder position and send data through rs485
RudderPos = map(analogRead(RudderControl), 0, 1023, 0 , 255);
rs485Serial.print("RUD:");
rs485Serial.println(RudderPos);
rs485Serial.flush(); // Wait until data is sent
delay(50);
Serial.println(digitalRead(SWITCHMOTOR_PIN)); // Debug info
Serial.println(MotorSpeed); // Debug info
Serial.println(RudderPos); // Debug info
delay(50);
digitalWrite(MASTER_EN, LOW); // Back to receive mode
delay(20); // Wait before next send
}
Slave code:
#include <SoftwareSerial.h>
#include <Servo.h>
#define SLAVE_EN 8 // RS485 Enable Pin (DE/RE)
#define RS485_RX 10 // SoftwareSerial RX
#define RS485_TX 11 // SoftwareSerial TX
SoftwareSerial rs485(RS485_RX, RS485_TX); // RX, TX
//motor
int pwmA = 5;
int in1A = 3;
int in2A = 4;
int MotorSpeed = 0;
//rudder/servo
Servo rudder;
int RudderPos = 127;
void setup() {
pinMode(SLAVE_EN, OUTPUT);
pinMode(pwmA, OUTPUT);
pinMode(in1A, OUTPUT);
pinMode(in2A, OUTPUT);
digitalWrite(SLAVE_EN, LOW); // Set to receive mode
rudder.attach(9);
rs485.begin(9600); // RS485 communication
Serial.begin(9600); // Optional: for debugging via Serial Monitor
delay(10); // 5ms minimum delay
}
void loop() {
rs485.setTimeout(10); // Set short timeout for string reads
if (rs485.available()) {
char firstChar = rs485.peek();
// If data looks like ASCII letters, assume it's a string command
if (isAlpha(firstChar)) {
String incoming = rs485.readStringUntil('\n');
if (incoming.startsWith("FWD")) {
Serial.println("Received: Forward command");
digitalWrite(in1A, HIGH);
digitalWrite(in2A, LOW);
} else if (incoming.startsWith("BCK")) {
Serial.println("Received: Backward command");
digitalWrite(in1A, LOW);
digitalWrite(in2A, HIGH);
} else if (incoming.startsWith("SPD:")) {
MotorSpeed = incoming.substring(4).toInt(); // Extract numeric value
Serial.print("MotorSpeed: ");
Serial.println(MotorSpeed);
//motor logic
if(MotorSpeed < 8)MotorSpeed=0; //prevents buzzing at very low speed
analogWrite(pwmA, MotorSpeed);
} else if (incoming.startsWith("RUD:")) {
RudderPos = incoming.substring(4).toInt(); // Extract numeric value
Serial.print("RudderPos: ");
Serial.println(RudderPos);
//rudder logic
delay(15);
//Map 0-255 to 45-135 degrees (90° total range)
int mappedRudder = map(RudderPos, 0, 255, 45, 135);
rudder.write(mappedRudder);
delay(20);
} else {
Serial.print("Unknown string: ");
Serial.println(incoming);
}
}
delay(10);
}
}
Thank you.
