Project showcase
The Train of the Future

The Train of the Future

Our train will solve many irritations. It is no longer crowded, faster, on time and gives you always up-to-date information through an app.

  • 13,854 views
  • 5 comments
  • 19 respects

Components and supplies

Necessary tools and machines

3drag
3D Printer (generic)

About this project

Do you also hate it when your train is late, or if you have to stand for hours in a crowded carriage, or if the remaining time on the arrival board isn't correct? We have the solution! Our concept is to develop the train of the future. 

The train:

In every station, one or more carriages will be standing. Every carriage has a motor. When a train is approaching to the station. The first carriage will unlink and go to the side track. The other carriages will go straight on.

In the meantime, a carriage with passengers will leave the station. When this carriage is in front of the train, the carriage with passengers will link to the other carriages. The train is now moving to the next station.

We have realized this with a Lego NXT robot and 3D printed wheels.

GPS:

In the train, there will be a GPS. This will give the passengers in the station up-to-date information by a mobile application.

We used an IOTOPIA rapid development kit for this part of our project.

Reservation system:

We have also build a reservation system. This will prevent crowded trains. When you buy your train tickets online, you receive a password. You need to enter this password at the entrance of the train to get access to the train.

We have build the access system with an Arduino prototype shield V2, some push buttons and resistors.

Extra: Lego bricks:

This are the bricks that we have used to build our project. They are all part of the LEGO NXT set.

Project video:

To help you understand our project, we have made a short video to explain it.

End

If you have any further questions. Please ask them below in the comments.

Thank you for watching to our project,

Tom - Stijn - Thijs

Code

GPS codeArduino
#include "ATT_IOT_UART.h"      // AllThingsTalk Arduino UART IoT library
#include <SPI.h>               // Required to have support for signed/unsigned long type
#include "keys.h"              // Keep all your personal account information in a seperate file
#include <SoftwareSerial.h>

ATTDevice Device(&Serial1);
char httpServer[] = "api.smartliving.io";          // HTTP API Server host
char mqttServer[] = "broker.smartliving.io";       // MQTT Server Address

// Define PIN numbers for assets
// For digital and analog sensors, we recommend to use the physical pin id as the asset id
// For other sensors (I2C and UART), you can select any unique number as the asset id
#define gpsId 2                // Digital sensor is connected to pin D2 on grove shield

SoftwareSerial SoftSerial(2, 3);
unsigned char buffer[64];                   // Buffer array for data receive over serial port
int count=0;
int time= 30;                               // set time between reading coordinates (in seconds)

// Required for the device
void callback(int pin, String& value);

void setup()
{
  Serial.begin(57600);                                 // Init serial link for debugging
  while(!Serial && millis() < 1000);                   // Make sure you see all output on the monitor. After 1 sec, it will skip this step, so that the board can also work without being connected to a pc
  Serial.println("Starting sketch");
  Serial1.begin(115200);                               // Init serial link for WiFi module
  while(!Serial1);

  while(!Device.StartWifi())
    Serial.println("Retrying...");
  while(!Device.Init(DEVICEID, CLIENTID, CLIENTKEY))   // If we can't succeed to initialize and set the device credentials, there is no point to continue
    Serial.println("Retrying...");
  while(!Device.Connect(httpServer))                   // Connect the device with the AllThingsTalk IOT developer cloud. No point to continue if we can't succeed at this
    Serial.println("Retrying");

  Device.AddAsset(gpsId, "GPS module", "GPS", false, "{\"type\": \"object\",\"properties\": {\"lat\": {\"type\": \"number\", \"unit\": \"°\"},\"lng\": {\"type\": \"number\", \"unit\": \"°\"},\"alt\": {\"type\": \"number\", \"unit\": \"°\"},\"time\": {\"type\": \"integer\", \"unit\": \"epoc time\"}},\"required\": [\"lat\",\"lng\",\"alt\",\"time\" ]}");   // Create the sensor asset for your device

  delay(1000);                                         // Give the WiFi some time to finish everything
  while(!Device.Subscribe(mqttServer, callback))       // Make sure that we can receive message from the AllThingsTalk IOT developer cloud (MQTT). This stops the http connection
    Serial.println("Retrying");

  //pinMode(gpsId, INPUT);                               // Initialize the digital pin as an input.
  SoftSerial.begin(9600);                 // the SoftSerial baud rate
  Serial.println("GPS module is ready for use!");
  delay(2000);
}


float longitude;
float latitude;
float altitude;
float timestamp;
float timestamp1;
float longitude1;
float latitude1;
float distance;
float time_left;
float station = 15.81; 

void loop() 
{
  if(readCoordinates() == true)
  {
     delay(time*1000);
     if(readCoordinates1() == true)SendValue();
  }
  
  Device.Process();
  delay(5000);
}

void SendValue()
{
    float distance = acos(sin(latitude*3.141592654/180)*sin(latitude1*3.141592654/180)+cos(latitude1*3.141592654/180)*cos(latitude*3.141592654/180)*cos(abs(longitude*3.141592654/180-longitude*3.141592654/180)))*6370*1000; 
    float Speed = distance/ time*3600;

    Serial.println(sin(latitude*3.141592654/180)*sin(latitude1*3.141592654/180)+cos(latitude1*3.141592654/180)*cos(latitude*3.141592654/180)*cos(abs((longitude*3.141592654/180)-(longitude1*3.141592654/180))),20);   

    float time_left = station / Speed ; 
    
    Serial.print("sending gps data");
    String data;
    data = "{\"Distance\":" + String(distance, 10)+"km" + ",\"Speed\":" + String(Speed, 3)+"km/h" + ",\"Time left\":" + String(time_left, 3)+"h" + "}";
    Device.Send(data, gpsId);
}

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////



// Callback function: handles messages that were sent from the iot platform to this device.
void callback(int pin, String& value) 
{ 
    Serial.print("incoming data for: ");         // Display the value that arrived from the AllThingsTalk IOT developer cloud.
    Serial.print(pin);
    Serial.print(", value: ");
    Serial.println(value);
}

bool readCoordinates()
{
  bool foundGPGGA = false;                          // Sensor can return multiple types of data, need to capture lines that start with $GPGGA
    if (SoftSerial.available())                     // If date is coming from software serial port ==> data is coming from SoftSerial shield
    {
        while(SoftSerial.available())               // Reading data into char array
        {
            buffer[count++]=SoftSerial.read();      // Writing data into array
            if(count == 64)break;
        }

        foundGPGGA = count > 60 && ExtractValues();  // If we have less then 60 characters, then we have bogus input, so don't try to parse it or process the values
        clearBufferArray();                          // Call clearBufferArray function to clear the stored data from the array
        count = 0; 
    }
    return foundGPGGA;
}

bool ExtractValues()
{
  unsigned char start = count;
  while(buffer[start] != '$')        // Find the start of the GPS data -> multiple $GPGGA can appear in 1 line, if so, need to take the last one.
  {
    if(start == 0) break;            // It's an unsigned char, so we can't check on <= 0
    start--;
  }
  start++;                           // Remove the '$', don't need to compare with that.
  if(start + 4 < 64 && buffer[start] == 'G' && buffer[start+1] == 'P' && buffer[start+2] == 'G' && buffer[start+3] == 'G' && buffer[start+4] == 'A')      //we found the correct line, so extract the values.
  {
    start+=6;
    timestamp = ExtractValue(start);
    latitude = ConvertDegrees(ExtractValue(start) / 100);
    start = Skip(start);    
    longitude = ConvertDegrees(ExtractValue(start)  / 100);
    start = Skip(start);
    start = Skip(start);
    start = Skip(start);
    start = Skip(start);
    altitude = ExtractValue(start);
    return true;
  }
  else
    return false;
}

float ExtractValue(unsigned char& start)
{
  unsigned char end = start + 1;
  while(end < count && buffer[end] != ',')      // Find the start of the GPS data -> multiple $GPGGA can appear in 1 line, if so, need to take the last one.
    end++;
  buffer[end] = 0;                              // End the string, so we can create a string object from the sub string -> easy to convert to float.
  float result = 0.0;
  if(end != start + 1)                          // If we only found a ',', then there is no value.
    result = String((const char*)(buffer + start)).toFloat();
  start = end + 1;
  return result;
}

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

bool readCoordinates1()
{
  bool foundGPGGA1 = false;                          // Sensor can return multiple types of data, need to capture lines that start with $GPGGA
    if (SoftSerial.available())                     // If date is coming from software serial port ==> data is coming from SoftSerial shield
    {
        while(SoftSerial.available())               // Reading data into char array
        {
            buffer[count++]=SoftSerial.read();      // Writing data into array
            if(count == 64)break;
        }

        foundGPGGA1 = count > 60 && ExtractValues1();  // If we have less then 60 characters, then we have bogus input, so don't try to parse it or process the values
        clearBufferArray();                          // Call clearBufferArray function to clear the stored data from the array
        count = 0; 
    }
    return foundGPGGA1;
}

bool ExtractValues1()
{
  unsigned char start = count;
  while(buffer[start] != '$')        // Find the start of the GPS data -> multiple $GPGGA can appear in 1 line, if so, need to take the last one.
  {
    if(start == 0) break;            // It's an unsigned char, so we can't check on <= 0
    start--;
  }
  start++;                           // Remove the '$', don't need to compare with that.
  if(start + 4 < 64 && buffer[start] == 'G' && buffer[start+1] == 'P' && buffer[start+2] == 'G' && buffer[start+3] == 'G' && buffer[start+4] == 'A')      //we found the correct line, so extract the values.
  {
    start+=6;
    timestamp1 = ExtractValue(start);
    latitude1 = ConvertDegrees(ExtractValue1(start) / 100);
    start = Skip(start);    
    longitude1 = ConvertDegrees(ExtractValue1(start)  / 100);
    start = Skip(start);
    start = Skip(start);
    start = Skip(start);
    start = Skip(start);
    altitude = ExtractValue1(start);
    return true;
  }
  else
    return false;
}

float ExtractValue1(unsigned char& start)
{
  unsigned char end = start + 1;
  while(end < count && buffer[end] != ',')      // Find the start of the GPS data -> multiple $GPGGA can appear in 1 line, if so, need to take the last one.
    end++;
  buffer[end] = 0;                              // End the string, so we can create a string object from the sub string -> easy to convert to float.
  float result = 0.0;
  if(end != start + 1)                          // If we only found a ',', then there is no value.
    result = String((const char*)(buffer + start)).toFloat();
  start = end + 1;
  return result;
}

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
float ConvertDegrees(float input)
{
  float fractional = input - (int)input;
  return (int)input + (fractional / 60.0) * 100.0;
}

unsigned char Skip(unsigned char start)
{
  unsigned char end = start + 1;
  while(end < count && buffer[end] != ',')      // Find the start of the GPS data -> multiple $GPGGA can appear in 1 line, if so, need to take the last one.
    end++;
  return end+1;
}

void clearBufferArray()                         // Function to clear buffer array
{
  for (int i=0; i<count; i++)
  {
    buffer[i] = NULL;                           // Clear all index of array with command NULL
  }
}
GPS CODE - keys.hArduino
In order to see the the time left till the train comes. You have to make an account on smartliving and next fill in the deviceid, clientid, clientkey
#ifndef SETTINGS
#define SETTINGS

#define DEVICEID "******"            // Your device id comes here
#define CLIENTID "*****"            // Your client id comes here;
#define CLIENTKEY "*****"           // Your client key comes here;

#endif
ButtonsArduino
/*
  DigitalReadSerial
 Reads a digital input on pin 2, prints the result to the serial monitor

 This example code is in the public domain.
 */

// digital pin 2 has a pushbutton attached to it. Give it a name:
int pushButton1 = 13;
int pushButton2 = 12;
int pushButton3 = 10;
int pushButton4 = 8;


// the setup routine runs once when you press reset:
void setup() {
  // initialize serial communication at 9600 bits per second:
  Serial.begin(9600);
  // make the pushbutton's pin an input:
  pinMode(pushButton1, INPUT);
  pinMode(pushButton2, INPUT);
  pinMode(pushButton3, INPUT);
  pinMode(pushButton4, INPUT);
}

// the loop routine runs over and over again forever:
void loop() {
    String char1;
    
  
    int buttonState1 = digitalRead(pushButton1);
    int buttonState2 = digitalRead(pushButton2);
    int buttonState3 = digitalRead(pushButton3);
    int buttonState4 = digitalRead(pushButton4);


    if (buttonState1 == 1) Serial.print("A");
    if (buttonState2 == 1) Serial.print("B");
    if (buttonState3 == 1) Serial.print("C");
    if (buttonState4 == 1) Serial.print("D");
    delay(150);
   

}

Custom parts and enclosures

Wheel at the front of the train.
Solid Edge file
legowiel-voor-V3.par
Wheel at the back of the train.
Solid Edge file
legowiel-v3-achter.par

Schematics

Push buttons
Foto%20drukknoppen

Comments

Similar projects you might like

Arduino Bluetooth Basic Tutorial

by Mayoogh Girish

  • 455,007 views
  • 42 comments
  • 239 respects

Home Automation Using Raspberry Pi 2 And Windows 10 IoT

Project tutorial by Anurag S. Vasanwala

  • 285,512 views
  • 95 comments
  • 671 respects

Security Access Using RFID Reader

by Aritro Mukherjee

  • 229,333 views
  • 38 comments
  • 236 respects

OpenCat

Project in progress by Team Petoi

  • 195,972 views
  • 154 comments
  • 1,362 respects
Add projectSign up / Login