Train Stop Project

Posted by | December 10, 2008 | ITP, Physical Computing | No Comments

What?

I worked on this project with Tim Haynes.

The goal of this project was to build a device that lets you know when your train stop is coming up.

Look!

It all started with the thought that when you’re coming home late, and you’re tired or drunk or both, you can sometimes miss your trainstop. Or if you’re reading a good book or watching a movie or even just having a nap. So, what if you had a device that could A) alert you that your stop was coming up and B) let you know that your stop was here.


How?

Enter… The Device
Right now it’s a simple box with very basic inputs and outputs.

  • You turn on the Device. By default, its set to two train stops, because why would you need something like this for only one stop?
  • You increment the number of stops by pushing a red on the side. This is also useful in the case of false stop detection.
  • When you reach the stop before your stop, a yellow light goes on and stays on until…
  • You near your stop where a red light comes on and a buzzer/vibrator goes off.

Do It Yourself

So the setup is pretty simple and the materials are cheap/easy to come by.

  • Arduino (or some other microcontroller thingy)
  • 2 LEDs
  • 1 (or more) (we used a piezo) Buzzer/vibrating motor/loud-annoying-wake-me-up-thing
  • 1 accelerometer
  • 1 pushbutton switch
  • 1 on/off type switch
  • power supply for arduino (we used a 9v battery)
  • breadboard, wires, wirecutter
  • 2x 220 ohm resistors, 1x 10k ohm resistor
  • A casing to hold the Device

Circuit Diagram

Code

int analogPin0 = 0;
int analogPin1 = 1;
int analogPin2 = 2;

int analogValue0 = 0;
int analogValue1 = 0;
int analogValue2 = 0;            // outgoing ADC value

int wasOn=-1;

int y = 0;

float distance, distanceo, totaldist, totaldisto;
float velocity, speedo, accel, accelo; 

int d1, d2, d3, d1o, d2o, d3o;
int count = 1;

float lowend, highend, lowendo, stayold, stayold2;
int highcount, lowcount, staycount, mystopcount, countdown;
int iteration, iterationo;

int switchPin = 7;      //  digital input pin for a switch
int yellowLedPin = 3;   //  digital output pin for an LED
int redLedPin = 6;      //  digital output pin for an LED
int buzzerPin = 8;      //  digital output pin for a buzzer
int switchState = 0;    //  the state of the switch
int stops = 2;          //  number of stops
int buzzerState = 0;    //  if buzzer is on

void setup()
{
  pinMode(switchPin, INPUT);       // set the switch pin to be an input
  pinMode(yellowLedPin, OUTPUT);   // set the yellow LED pin to be an output
  pinMode(redLedPin, OUTPUT);      // set the red LED pin to be an output
  pinMode(buzzerPin, OUTPUT);      // set the buzzer pin to be an output

  // start serial port at 9600 bps:
  Serial.begin(9600);
  lowend=highend=accel=velocity=distance=d1=d2=d3=staycount=mystopcount=0;
  iteration=0;
  lowendo=totaldisto=accelo=speedo=totaldist=distanceo=d1o=d2o=d3o=iterationo=0;
  highcount=lowcount=3;
  stayold=0; stayold2=1;
  countdown=3;
}

void loop()
{
  switchState = digitalRead(switchPin);

  analogValue0 = analogRead(analogPin0); 

  analogValue1 = analogRead(analogPin1); 

  analogValue2 = analogRead(analogPin2); 

 if (switchState == 1) {
    wasOn=1;
  }
  if(switchState == 0 && wasOn == 1)
  {
    stops = stops + 1;
    //Serial.println("HAI! I'm on!");
    wasOn=0;
  }

  /*
 Serial.print(analogValue0);
 Serial.print("*");
  Serial.print(analogValue1);
   Serial.print("*");
   Serial.println(analogValue2);
   */
  // pause for 10 milliseconds:
  delay(10);

	/*
	the data is collected every 10 ms, so a count of 100 is 1 second
	*/
        if(count==100)
        {
          iteration++;

          /*
            if 3 data points are high and close enough to each other then a 
	    high-end point is recorded
          */
          if(totaldist-300 > lowend) // looking for a number above the lowest 
                                     //data point (lowend) 
          {
            if(highcount >=2) // on the 3rd occurence of a high point within
                              // 100 points of itself, see if its ok to say 
 			      // its a high point 
            {

              if(totaldisto+100 >= totaldist && totaldisto-100 <= totaldist)
              {  highend=totaldist; } else{ highcount=0;}
            } else { //else the count is restarted and the search for 
                     // consecutive high data points continues
              if(totaldisto+100>=totaldist && totaldisto-100<=totaldist)
              {  highcount++; } else { highcount=0; }
            }
          }

          /* A cheap hack. Just puts the first data point lower than the first 
	     high data point into the low end point. */
          if(highend>0 && lowend==0) {
            if(totaldist 0)
          {
            if(totaldist>lowend){highend=totaldist;}
          }

          /*
            if 3 data points in succession are low, then a  new low end point is
	    recorded
          */
          if(totaldist+300 < highend)// looking for a number below the high 
				     //data point
          {
            if(lowcount >=2){ // on the 3rd occurence of a low data point w/in 
                              // 100 points of itself, check to see if its ok 
			      // to record
              if(totaldisto+100>=totaldist && totaldisto-100<=totaldist)
              { lowendo=lowend; lowend=totaldist; } else {lowcount=0;}
            } else {//else the count is restarted and the search for consecutive
                    // low points resumes
              if(totaldisto+100>=totaldist && totaldisto-100<=totaldist)
              {  lowcount++; } else { lowcount=0; }
            }
          }

          /*
          Serial.print("!");
          Serial.print("*");
          Serial.print(highend,DEC);
          Serial.print("*");
          Serial.print(lowend,DEC);
          Serial.print("*");
          Serial.println(totaldist,DEC);
          */

         /*if the last low end point is close enough to the current low end
        point, then start saying that maybe we're stopping or have stopped */
          if(lowendo+100>=lowend && lowendo-100<=lowend)
          {staycount++; stayold2=lowendo;}else{staycount=0;}
          /* if we've been at a low end for quite a while and its not the 
          beginning of the program then check to see if we've been staying 
             at the same place as well and if so then say that we think that 
             we've stopped */
          if(staycount>=3 && highend!=0 && lowend!= 0 && stayold!=stayold2)
          {
            //Serial.println("@");
            stayold=lowendo;
            stayold2=stayold;
            staycount=0;
            if(mystopcount==-1)
            {
              //Serial.println("#");
              countdown--;
              stops--;
            }

	    /*
            stops--;
            Serial.print(iteration);
            Serial.print(" ");
            Serial.println(stops);
	    */
            if (stops == 1) {
              digitalWrite(yellowLedPin, HIGH);   // turn on the yellow LED
            }
            if (stops == 0) {
              digitalWrite(yellowLedPin, LOW);   // turn off the yellow LED
              digitalWrite(redLedPin, HIGH);     // turn on the red LED
              digitalWrite(buzzerPin, HIGH);     // turn on the buzzer
              buzzerState = 1;
              stops=0;
            }

            mystopcount++;
            iterationo=iteration;

          }

          //this is the number we need to play with to finesse things
          if(iterationo+8 < iteration){mystopcount=-1;}
          if(iterationo+3 < iteration){
          digitalWrite(buzzerPin, LOW); digitalWrite(redLedPin,LOW);
        }

          /* reset distances and times */
          totaldisto=totaldist;
          totaldist=0;
          count=1;

          speedo=velocity;
          accelo=accel;

        }

        /*below this line is all graph data */

        //X
        y = analogValue0;
        d1 =  y- d1o;
        d1o = y;

        //Y
        y = analogValue1;
        d2 = y - d2o;
        d2o = y;

        //Z
        y = analogValue2;
        d3 = y - d3o;
        d3o = y;

        //Distance
        if(d1o != 0 && d2o != 0 && d3o != 0)
        {
          distance = sqrt(sq(d1)+sq(d2)+sq(d3));
          distanceo= distance;
        }

        //Speed (averaged over time (every reading is 1 second)), reset @ STOPs
        totaldist+=distance;  //DONT'T DELETE THIS LINE OR EVERYTHING WILL DIE
        velocity = totaldist/count;

        //Accel
        accel = velocity/count;

        count++;  //OR THIS
}

Thoughts, Commnets, Concerns

So this project went along at pretty steady pace. We had a few hiccoughs in the beginning, trying to interpret the accelerometer data in order to extrapolate the speed and then figure out how to detect a "stop" from all of that mess.
Once we got that figured out, it was just a matter of actually riding the train trying to fine tune our settings. The most trouble we had (still have actually) was with detecting false stops. Where the train decelerates while underground or stops for some train delay or another.
We've thought about combining the accelerometer with an audio sensor or something but none of those ideas were really feasible in the amount of time we had. So right now the Device only works for the 4/6 train line and its sometimes a bit shaky at that.

Leave a Reply

Your email address will not be published.