Introduction: Intelligent Traffic Management With the Internet of Things

A smart device that prompts a driver to speed up or slow down in order to pass only green signals. This way, highway fuel economies can be achieved in the city, reducing pollution by up to 25%

Step 1: A Brief Overview - Theory of Operation

Traffic has the ability to irritate the best of us. What if, that can be changed with the Intel Edison? This project is essentially a device that is kept in a car, communicates with an online server that stores traffic signal timings, and prompts the driver to speed up or slow down in order to reach every signal while it's green. This Instructable is still a work in progress, as it will require some work to integrate completely with the current infrastructure, but nevertheless, it's a great proof of the concept as well as the promise it holds for the future.

The way this is pulled off is through careful coordination between the timed signals and the GPS location. The signals' locations and timing information is downloaded onto this device, which then uses its GPS position to determine which signal is the vehicle headed to, as well as the speed to maintain in order to catch that signal while green. An LED will light up to let the driver know to speed up, slow down, or maintain his current speed. The program is written in JavaScript, though it can easily be adapted to other languages as well. The database that stores the information runs on Google App Engine, and runs a Python script to handle the data requests. If this device is implemented in every vehicle on the road, we can expect to see much higher fuel economies, less pollution, and less traffic in general.

Step 2: Parts Required

First of all, just a disclaimer: This device is only intended for experimental purposes only; I will not be liable if you decide to take this on the road.

Parts List:

  • Intel Edison with Arduino Breakout
  • Any NMEA-based GPS (I'm using the Parallax #28506)
  • A 3G dongle (I'm using the Huawei E303
  • A few LEDs to notify the driver

Step 3: Assembly

You'll need to set up your board with the Intel XDK, if you haven't done so already. Setup is quite simple, and hundreds of tutorials are making rounds around the web on how to do that. I would suggest taking a look at the following link with regards to setup, as it includes everything you need to know from the hardware to the IDE setup:

Assembling the hardware side of the board is pretty straightforward, the GPS must be powered with the 5V pin as labeled on the board. Ground connections are just as essential. The raw NMEA data must be fed into the UART Rx port, which is located on the Arduino shield header pin closest to the Edison (See the picture). The 3G dongle will be plugged into the USB-A port on the side; I've decided to use a USB extension, as the dongle is too wide to fit in with the power plug. Make sure the USB mode selector switch is in the position as shown in the picture (towards the large USB port).

Step 4: Programming

The program will be an ever-evolving project. If you would like to have access to an updated version, I would suggest forking the code from my GitHub repository at the following link:

However, I've pasted the code below for your convenience, although this is only for the local device that will be kept in the vehicle. The Server files are all located on the repo.

For those of you who are interested, here's a basic outline of the algorithm that the program uses:

  1. GPS receives location, speed, heading, and time
  2. Device requests data from server via the 3G dongle
  3. Server responds with a data stream, similar to that of a NMEA sentence (but, hey, it's an easy protocol)
  4. Data stream is parsed and arranged into a 2-D array, containing the signals' locations, timings, offsets, etc.
  5. Using this information, the device determines which signal is approaching.
  6. The green light window is determined, and measures it against the current speed
  7. Device prompts driver to speed up, slow down, or maintain speed in order to catch the signal's green window.

In the future, this could be expanded to include non-timed signals (the ones with induction coils under the road), as well as a "safety buffer" of approximately 3 seconds when the vehicle will *barely* make it past the signal. This way, the driver will never run any yellow lights (dangerous); there will be some time to spare.

import mraa;
import Math;

//Port Initialization

var GPS = mraa.Uart(0); var 3G = mraa.Usb(0); //not working as of yet, a USB host port driver will be implemented in its place var increase = mraa.gpio(2); var maintain = mraa.gpio(3); var decrease = mraa.gpio(4); GPS.setBaudRate(9600);


var earthRadius = 6371000; //radius of the Earth in meters var degToRad = 0.01745329251; //Radians per degree var radToDeg = 57.2957795131; //Degrees per radian

function getLocation(){ //Uses the $GPGGA messages to determine current location var GPSLocation = [0,0,0,0]; while(1){ if(GPS.dataAvailable()){ var buffer = GPS.readStr(512); if (buffer.find("GPGGA") != -1){ var rawNmea = buffer.substring("GPGGA"),"\n")); var nmeaList = rawNmea.strip().split(","); var time = nmeaList[1]; var latraw = nmeaList[2]; var latdir = nmeaList[3]; var lonraw = nmeaList[4]; var londir = nmeaList[5]; var lat = (latraw.substring(0,2)) + (latraw.substring(2)) /60; var lon = (lonraw.substring(0,3)) + (lonraw.substring(3,0)) /60; if (londir == "W"){ lon = lon * -1; } if (latdir == "S"){ lat = lat * -1; } var alt = nmeaList[9]; GPSLocation = [lat,lon,alt,time]; return GPSLocation; } } } } function getVelocity(){ //Uses $GPVTG messages to determine speed and direction var GPSVel = [0,0]; while(1){ if(GPS.dataAvailable()){ var buffer = GPS.readStr(512); if (buffer.find("GPVTG") != -1){ var nmeaData = buffer.substring("GPVTG"),"\n")); var nmeaList = nmeaData.strip().split(","); var hdg = nmeaList[1]; var rawVel = nmeaList[7]; var vel = rawVel / 3.6; GPSVel = [hdg,vel]; return GPSVel; } } } }

function getLights(){ var Lights = [7][10]; //array of traffic light timings, 10 nearest lights, 7 parameters each. Lat,Lon,NTime,Etime,TimeOffset,Heading,Distance //requestData(); if(3G.dataAvailable()){ var buffer = 3G.readStr(512); if (buffer.find("$$") != -1){ lightData = buffer.substring("$$"),"\n")); //light information specification follows GPS scheme, with "$$" denoting the beginning of a sentence. lightList = nmeaData.strip().split(","); for (i=0;i

function computeDistance(Latdeg1, Londeg1, Latdeg2, Londeg2){ var Lat1 = Latdeg1 * degToRad; var Lat2 = Latdeg2 * degToRad; var Lon1 = Londeg1 * degToRad; var Lon2 = Londeg2 * degToRad; var distance = 2*earthRadius* Math.asin(sqrt((Math.sin(Lat2-Lat1/2))^2 + (Math.cos(Lat1) * Math.cos(Lat2) * (Math.sin(Lon2-Lon1/2))^2) )); //Use haversine formula to compute great circle distance }

function computeHeading(Latdeg1, Londeg1, Latdeg2, Londeg2){ var Lat1 = Latdeg1 * degToRad; var Lat2 = Latdeg2 * degToRad; var Lon1 = Londeg1 * degToRad; var Lon2 = Londeg2 * degToRad; var y = Math.sin(Lon2-Lon1) * Math.cos(Lat2); var x = Math.cos(Lat1)*Math.sin(Lat2) - Math.sin(Lat1)*Math.cos(Lat2)*Math.cos(Lon2-Lon1); var heading = Math.atan2(y, x).toDegrees(); return heading; }

//Main Sequence while(1){ var temp[4]; var currLat; var currLon; var currHdg; var currSpd; var Lights; var time; var Dir; var currSignal; var t1, t2; temp = getLocation(); currLat = temp[0]; currLon = temp[1]; time = temp[3]; temp = getVelocity(); currHdg = temp[0]; currSpd = temp[1]; Lights = getLights(); for(i = 0; i < Lights.length(); i++){ var hdg = computeHeading(currLat, currLon, Lights[0][i], Lights[1][i]); if (hdg > 180) { Lights[5][i] = 180 - computeHeading(currLat, currLon, Lights[0][i], Lights[1][i]); } else { Lights[5][i] = computeHeading(currLat, currLon, Lights[0][i], Lights[1][i]); } Lights[6][i] = computeDistance(currLat, currLon, Lights[0][i], Lights[1][i]); if (Lights[6][i] < Lights[6][currSignal]){ currSignal = i; } } if (hdg < 45 || hdg > 315 || 135 < hdg < 225){ //north-south traffic Dir = 0; } else { Dir = 1; } if (Dir == 0){ t1 = Lights[4][currSignal] + time%(Lights[2][currSignal] + Lights[3][currSignal]); //may need to be fixed t2 = Lights[4][currSignal] + time%(Lights[2][currSignal] + Lights[3][currSignal]) + Lights[2][currSignal]; }else{ t1 = Lights[4][currSignal] + time%(Lights[2][currSignal] + Lights[3][currSignal]); t2 = Lights[4][currSignal] + time%(Lights[2][currSignal] + Lights[3][currSignal]) + Lights[3][currSignal]; } if (t1 > Lights[6][currSignal]){ \\increase speed increase.write(1); maintain.write(0); decrease.write(0); } else if(t1 == Lights[6][currSignal]){ \\maintain speed increase.write(0); maintain.write(1); decrease.write(0); } else { \\decrease speed increase.write(0); maintain.write(0); decrease.write(1); }


Tech Contest

Participated in the
Tech Contest

Intel® IoT Invitational

Participated in the
Intel® IoT Invitational