Here is my project with remote control of different devices with Arduino Nano
A humorous video featuring an RC car that uses an Arduino Nano.
The Arduino code used in the first video.
#include <ModbusRTUSlave.h>
#include <Servo.h>
// ================== PIN MAPPING ==================
const uint8_t digitalPins[] = {2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13}; // Digital ping
const bool pwmPins[] = {false, true, false, true, true, false, false, true, true, true, false, false}; // PWM
const uint8_t digitalInPins[] = {A0, A1, A2, A3}; // digital
const uint8_t analogPins[] = {A0, A1, A2, A3, A4, A5, A6, A7}; // analog
Servo servos[11];
uint16_t servosDefault[] = {1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500};
// ================== STATE ARRAYS ==================
#define NUM_COILS sizeof(digitalPins)/sizeof(digitalPins[0])
#define NUM_HOLDINGS sizeof(digitalPins)/sizeof(digitalPins[0])
#define NUM_DISCRETE sizeof(digitalInPins)/sizeof(digitalInPins[0])
#define NUM_INPUTS sizeof(analogPins)/sizeof(analogPins[0])
bool coils[NUM_COILS] = {0};
uint16_t holdingRegs[NUM_HOLDINGS] = {0};
bool discreteInputs[NUM_DISCRETE] = {0};
uint16_t inputRegs[NUM_INPUTS] = {0};
// ================== MODBUS ==================
ModbusRTUSlave modbus(Serial, -1, -1);
unsigned long lastCommandTime = 0;
const unsigned long COMMAND_TIMEOUT = 1000;
// ================== SETUP ==================
void setup() {
pinMode(13, OUTPUT);
digitalWrite(13, LOW);
delay(500);
digitalWrite(13, HIGH);
Serial.begin(9600);
for(uint8_t i=0; i<NUM_COILS; i++){
if(pwmPins[i]) {
servos[i].attach(digitalPins[i]);
servos[i].writeMicroseconds(servosDefault[i]);
holdingRegs[i] = servosDefault[i];
} else {
pinMode(digitalPins[i], OUTPUT);
digitalWrite(digitalPins[i], LOW);
}
}
for(uint8_t i=0;i<NUM_DISCRETE;i++){
pinMode(digitalInPins[i], INPUT_PULLUP);
}
modbus.configureCoils(coils, NUM_COILS);
modbus.configureHoldingRegisters(holdingRegs, NUM_HOLDINGS);
modbus.configureDiscreteInputs(discreteInputs, NUM_DISCRETE);
modbus.configureInputRegisters(inputRegs, NUM_INPUTS);
// Modbus slave (ID=1, baud 9600, SERIAL_8N1)
modbus.begin(1, 9600, SERIAL_8N1);
}
// ================== LOOP ==================
void loop() {
if(true) {
modbus.poll();
//========================================
// ===== DETECT COMMAND CHANGES =====
if(false) {
bool commandReceived = false;
for (uint8_t i = 0; i < NUM_HOLDINGS; i++) {
static uint16_t prev[NUM_HOLDINGS] = {0};
if (holdingRegs[i] != prev[i]) {
prev[i] = holdingRegs[i];
commandReceived = true;
}
}
for (uint8_t i = 0; i < NUM_COILS; i++) {
static bool prevC[NUM_COILS] = {0};
if (coils[i] != prevC[i]) {
prevC[i] = coils[i];
commandReceived = true;
}
}
if (commandReceived) {
lastCommandTime = millis();
}
// ===== TIMEOUT FAILSAFE =====
if (millis() - lastCommandTime > COMMAND_TIMEOUT) {
for (uint8_t i = 0; i < NUM_HOLDINGS; i++) {
if (pwmPins[i]) {
holdingRegs[i] = servosDefault[i];
}
}
}
}
//========================================
for(uint8_t i=0;i<NUM_COILS;i++){
if(pwmPins[i]){
servos[i].writeMicroseconds(holdingRegs[i]);
} else {
digitalWrite(digitalPins[i], coils[i] ? HIGH : LOW);
}
}
for(uint8_t i=0;i<NUM_DISCRETE;i++){
discreteInputs[i] = digitalRead(digitalInPins[i]);
}
for(uint8_t i=0;i<NUM_INPUTS;i++){
inputRegs[i] = analogRead(analogPins[i]);
}
}
}
The Arduino code used in the second video.
#include <ModbusRTUSlave.h>
#include <Servo.h>
// ================== PIN MAPPING ==================
const uint8_t digitalPins[] = {2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13}; // Digital ping
const bool pwmPins[] = {false, true, false, true, true, false, false, true, true, true, false, false}; // PWM
const float pwmSmooth[] = {1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 0.1, 1.0, 0.1, 1.0, 1.0}; // smoothing
const uint8_t digitalInPins[] = {A0, A1, A2, A3}; // digital
const uint8_t analogPins[] = {A0, A1, A2, A3, A4, A5, A6, A7}; // analog
Servo servos[11];
uint16_t servosDefault[] = {1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500};
uint16_t servosShift[] = {0, 0, 0, 0, 0, 0, 0, 15, 0, 0, 0, 0};
// ================== STATE ARRAYS ==================
#define NUM_COILS sizeof(digitalPins)/sizeof(digitalPins[0])
#define NUM_HOLDINGS sizeof(digitalPins)/sizeof(digitalPins[0])
#define NUM_DISCRETE sizeof(digitalInPins)/sizeof(digitalInPins[0])
#define NUM_INPUTS sizeof(analogPins)/sizeof(analogPins[0])
bool coils[NUM_COILS] = {0};
uint16_t holdingRegs[NUM_HOLDINGS] = {0};
bool discreteInputs[NUM_DISCRETE] = {0};
uint16_t inputRegs[NUM_INPUTS] = {0};
uint16_t servoFiltered[NUM_HOLDINGS] = {0};
// ================== MODBUS ==================
ModbusRTUSlave modbus(Serial, -1, -1); // Serial, DE/RE pins (-1 if no RS-485)
unsigned long lastCommandTime = 0;
const unsigned long COMMAND_TIMEOUT = 1000;
// ================== SETUP ==================
void setup() {
pinMode(13, OUTPUT);
digitalWrite(13, LOW);
delay(500);
digitalWrite(13, HIGH);
Serial.begin(9600);
for(uint8_t i=0; i < NUM_COILS; i++){
if(pwmPins[i]) {
servos[i].attach(digitalPins[i]);
servos[i].writeMicroseconds(servosDefault[i] + servosShift[i]);
holdingRegs[i] = servosDefault[i];
} else {
pinMode(digitalPins[i], OUTPUT);
digitalWrite(digitalPins[i], LOW);
}
}
for(uint8_t i = 0; i < NUM_DISCRETE; i++){
pinMode(digitalInPins[i], INPUT_PULLUP);
}
modbus.configureCoils(coils, NUM_COILS);
modbus.configureHoldingRegisters(holdingRegs, NUM_HOLDINGS);
modbus.configureDiscreteInputs(discreteInputs, NUM_DISCRETE);
modbus.configureInputRegisters(inputRegs, NUM_INPUTS);
// Modbus slave (ID=1, baud 9600, SERIAL_8N1)
modbus.begin(1, 9600, SERIAL_8N1);
}
// ================== LOOP ==================
void loop() {
modbus.poll();
//========================================
// ===== DETECT COMMAND CHANGES =====
if(false) {
bool commandReceived = false;
for (uint8_t i = 0; i < NUM_HOLDINGS; i++) {
static uint16_t prev[NUM_HOLDINGS] = {0};
if (holdingRegs[i] != prev[i]) {
prev[i] = holdingRegs[i];
commandReceived = true;
}
}
for (uint8_t i = 0; i < NUM_COILS; i++) {
static bool prevC[NUM_COILS] = {0};
if (coils[i] != prevC[i]) {
prevC[i] = coils[i];
commandReceived = true;
}
}
if (commandReceived) {
lastCommandTime = millis();
}
// ===== TIMEOUT FAILSAFE =====
if (millis() - lastCommandTime > COMMAND_TIMEOUT) {
for (uint8_t i = 0; i < NUM_HOLDINGS; i++) {
if (pwmPins[i]) {
holdingRegs[i] = servosDefault[i];
}
}
}
}
//========================================
for(uint8_t i=0; i < NUM_COILS; i++) {
if(pwmPins[i]) {
if (servoFiltered[i] == 0) {
servoFiltered[i] = holdingRegs[i];
}
servoFiltered[i] = servoFiltered[i] * (1.0 - pwmSmooth[i]) + holdingRegs[i] * pwmSmooth[i];
servos[i].writeMicroseconds(servoFiltered[i] + servosShift[i]);
} else {
digitalWrite(digitalPins[i], coils[i] ? HIGH : LOW);
}
}
for(uint8_t i = 0; i < NUM_DISCRETE; i++) {
discreteInputs[i] = digitalRead(digitalInPins[i]);
}
for(uint8_t i=0;i<NUM_INPUTS;i++) {
inputRegs[i] = analogRead(analogPins[i]);
}
}


