Ardunio Sketch by Roy Cheers

by

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'


Advert

Enjoy more Model Boats Magazine reading every month. Click here to subscribe.


Article Tags:

About the Author