HO Scale Model Train Controller


#include 

#include 

/* 
 * Now we create a new LedControl. 
 * We use pins 12,11 and 10 on the Arduino for the SPI interface
 * Pin 12 is connected to the DATA IN-pin of the first MAX7221
 * Pin 11 is connected to the CLK-pin of the first MAX7221
 * Pin 10 is connected to the LOAD(/CS)-pin of the first MAX7221   
 * There will only be a single MAX7221 attached to the arduino 
 */

//Pin definitions

const int LED_WHITE=13;
const int LED_YELLOW=A0;
const int LED_GREEN=A1;

const int LED_CLOCK=7;  //white
const int LED_CS=6;     //black
const int LED_DIN=5;    //purple

const int DETECT_ON_SWITCH=3;
const int MOTION_DETECT=2;
const int SPEED_POT=A2;
const int LASER_DETECT=A3;

int _maxSpeed=0;
int _curSpeed=0;

int _targetSpeed=0;
bool _changingSpeed=false;

bool _accelerate=false;
bool _declerate=false;

unsigned long _lastOnTime;
const long RUN_TIME=50000;
const int STALL_SPEED=2;

bool _detectOff=false;
bool _blink=false;

LedControl _lc1=LedControl(LED_DIN,LED_CLOCK,LED_CS,1);

AF_DCMotor _motor(1, MOTOR12_1KHZ);

/* CharData is a two dimensional constant array that holds the 8-bit column values of
   individual rows for ASCII characters that are to be displayed on a 8x8 matrix format.
*/
const unsigned short _CharData[][8] ={
  //{0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000}, 
  //{0b00000100, 0b00000100, 0b00000100, 0b00000100, 0b00000100, 0b00000100, 0b00000000, 0b00000100}, 
  //{0b00001010, 0b00001010, 0b00001010, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000}, 
  //{0b00000000, 0b00001010, 0b00011111, 0b00001010, 0b00011111, 0b00001010, 0b00011111, 0b00001010}, 
  //{0b00000111, 0b00001100, 0b00010100, 0b00001100, 0b00000110, 0b00000101, 0b00000110, 0b00011100}, 
  //{0b00011001, 0b00011010, 0b00000010, 0b00000100, 0b00000100, 0b00001000, 0b00001011, 0b00010011}, 
  //{0b00000110, 0b00001010, 0b00010010, 0b00010100, 0b00001001, 0b00010110, 0b00010110, 0b00001001}, 
  //{0b00000100, 0b00000100, 0b00000100, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000}, 
  //{0b00000010, 0b00000100, 0b00001000, 0b00001000, 0b00001000, 0b00001000, 0b00000100, 0b00000010}, 
  //{0b00001000, 0b00000100, 0b00000010, 0b00000010, 0b00000010, 0b00000010, 0b00000100, 0b00001000}, 
  //{0b00010101, 0b00001110, 0b00011111, 0b00001110, 0b00010101, 0b00000000, 0b00000000, 0b00000000}, 
  //{0b00000000, 0b00000000, 0b00000100, 0b00000100, 0b00011111, 0b00000100, 0b00000100, 0b00000000},
  //{0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000110, 0b00000100, 0b00001000},
  //{0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00001110, 0b00000000, 0b00000000, 0b00000000},
  //{0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000100},
  //{0b00000001, 0b00000010, 0b00000010, 0b00000100, 0b00000100, 0b00001000, 0b00001000, 0b00010000}, 
  {0b00001110, 0b00010001, 0b00010011, 0b00010001, 0b00010101, 0b00010001, 0b00011001, 0b00001110}, //0
  {0b00000100, 0b00001100, 0b00010100, 0b00000100, 0b00000100, 0b00000100, 0b00000100, 0b00011111}, //1
  {0b00001110, 0b00010001, 0b00010001, 0b00000010, 0b00000100, 0b00001000, 0b00010000, 0b00011111}, //2
  {0b00001110, 0b00010001, 0b00000001, 0b00001110, 0b00000001, 0b00000001, 0b00010001, 0b00001110}, //3
  {0b00010000, 0b00010000, 0b00010100, 0b00010100, 0b00011111, 0b00000100, 0b00000100, 0b00000100}, //4
  {0b00011111, 0b00010000, 0b00010000, 0b00011110, 0b00000001, 0b00000001, 0b00000001, 0b00011110}, //5
  {0b00000111, 0b00001000, 0b00010000, 0b00011110, 0b00010001, 0b00010001, 0b00010001, 0b00001110}, //6
  {0b00011111, 0b00000001, 0b00000001, 0b00000001, 0b00000010, 0b00000100, 0b00001000, 0b00010000}, //7
  {0b00001110, 0b00010001, 0b00010001, 0b00001110, 0b00010001, 0b00010001, 0b00010001, 0b00001110}, //8
  {0b00001110, 0b00010001, 0b00010001, 0b00001111, 0b00000001, 0b00000001, 0b00000001, 0b00000001}, //9
 // {0b00000000, 0b00000100, 0b00000100, 0b00000000, 0b00000000, 0b00000100, 0b00000100, 0b00000000},
//  {0b00000000, 0b00000100, 0b00000100, 0b00000000, 0b00000000, 0b00000100, 0b00000100, 0b00001000},
//  {0b00000001, 0b00000010, 0b00000100, 0b00001000, 0b00001000, 0b00000100, 0b00000010, 0b00000001},
//  {0b00000000, 0b00000000, 0b00000000, 0b00011110, 0b00000000, 0b00011110, 0b00000000, 0b00000000},
//  {0b00010000, 0b00001000, 0b00000100, 0b00000010, 0b00000010, 0b00000100, 0b00001000, 0b00010000},
//  {0b00001110, 0b00010001, 0b00010001, 0b00000010, 0b00000100, 0b00000100, 0b00000000, 0b00000100},
//  {0b00001110, 0b00010001, 0b00010001, 0b00010101, 0b00010101, 0b00010001, 0b00010001, 0b00011110},
//  {0b00001110, 0b00010001, 0b00010001, 0b00010001, 0b00011111, 0b00010001, 0b00010001, 0b00010001},
//  {0b00011110, 0b00010001, 0b00010001, 0b00011110, 0b00010001, 0b00010001, 0b00010001, 0b00011110},
//  {0b00000111, 0b00001000, 0b00010000, 0b00010000, 0b00010000, 0b00010000, 0b00001000, 0b00000111},
//  {0b00011100, 0b00010010, 0b00010001, 0b00010001, 0b00010001, 0b00010001, 0b00010010, 0b00011100},
//  {0b00011111, 0b00010000, 0b00010000, 0b00011110, 0b00010000, 0b00010000, 0b00010000, 0b00011111},
//  {0b00011111, 0b00010000, 0b00010000, 0b00011110, 0b00010000, 0b00010000, 0b00010000, 0b00010000},
//  {0b00001110, 0b00010001, 0b00010000, 0b00010000, 0b00010111, 0b00010001, 0b00010001, 0b00001110},
//  {0b00010001, 0b00010001, 0b00010001, 0b00011111, 0b00010001, 0b00010001, 0b00010001, 0b00010001},
//  {0b00011111, 0b00000100, 0b00000100, 0b00000100, 0b00000100, 0b00000100, 0b00000100, 0b00011111},
//  {0b00011111, 0b00000100, 0b00000100, 0b00000100, 0b00000100, 0b00000100, 0b00010100, 0b00001000},
//  {0b00010001, 0b00010010, 0b00010100, 0b00011000, 0b00010100, 0b00010010, 0b00010001, 0b00010001},
//  {0b00010000, 0b00010000, 0b00010000, 0b00010000, 0b00010000, 0b00010000, 0b00010000, 0b00011111},
//  {0b00010001, 0b00011011, 0b00011111, 0b00010101, 0b00010001, 0b00010001, 0b00010001, 0b00010001},
//  {0b00010001, 0b00011001, 0b00011001, 0b00010101, 0b00010101, 0b00010011, 0b00010011, 0b00010001},
//  {0b00001110, 0b00010001, 0b00010001, 0b00010001, 0b00010001, 0b00010001, 0b00010001, 0b00001110},
//  {0b00011110, 0b00010001, 0b00010001, 0b00011110, 0b00010000, 0b00010000, 0b00010000, 0b00010000},
//  {0b00001110, 0b00010001, 0b00010001, 0b00010001, 0b00010001, 0b00010101, 0b00010011, 0b00001111},
//  {0b00011110, 0b00010001, 0b00010001, 0b00011110, 0b00010100, 0b00010010, 0b00010001, 0b00010001},
//  {0b00001110, 0b00010001, 0b00010000, 0b00001000, 0b00000110, 0b00000001, 0b00010001, 0b00001110},
//  {0b00011111, 0b00000100, 0b00000100, 0b00000100, 0b00000100, 0b00000100, 0b00000100, 0b00000100},
//  {0b00010001, 0b00010001, 0b00010001, 0b00010001, 0b00010001, 0b00010001, 0b00010001, 0b00001110},
//  {0b00010001, 0b00010001, 0b00010001, 0b00010001, 0b00010001, 0b00010001, 0b00001010, 0b00000100},
//  {0b00010001, 0b00010001, 0b00010001, 0b00010001, 0b00010001, 0b00010101, 0b00010101, 0b00001010},
//  {0b00010001, 0b00010001, 0b00001010, 0b00000100, 0b00000100, 0b00001010, 0b00010001, 0b00010001},
//  {0b00010001, 0b00010001, 0b00001010, 0b00000100, 0b00000100, 0b00000100, 0b00000100, 0b00000100},
//  {0b00011111, 0b00000001, 0b00000010, 0b00000100, 0b00001000, 0b00010000, 0b00010000, 0b00011111},
//  {0b00001110, 0b00001000, 0b00001000, 0b00001000, 0b00001000, 0b00001000, 0b00001000, 0b00001110},
//  {0b00010000, 0b00001000, 0b00001000, 0b00000100, 0b00000100, 0b00000010, 0b00000010, 0b00000001},
//  {0b00001110, 0b00000010, 0b00000010, 0b00000010, 0b00000010, 0b00000010, 0b00000010, 0b00001110},
//  {0b00000100, 0b00001010, 0b00010001, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000},
//  {0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00011111},
//  {0b00001000, 0b00000100, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000},
//  {0b00000000, 0b00000000, 0b00000000, 0b00001110, 0b00010010, 0b00010010, 0b00010010, 0b00001111},
//  {0b00000000, 0b00010000, 0b00010000, 0b00010000, 0b00011100, 0b00010010, 0b00010010, 0b00011100},
//  {0b00000000, 0b00000000, 0b00000000, 0b00001110, 0b00010000, 0b00010000, 0b00010000, 0b00001110},
//  {0b00000000, 0b00000001, 0b00000001, 0b00000001, 0b00000111, 0b00001001, 0b00001001, 0b00000111},
//  {0b00000000, 0b00000000, 0b00000000, 0b00011100, 0b00010010, 0b00011110, 0b00010000, 0b00001110},
//  {0b00000000, 0b00000011, 0b00000100, 0b00000100, 0b00000110, 0b00000100, 0b00000100, 0b00000100},
//  {0b00000000, 0b00001110, 0b00001010, 0b00001010, 0b00001110, 0b00000010, 0b00000010, 0b00001100},
//  {0b00000000, 0b00010000, 0b00010000, 0b00010000, 0b00011100, 0b00010010, 0b00010010, 0b00010010},
//  {0b00000000, 0b00000000, 0b00000100, 0b00000000, 0b00000100, 0b00000100, 0b00000100, 0b00000100},
//  {0b00000000, 0b00000010, 0b00000000, 0b00000010, 0b00000010, 0b00000010, 0b00000010, 0b00001100},
//  {0b00000000, 0b00010000, 0b00010000, 0b00010100, 0b00011000, 0b00011000, 0b00010100, 0b00010000},
//  {0b00000000, 0b00010000, 0b00010000, 0b00010000, 0b00010000, 0b00010000, 0b00010000, 0b00001100},
//  {0b00000000, 0b00000000, 0b00000000, 0b00001010, 0b00010101, 0b00010001, 0b00010001, 0b00010001},
//  {0b00000000, 0b00000000, 0b00000000, 0b00010100, 0b00011010, 0b00010010, 0b00010010, 0b00010010},
//  {0b00000000, 0b00000000, 0b00000000, 0b00001100, 0b00010010, 0b00010010, 0b00010010, 0b00001100},
//  {0b00000000, 0b00011100, 0b00010010, 0b00010010, 0b00011100, 0b00010000, 0b00010000, 0b00010000},
//  {0b00000000, 0b00001110, 0b00010010, 0b00010010, 0b00001110, 0b00000010, 0b00000010, 0b00000001},
//  {0b00000000, 0b00000000, 0b00000000, 0b00001010, 0b00001100, 0b00001000, 0b00001000, 0b00001000},
//  {0b00000000, 0b00000000, 0b00001110, 0b00010000, 0b00001000, 0b00000100, 0b00000010, 0b00011110},
//  {0b00000000, 0b00010000, 0b00010000, 0b00011100, 0b00010000, 0b00010000, 0b00010000, 0b00001100},
//  {0b00000000, 0b00000000, 0b00000000, 0b00010010, 0b00010010, 0b00010010, 0b00010010, 0b00001100},
//  {0b00000000, 0b00000000, 0b00000000, 0b00010001, 0b00010001, 0b00010001, 0b00001010, 0b00000100},
//  {0b00000000, 0b00000000, 0b00000000, 0b00010001, 0b00010001, 0b00010001, 0b00010101, 0b00001010},
//  {0b00000000, 0b00000000, 0b00000000, 0b00010001, 0b00001010, 0b00000100, 0b00001010, 0b00010001},
//  {0b00000000, 0b00000000, 0b00010001, 0b00001010, 0b00000100, 0b00001000, 0b00001000, 0b00010000},
//  {0b00000000, 0b00000000, 0b00000000, 0b00011111, 0b00000010, 0b00000100, 0b00001000, 0b00011111},
//  {0b00000010, 0b00000100, 0b00000100, 0b00000100, 0b00001000, 0b00000100, 0b00000100, 0b00000010},
//  {0b00000100, 0b00000100, 0b00000100, 0b00000100, 0b00000100, 0b00000100, 0b00000100, 0b00000100},
//  {0b00001000, 0b00000100, 0b00000100, 0b00000100, 0b00000010, 0b00000100, 0b00000100, 0b00001000},
  {0b00000000, 0b00000000, 0b00000000, 0b00001010, 0b00011110, 0b00010100, 0b00000000, 0b00000000}
};

void setup() {
  //Initiate Serial communication.
  Serial.begin(9600);

  // put your setup code here, to run once:
  pinMode(LED_DIN,OUTPUT); 
  pinMode(LED_CLOCK,OUTPUT); 
  pinMode(LED_CS,OUTPUT); 

  pinMode(LED_WHITE,OUTPUT);
  pinMode(LED_YELLOW,OUTPUT);
  pinMode(LED_GREEN,OUTPUT);

  pinMode(DETECT_ON_SWITCH,INPUT);
  pinMode(MOTION_DETECT,INPUT);
  pinMode(SPEED_POT,INPUT);
  pinMode(LASER_DETECT,INPUT);

_motor.setSpeed(255);
  _motor.run(FORWARD);

}

/*
 * If the human dectector is activated, we want the train to slowly accelerate to the set max speed.
 * If the designated time goes by with the human detector not activated, we want to slowly decelerate to 2 (if max speed > 2)
 * If designated time has gone by and speed is at 2, and laser is activated then train should immediately stop.
 * 
 */
void loop() {
  // clear max speed led, as we want it to flash
  _lc1.shutdown(0,false);
  _lc1.setIntensity(0,8);
  _lc1.clearDisplay(0);

  delay(1000);

  //read and set max speed led
  SetMaxSpeed();

  //run switch bypasses human detector. If run switch is on, train should run at max speed until manually turned off.
  bool runSwitchOn=RunSwitchOn();
  
  if (runSwitchOn)
  {
    _targetSpeed=_maxSpeed;

    if (_curSpeed<_maxSpeed) { _accelerate=true; _declerate=false; _changingSpeed=true; } else if (_curSpeed>_maxSpeed)
    {
      _declerate=true;
      _accelerate=false;
      _changingSpeed=true;
    }
    else
    {
      _declerate=false;
      _accelerate=false;
      _changingSpeed=false;
    }
  }
  else
  {
    bool humanDetected=HumanDetected();
    bool laserActivated=LaserActivated();
    bool timeoutExpired=(millis()-_lastOnTime)>RUN_TIME;

    if (humanDetected)
    {
      _lastOnTime=millis();
      if (_curSpeed<_maxSpeed) { _accelerate=true; _declerate=false; _changingSpeed=true; } else if (_curSpeed>_maxSpeed)
        {
          _declerate=true;
          _accelerate=false;
          _changingSpeed=true;
        }
        else
        {
          _declerate=false;
          _accelerate=false;
          _changingSpeed=false;
        }      
    }
    else if (timeoutExpired)
    {
        if (_curSpeed>STALL_SPEED)
        {
          _declerate=true;
          _accelerate=false;
          _changingSpeed=true;
        } else if (laserActivated)
          {
            _curSpeed=0;
            _declerate=false;
            _accelerate=false;
            _changingSpeed=false;
          }
          else
          {
            _declerate=false;
            _accelerate=false;
            _changingSpeed=false;
          }      
    }  
  } 

  if (_changingSpeed)
  {
    if (_accelerate)
    {
      //speed up
      _curSpeed++;
      if (_curSpeed>_maxSpeed) _curSpeed=_maxSpeed;
            
    }
    else if (_declerate)
    {
      //slow down
      _curSpeed--;
      if (_curSpeed<STALL_SPEED) _curSpeed=STALL_SPEED; } if (_curSpeed>0)
      {
          StartMotor(_curSpeed);
          _motor.run(FORWARD);
          Serial.println("motor on");
          digitalWrite(LED_GREEN,HIGH);
      }
  }
  else if (_curSpeed==0)
      {
        _motor.run(RELEASE);
        Serial.println("motor off");
        digitalWrite(LED_GREEN,LOW);
      }
      
  ShowUI();
    
  delay(1000);    
}

void ShowUI()
{
  ShowNumber(_curSpeed);

  if (_detectOff)
  {
    if (_blink)
    {
      digitalWrite(LED_WHITE,LOW);
      digitalWrite(LED_YELLOW,LOW);
      digitalWrite(LED_GREEN,LOW);      
    }
    else
    {
      digitalWrite(LED_WHITE,HIGH);
      digitalWrite(LED_YELLOW,HIGH);
      digitalWrite(LED_GREEN,HIGH);         
    }
    _blink=!_blink;
  }  
}

void SetMaxSpeed()
{
  int potval=analogRead(SPEED_POT);
  
  if (potval>931)
    _maxSpeed=0;
  else if (potval>814)
    _maxSpeed=1;
  else if (potval>690)
    _maxSpeed=2;
  else if (potval>616)
    _maxSpeed=3;
  else if (potval>364)
    _maxSpeed=4;
  else if (potval>249)
    _maxSpeed=5;
  else if (potval>126)
    _maxSpeed=6;
  else if (potval>51)
    _maxSpeed=7;
  else if (potval>5)
    _maxSpeed=8;
  else
    _maxSpeed=9;
}

bool RunSwitchOn()
{
  bool runSwitchActivated=false;

  int sensorEnable=digitalRead(DETECT_ON_SWITCH);
  if(sensorEnable==1)
  {
    Serial.println("detect off switch activated");
    
    runSwitchActivated=true;
  }
  
  return runSwitchActivated;
}

bool HumanDetected()
{
  bool detectOn=false;

  _detectOff=false;
  
  Serial.println("detect on switch not activated");
  
  digitalWrite(LED_WHITE,LOW);

  int motionDetect=digitalRead(MOTION_DETECT);
  if (motionDetect>0)
  {
    //motion detected.
    Serial.println("motion detected");
    digitalWrite(LED_WHITE,HIGH);
    detectOn=true;
  }

  return detectOn;
}

bool LaserActivated()
{ 
  bool laserActivated=false;
  
  int laserVal = analogRead(LASER_DETECT);     // read the input pin
  if (laserVal<600) { //Laser sees something laserActivated=true; digitalWrite(LED_YELLOW,HIGH); Serial.print("laser detected "); Serial.println(laserVal); } else { digitalWrite(LED_YELLOW,LOW); Serial.print("laser not activated "); Serial.println(laserVal); } return laserActivated; } void StartMotor(byte index) { switch(index) { case 0: _motor.setSpeed(0); break; case 1: _motor.setSpeed(85); break; case 2: _motor.setSpeed(106); break; case 3: _motor.setSpeed(127); break; case 4: _motor.setSpeed(148); break; case 5: _motor.setSpeed(170); break; case 6: _motor.setSpeed(191); break; case 7: _motor.setSpeed(212); break; case 8: _motor.setSpeed(233); break; case 9: _motor.setSpeed(255); break; default: _motor.setSpeed(0); break; } Serial.print("set speed "); Serial.println(index); } void ShowNumber(byte val) { if (val>=0 && val<=9)
    for (byte row=0;row<8;row++)
      _lc1.setRow(0,row,_CharData[val][row]<<2);
  else
    //unrecognized character
    for (byte row=0;row<8;row++)
      _lc1.setRow(0,row,_CharData[10][row]<<2);      
}