Arduino GPIO Traffic Light w/ Web Server (Lab Writeup)

Create a Traffic Light with using the GPIO pins on an Arduino. Then, control it with a web server!

Objective

The purposes of this lab are to:

  • Reinforce enumerating requirements from use cases and user stories
  • Become familiar with the Arduino platform and its programming methodologies.
  • Program an Arduino-based micro-controller to use the GPIO pins to control LEDs.
  • Develop iteratively, beginning with a minimum viable product and add functionality until the requirements are met.

Materials

I used the following materials to accomplish this lab:

  • Wemos D1 Mini Arduino
  • 1 x breadboard
  • 1 x Red LED
  • 1 x Yellow LED
  • 1 x Green LED
  • 3 x 33 Ω Resistor (OrOrBlGd)
  • 4x Jumper Wires

References

I used the following resources in this lab:

Procedures:

  1. Install Arduino’s latest IDE
  2. Install the ESP8266 core library as a remote repository in Arduino IDE.
  3. Verify which port your Arduino will be using once plugged into the computer with Device Manager (if on Windows)
  4. Model the functionality, logical flow, and components of the system. Include a schematic diagram.
    1. Functionality – This system is a basic state machine, represented by the diagram in Appendix A.
      • Upon startup, the machine will enter the “LED OFF” state.
      • While in the “Initial (off)” state:
        • If the system receives a /<color> command, it will change to the ‘Any Single Color’ state where the LED associated with that color will be lit.
        • If the system receives an /off command, it will change to the “Off” state, which is depicted above as being different from the initial off state.
      • While in the “Any Single Color” state:
        • If the system receives a /<color> command, it will change to the ‘Any Single Color’ state where the LED associated with that color will be lit. This color may be different from the previous color.
        • If the system receives an /off command, it will change to the “Off” state.
        • If the system receives an /auto command, it will change to the “Auto” state where red, yellow, and green will be cycled in 10-2-10 intervals. Time in ms will be printed to the serial monitor for debugging.
      • While in the “Off” state:
        • If the system receives a /<color> command, it will change to the ‘Any Single Color’ state where the LED associated with that color will be lit.
        • If the system receives an /off command, it will remain in the “Off” state.
        • If the system receives an /auto command, it will change to the “Auto” state where red, yellow, and green will be cycled in 10-2-10 intervals. Time in ms will be printed to the serial monitor for debugging.
      • While in the “Auto” state:
        • If the system receives a /<color> command, it will change to the ‘Any Single Color’ state where the LED associated with that color will be lit.
        • If the system receives an /off command, it will change to the “Off” state.
        • If the system receives an /auto command, it will remain in the “Auto” state where red, yellow, and green will be cycled in 10-2-10 intervals. Time in ms will be printed to the serial monitor for debugging.
    2. System Design – The technical function of this system is outlined in the code found in the appendix. The main points of the code are the web handler functions.
    3. Component Diagram and Schematic Diagram – This system is represented by the similar “as-built” diagram in Appendix B, showing a physical component diagram
  1. Follow the first two resources under ‘References’ to get a basic stoplight and web server, then combine the ideas, meeting project specifications.
  2. Use the HTML from the RPi Stoplight Web Server (3rd resource under ‘References’) to create the web page
  3. Test functionality and usability

Observations

                This lab was fun and much more straightforward to me than the last one with the Raspberry Pi. I felt like it was hard to go astray or go down a rabbit hole of getting something to work here because its all done in a single file that can only be a single thread. The simplicity of it is wonderful and I’ve come to quickly appreciate Arduino for how effective it can be while being so simple and relatively easy to work with.

                The largest issues I had were with the Arduino IDE itself. The serial monitor likes to print out gibberish at times, which I never fully got rid of. Also, the serial monitor tab must be closed before you upload new compiled code to the Arduino board, or it says there’s a port error. These were annoying, but this didn’t stop me from completing the project with relative ease.

                The hardest part for me was the discrepancy between native HTML characters and C string escape characters. This made writing the HTML code in C strings tedious. The HTML was what took me the longest despite having already had working HTML code from Lab 1.

                One of the coolest parts in the transition from RPi to Arduino was that in Arduino the code is looped about every 100ms instead of being on a as-needed basis like in RPi’s Python. This made the /auto mode very easy to code because I’d know that logic for light switching would be run very often.

Because there is only a single device, there isn’t any communication between internal components. The single device does the following:

  • Listening on TCP port 80
  • Parsing input
  • Controlling the LEDs
  • Responding to the client with HTML

Thought Questions

What are some key differences between developing this lab on a Raspberry Pi, and developing on Arduino?

            There are two big changes moving from Raspberry Pi to Arduino. On Arduino, the program is a single (usually C) file that runs forever, and so all the code must be in that one file and work within a single process and thread. On Raspberry Pi, the python implementation I used was multi-threaded by default, and I could use as many files as I liked. Because of the simplicity, Arduino was more straightforward and was easier to wrap my head around.

What are the strengths and trade-offs of each of these platforms?

            With a Raspberry Pi, the user can create processes with multiple processes, threads, and can utilize more that four gigabytes of RAM and many gigabytes of storage. These processes can be complex and are layered over a full operating system. On the other hand, Arduino is not powerful at all, but can be very efficient and simplistic. These run on a single file that can run forever, so although it is less powerful and simpler, it can be much cheaper, more stable, and easier to debug. Arduino comes with the advantage of a side button that will reset the system and run the file over again, whereas on an RPi, you’d need a shell. From the user perspective, it’d be much easier to work with an Arduino system.

How familiar were you with the Arduino platform prior to this lab?

            I had no prior experience with Arduino or its IDE.

What was the biggest challenge you overcame in this lab?

            The biggest challenge to me was learning how to write the HTML in a C based file. This became very tedious because of the misalignment of escape symbols and quotation marks between the two languages. This took me a while to get right. In addition, the timing of the auto mode took a while to figure out, but once I understood that this is a single threaded program that runs in a constant loop, I figured out what I think is a clever way to do the timing logic.

Please estimate the total time you spent on this lab and report.

            I spent about 5 hours on the project with 1 hour on this lab report.

Certification of Work

I certify that the solution presented in this lab represents my own work. In the case where I have borrowed code or ideas from another person, I have provided a link to the author’s work in the references and included a citation in the comments of my code.

–Jairus Christensen

Appendix A: State/Functionality Diagram

Appendix B: Physical Component Diagram

Appendix C: Arduino Code

#include <ESP8266WiFi.h>

// wifi pass
const char* ssid = "MyWifiSSID";
const char* password = "MyWifiPassword";

WiFiServer server(80);

int cycleValue;  
unsigned long start;
bool cycle = false;
int green = D2;
int yellow = D3;
int red = D4;
int msToBeRed = 5000;
int msToBeGreen = 5000;
int msToBeYellow = 2000;

void setup() {
  //Setup serial and all LED outputs then clears the LEDs
  Serial.begin(9600);
  pinMode(green, OUTPUT);
  pinMode(yellow, OUTPUT);
  pinMode(red, OUTPUT);
  allLightsOff();
  //Using the Wifi library begin connecting to the set network and provide status updates.
  Serial.print("Connecting to ");
  Serial.println(ssid);
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println();
  Serial.println("(( WiFi connected ))");
  Serial.println(WiFi.localIP());
  server.begin();
  Serial.println("((( Server Started )))");
}

void loop() {
  
  // Sets up a client object for connections to the webpage. Constantly checks if a request is made
  WiFiClient client = server.available();
  if (client) {
    while (!client.available()) {
      delay(10);
    }
  }
  client.setTimeout(100);          
  //This section reads for inbound requests made by the web client. If any one of the endpoints is hit the corresponding code will trigger.
  String req = client.readStringUntil('\r');
  if (req.indexOf("/off") != -1) {
    cycle = false;
    allLightsOff();     
    Serial.println("Off Selected");         
  }
  if (req.indexOf("/green") != -1) {
    cycle = false;
    greenLight();
    Serial.println("Green Selected");
  }
  if (req.indexOf("/yellow") != -1) {
    cycle = false;
    yellowLight();
    Serial.println("Yellow Selected");
  }
  if (req.indexOf("/red") != -1) {
    cycle = false;
    redLight();
    Serial.println("Red Selected");
  }
  if (req.indexOf("/auto") != -1) {
    cycle = true;
    start = millis();
    Serial.println("Auto Selected");
  }

  if (cycle == true) {
    unsigned long now = millis();
    unsigned long timeSinceStart = now - start;
    Serial.println(timeSinceStart);
    if (timeSinceStart < msToBeRed) {
      redLight();      
    }
    if ((timeSinceStart >= msToBeRed) && (timeSinceStart < (msToBeRed + msToBeGreen))) {
      greenLight();
    } 
    if ((timeSinceStart >= (msToBeRed + msToBeGreen) && (timeSinceStart < (msToBeRed + msToBeGreen + msToBeYellow)))) {
      yellowLight();
    } 
    if (timeSinceStart >= (msToBeRed + msToBeGreen + msToBeYellow)) {
      start = millis();
    }
  }
  
  client.println("<!doctype html>");
  client.println("<html>");
  client.println("<head>");
  client.println("<link rel='stylesheet' href='https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css' integrity='sha384-Vkoo8x4CGsO3+Hhxv8T/Q5PaXtkKtu6ug5TOeNV6gBiFeWPGFN9MuhOf23Q9Ifjh' crossorigin='anonymous'>");
  client.println("<link rel='stylesheet' href='https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css' integrity='sha384-1q8mTJOASx8j1Au+a5WDVnPi2lkFfwwEAa8hDDdjZlpLegxhjVME1fgjWPGmkzs7' crossorigin='anonymous'>");
  client.println("<script src='https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/js/bootstrap.min.js' integrity='sha384-0mSbJDEHialfmuBBQP6A4Qrprq5OVfW37PRR3j5ELqxss1yVqOtnepnHVP9aJ7xS' crossorigin='anonymous'></script>");
  client.println("<title>Arduino Web Server Stoplight</title>");
  client.println("</head>");
  client.println("<center>");
  client.println("<body>");
  client.println("<header>");
  client.println("<h1>Traffic Control</h1>");
  client.println("</header>");
  client.print("<a href='/red' class='btn btn-block btn-lg btn-default' role='button'>Red</a>");
  client.print("<a href='/yellow' class='btn btn-block btn-lg btn-default' role='button'>Yellow</a>");
  client.print("<a href='/green' class='btn btn-block btn-lg btn-default' role='button'>Green</a>");
  client.print("<a href='/off' class='btn btn-block btn-lg btn-default' role='button'>Turn off</a>");
  client.print("<a href='/auto' class='btn btn-block btn-lg btn-default' role='button'>Auto Mode</a>");
  client.println("</body>");
  client.println("</center>");
  client.println("</html>");
}
void allLightsOff() {
  digitalWrite(green, LOW);
  digitalWrite(yellow, LOW);
  digitalWrite(red, LOW);
}
void greenLight() {
  digitalWrite(green, HIGH);
  digitalWrite(yellow, LOW);
  digitalWrite(red, LOW);
}
void yellowLight() {
  digitalWrite(green, LOW);
  digitalWrite(yellow, HIGH);
  digitalWrite(red, LOW);
}
void redLight() {
  digitalWrite(green, LOW);
  digitalWrite(yellow, LOW);
  digitalWrite(red, HIGH);
}

Appendix D: System Interface – Web Page (any state)

Appendix E: Serial Monitor Output

Share this post
Jairus Christensen

Jairus Christensen

Articles: 19

Leave a Reply

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