Arduino Code for Basic Train Control Tethered

Here is the code used in the first video showing the tethered locomotive moving back and forth. The analog speed input is disabled and instead a direction variable tells the motor to switch directions every few seconds.

 

// PWM Motor controller with direction control via
// input potentiometer
//
// (C) 2014 zapmaker
//
// Apache 2.0 License
//
const int analogIn0Pin = 0;
const int ledPin = 13;
const int interruptNumber = 0;// usually connects to pin 2
const int pwmPin = 3;
const int dir1Pin = 4;
const int dir2Pin = 5;

volatile int state = LOW;
volatile int lastTime = 0;

int last = 0;
int motorTime = 0;
int serialTime = 0;
int delta = 0;
int pwmOut = 0;
int lastDir1 = 0;
int lastDir2 = 0;
float detectedSpeed = 0;
boolean useBrakingOnReversal = false;
int lastswaptime = 0;
#define SVAL 390
int dirX = SVAL;
#define SDELT 3000

#define BUFSIZE 200
char buf[BUFSIZE];

void setup()
{
  Serial.begin(9600);
  //
  pinMode(ledPin, OUTPUT);
  attachInterrupt(interruptNumber, blink, RISING);
  digitalWrite(pwmPin, pwmOut);
  pinMode(pwmPin, OUTPUT);
  digitalWrite(dir1Pin, lastDir1);
  pinMode(dir1Pin, OUTPUT);
  digitalWrite(dir2Pin, lastDir2);
  pinMode(dir2Pin, OUTPUT);
}

void loop()
{
  int curr = millis();
  if (last != lastTime) {
    int tmp = lastTime - last;
    if (tmp > 30) {
      delta = tmp;
    }
    last = lastTime;
  }
  else if ((curr - lastTime) > 3000) {
    delta = 0;
  }  

  if ((curr - motorTime) > 100) {
    //int a = analogRead(analogIn0Pin);
    int a = dirX;
    a /= 4;
    // split the potentiometer in half, incrementing
    // the speed in opposite motor direction from the
    // middle of the pot
    if (a <= 127) {
      // bottom half of pot
      if (lastDir1 == 0 && lastDir2 == 1) {
        // reversal occurred, stop motor to protect 
        // motor and controller
        stop();
        // ensure no pwm signal, just dc
        a = 255;
      }
      else {
        // change direction
        lastDir1 = 1;
        lastDir2 = 0;
        a = (127 - a) * 2;
      }
    }
    else {
      // top half of pot
      if (lastDir1 == 1 && lastDir2 == 0) {
        // reversal occurred, stop motor to protect 
        // motor and controller
        stop();
        // ensure no pwm signal, just dc
        a = 255;
      }
      else {
        // change direction
        lastDir1 = 0;
        lastDir2 = 1;
        a = (a - 128) * 2;
      }
    }

    // motor direction
    digitalWrite(dir1Pin, lastDir1);
    digitalWrite(dir2Pin, lastDir2);

    pwmOut = a;
    // pwm 'speed'
    analogWrite(pwmPin, pwmOut);

    float d = delta;
    detectedSpeed = 0;
    if (d > 0)
      detectedSpeed = 10000 / d;

    motorTime = curr;
  } 

  if ((curr - lastswaptime) > SDELT) {
    if (dirX < 512)
      dirX = 512 + SVAL;
    else
      dirX = 512 - SVAL;

    lastswaptime = curr;
  }

  if ((curr - serialTime) > 1000) {  
    String msg = "L1: ";
    msg += lastDir1;
    msg += " L2: ";
    msg += lastDir2;
    msg += " A: ";
    msg += pwmOut;
    msg += "\n";
    msg.toCharArray(buf, BUFSIZE); 
    Serial.write(buf);

    msg = "Pulse Time: ";
    msg += delta;
    msg += " Speed: ";
    msg += (int)detectedSpeed;
    msg += "\n";
    msg.toCharArray(buf, BUFSIZE); 
    Serial.write(buf);

    serialTime = curr;   
  }
  digitalWrite(ledPin, state);
}

void stop()
{
  // decide if we are braking on stop or
  // letting motor coast 
  if (useBrakingOnReversal) {
    lastDir1 = 0;
    lastDir2 = 0;
  }
  else {
    lastDir1 = 1;
    lastDir2 = 1;
  }
}

void blink()
{
  lastTime = millis();

  state = !state;
}

Leave a Reply

Your email address will not be published. Required fields are marked *

*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>