The Arduino sketch in support of Roy Cheers 'An Introduction to Arduino' article as published in the May 2020 Edition of Model Boats Magazine. (See Page 59)
// Demonstration of propulsion & thruster control
// SECTION 1 ...............................................................................
#include (NB this line should have Servo.h7 added between less than and greater than sign characters which do not reproduce on the text editor used on this document.)
// Assign names and pin numbers for input from radio receiver
#define Speed_In_Pin 4 // Channel 3 throttle
#define Rudder_In_Pin 2 // Channel 1, rudder and stern thruster
#define Ch2_In_Pin 3 // Channel 2, bow thruster
Servo port_ESC; //create a servo object to control the port ESC
Servo stbd_ESC; //create a servo ojbect to contorl the stbd ESC
Servo Steer; //create a servo object to move rudder
// Define pulse durations corresponding to neutral positions
const int SpeedNeutral = 1500; // Value in mu of Neutral/Zero speed signal from receiver
const int RudderNeutral = 1500;
const int Ch2Neutral = 1500;
const int BowThrustDirPin = 11; //Define pins for outputs to devices
const int SternThrustDirPin = 12;
const int ThrusterPwrPin = 13;
const int ThrustDisable = 200; // Plus/minus change from throttle neutral over which thrusters
// are enabled.e.g if = 200, throttle signal must be between
// 1300 and 1700 for thrusters to be enabled, if neutral = 1500.
// Confirm and adjust as necessary.
const int RudderLimit = 300; //Change of rudder input from neutral below which thrusters are off
//i.e. only turned on when a tight turn is signalled
//change value to suit
boolean ThrPwrEnabled; //Is TRUE if thruster operation allowed.
boolean ThrusterPwrOn; //Is TRUE if thruster power is actually on
boolean DirnChg; //TRUE if a change in direction of the thrusters is to be made
String BowPush, SternPush; //Is "Right" if model to be pushed to the right, othewise "left"
int Mvrg_Mode; //Manoeuvring mode: 0 normal, 1 side thrust, 2 rotate
int SpeedInput, RudderInput, Ch2Input; // Values read from rc receiver
int SpdMove; //Amount speed signal has changed from neutral
int R, S; //temporary variables
// SECTION 2 ........................................................................
void setup()
{
Serial.begin(9600); //This is required for any test values you wish to display.
pinMode(BowThrustDirPin, OUTPUT); //Define pins being used for output.
pinMode(SternThrustDirPin, OUTPUT);
pinMode(ThrusterPwrPin, OUTPUT);
digitalWrite(BowThrustDirPin, LOW); //Set relays unpowered
digitalWrite(SternThrustDirPin, LOW);
digitalWrite(ThrusterPwrPin, LOW); // Set thrusters off
ThrPwrEnabled = false; //Set conditions off for thruster power
// attach servo objects to their signal pins, these will generate the correct
// pulses for driving Electronic speed controllers, & servos
// designed to interface directly with RC Receivers
port_ESC.attach(9, 1000, 2000); //attach these pins for output to ESC's
stbd_ESC.attach(10, 1000, 2000);
Steer.attach(6, 1000, 2200); //attach this pin for output to rudder servo
} // End of 'setup'.
//SECTION 3..................................................................................
void loop()
{
// Read signals from RC receiver; start timing pulse when voltage goes high
SpeedInput = pulseIn(Speed_In_Pin, HIGH);
RudderInput = pulseIn(Rudder_In_Pin, HIGH);
Ch2Input = pulseIn(Ch2_In_Pin, HIGH);
//If you want to verify the pulse durations that your receiver is sending to Arduino,
//remove the comment slashes from the code below and, with your Arduino connected to your
//computer, and your Arduino sketch open, click on 'Tools -> Serial Monitor'.
//Do not touch the control sticks on your radio and observe the readings. Ajust your trim tabs
//if you want to change the values you see.
//Then move the sticks to confirm the direction that the pulses increase.
//Remove the comment slashes from the following seven lines.
//Serial.println("Throttle Channel 2 Rudder");
//Serial.print(SpeedInput);
//Serial.print(" ");
//Serial.print(Ch2Input);
//Serial.print(" ");
//Serial.println(RudderInput);
//delay(500); //slow down execution to give time to read
//If any channel signals increase in the wrong direction, use whichever of the following statements
// apply to reverse them, by removing the '//'
// SpeedInput = 2 * SpeedNeutral - SpeedInput;
// RudderInput = 2 * RudderNeutral - SpeedInput;
// Ch2Input = 2 * Ch2Neutral - Ch2Input;
//If there is no throttle signal, or an out-of-range signal, set zero speed
if ((SpeedInput < 900) or (SpeedInput > 2100))
{
SpeedInput = SpeedNeutral;
}
// Determine manoeuvring mode; assume normal control then check to see if stick positions
// match other modes. Also assume that received signal may vary from neutral by +/-50 mu,
// with no stick movement, due to radio interference, etc.
Mvrg_Mode = 0;
if (abs(SpeedInput - SpeedNeutral) < 50) // Throttle stick in neutral
{
if (abs(RudderInput - RudderNeutral) > 50) // Rudder stick not neutral
{
Mvrg_Mode = 1; //Side thrust
}
else if (abs(Ch2Input - Ch2Neutral) > 50) // Ch 2 stick not in neutral
{
Mvrg_Mode = 2; //Rotate
}
}
// SECTION 4...........................................................................
//Assume thruster power can be switched on; but is set off if in normal control
//and either of the following apply
// Forward/astern speed is high enough that thrusters ineffective
// Turn is not tight enough to require thruster assistance
ThrPwrEnabled = true;
SpdMove = abs(SpeedInput - SpeedNeutral);
if ( Mvrg_Mode == 0 )
{
if (SpdMove > ThrustDisable || abs(RudderInput - RudderNeutral) < RudderLimit)
{
ThrPwrEnabled = false;
}
}
if (ThrPwrEnabled)
{
if (Mvrg_Mode == 1) // Sideways movement
{
if (RudderInput > RudderNeutral) //Rudder stick to right; side thrust right
{
BowPush = "Right";
SternPush = "Right";
}
else // Rudder stick to left; side thrust left
{
BowPush = "Left";
SternPush = "Left";
}
}
else if (Mvrg_Mode == 2 ) // Rotate
{
if (Ch2Input > Ch2Neutral) //Rudder stick pushed forwards; rotate CCW
{
BowPush = "Left";
SternPush = "Right";
}
else //Rudder stick pulled back; rotate CW
{
BowPush = "Right";
SternPush = "Left";
}
}
else // Must be Mvrg_Mode 0
{
if (SpeedInput - SpeedNeutral > 0) {S = +1 ;} else { S = -1;}
if (RudderInput - RudderNeutral > 0) {R = +1;} else { R = -1;}
if (S * R > 0 ) // Ahead - Turning right; Astern - turning left
{
BowPush = "Right";
SternPush = "Left";
}
else // Ahead - turning left; astern - turning right
{
BowPush = "Left";
SternPush = "Right";
}
}
// SECTION 5 ................................................................................
DirnChg = false;
if (digitalRead(SternThrustDirPin) == LOW && SternPush == "Left") //These represent opposite directions
{
DirnChg = true;
}
else if (digitalRead(SternThrustDirPin) == HIGH && SternPush == "Right") //also opposite
{
DirnChg = true;
}
if (digitalRead(BowThrustDirPin) == LOW && BowPush == "Left") //Also opposite directions
{
DirnChg = true;
}
else if (digitalRead(BowThrustDirPin) == HIGH && BowPush == "Right") //also opposite
{
DirnChg = true;
}
if (DirnChg == true || ThrusterPwrOn == false) //If direction change reqd OR thruster power off
{
if (ThrusterPwrOn == true)
{
digitalWrite(ThrusterPwrPin, LOW); //Switch off power to thrusters
delay(10); //Pause 10ms for kickback voltage to dissipate
}
if (BowPush == "Right")
{
digitalWrite(BowThrustDirPin, LOW); //Bow Thruster pushes model right
}
else
{
digitalWrite(BowThrustDirPin, HIGH); //Bow Thruster pushes model left
}
if (SternPush == "Right")
{
digitalWrite(SternThrustDirPin, LOW); //Stern Thruster pushes model right
}
else
{
digitalWrite(SternThrustDirPin, HIGH); //Stern Thruster pushes model left
}
digitalWrite(ThrusterPwrPin, HIGH); //Switch on power to thrusters
ThrusterPwrOn = true;
}
}
else
{
digitalWrite(ThrusterPwrPin, LOW); // Thrusters off
ThrusterPwrOn = false;
}
//Removing the comment slashes from the following lines will display the information.
//You may find this useful for testing, or just to check what's going on.
//Serial.println("Man'vrg Mode Thr Pwr? Bow Stern Rudder Inp");
//Serial.print(Mvrg_Mode);
//Serial.print(" ");
//if (ThrPwrEnabled) {Serial.print("ON ");} else {Serial.print("off ");}
//Serial.print(BowPush);
//Serial.print(" ");
//Serial.print(SternPush);
//Serial.print(" ");
//Serial.println(RudderInput);
//Serial.println();
//delay(400);
if (Mvrg_Mode == 0)
{
port_ESC.writeMicroseconds(SpeedInput); //send signal to ESC's
stbd_ESC.writeMicroseconds(SpeedInput);
Steer.writeMicroseconds(RudderInput); // send signal to rudder servo
}
} //End of 'loop'
Want the latest issue of Model Boats? Use our magazine locator link to find your nearest stockist!
Make sure you never miss out on the latest news, product reviews and competitions with our free RSS feed
We welcome well written contributions from Website members on almost any aspect of Model Boating with a particular emphasis on practical hints, tips, experience and builds.
In order to maintain a consistent standard and format, all suggestions should first be sent to me by Personal Message for approval in principle. Only a very limited amount of time is available for editing contributions into a suitable format for placing on the website so it is important that the material is well presented, lucid and free from obvious spelling errors. I think it goes without saying that contributions should be illustrated by appropriate photos. I shall be happy to give advice on this.
The Member Contribution area offers space for short informative mini articles which would not normally find a place in Model Boats magazine. It is an opportunity for Website Members to freely share their expertise and experience but I am afraid that virtue is its own reward as there is no budget to offer more material recompense!
I look forward to receiving your suggestions.
Colin Bishop - Website Editor