An Arduino is a microcontroller that can be used to control electronic devices such as lights, motors, and other devices. They can also be used to create interactive projects such as games and robots. Arduinos are some of the most popular microcontrollers used by hobbyists and makers because they are easy to use and relatively inexpensive.
Collimator is a powerful simulation platform that allows users to fully test a system before deploying to real world hardware. Models in Collimator can be quite complex, involving multiple hardware components that run their own code. By using Submodels in Collimator to represent each physical processor, C code can be generated and exported in order to deploy the model on physical hardware such as an Arduino, or any other compatible microcontroller. This guide will demonstrate how to generate and deploy code to an Arduino Uno and connect the Collimator model to actual hardware inputs and outputs.
In this project, we'll be using an Arduino Uno to simulate a traffic light on a busy street with a pedestrian crossing. 3 LEDs will represent the red, yellow, and green lights, and a button will represent the pedestrian crossing button. The traffic light stays green until a pedestrian arrives and pushes the button. The traffic light then changes to yellow, then red while the pedestrian crosses, and back to green again until the next crossing.
The Collimator model consists of a submodel representing the Arduino Uno, and a group which simulates a button press. Because Collimator generates code for submodels, the Collimator model must be arranged such that each hardware device that will use code generation is represented as a separate submodel. On the left, the Button group will generate a button press at 15 seconds so we can test the system within Collimator. On the right, the TrafficLight submodel will take an input for the pedestrian crossing button, and provide 3 outputs for the green, yellow, and red LEDs. The outputs are not connected to anything but will still be shown in the visualizer.
The TrafficLight submodel uses a counting loop, and some basic logic to determine the states of each LED.
On the left, a UnitDelay with a constant Adder that increases the loop by 1 with each time step. By itself, this loop would count the number of seconds since the start of the simulation.
If the button is pushed, the IfThenElse block before the UnitDelay will reset the loop to a value of 0. Now the value in this loop will represent the number of seconds since the button was last pushed.
After the button is pushed the light should turn yellow, so the value stored in the loop is now compared to YellowTime, which is 2 seconds. If it’s been less than 2 seconds, Y is on.
Another similar test is used to determine if R is on.
YellowTime is subtracted from the counting loop value first because RedTime is the number of seconds red should be on, not the number of seconds since the last button push.
One more check is needed since the result of the subtractor might be negative, which would indicate that Y should be on an not R. With the highlighted parts here, R can only turn on if Y is off.
Finally, the simplest test to see if G should be on is if neither Y or R are on.
Here is the visualization tab after running the simulation. The light starts Yellow for 2 seconds, then turns Red for 4 seconds, then turns Green and stays Green until the button is pressed. Then the cycle repeats.
With the TrafficLight submodel selected, click the button at the bottom of the properties side menu.
You should see this popup at the top of the screen.
A zip file will download.
TrafficLight_initialize(dt_ms, TrafficLight_vars_ptr) is called in the setup() function of TrafficLight.ino. It is called once on startup, and never again.
TrafficLight_main(dt_ms, TrafficLight_vars_ptr) is the main function call which happens inside the loop() function. It must be called periodically, every dt_ms milliseconds.
Fields are used instead of variables. They can be accessed with an arrow operator: TrafficLight_vars_ptr->TrafficLight_G_0
Between every call to the main function, the Arduino needs to set input variables for the next time step, and get output variables from the last one.
When setting up with TrafficLight_initialize(dt_ms,TrafficLight_vars_ptr), dt_ms should be set to the intended time between loops. When calling TrafficLight_main(dt_ms,TrafficLight_vars_ptr) in the loop, dt_ms should equal the actual time since the last loop.
The Arduino Uno has 14 general purpose input/output (GPIO) pins. Some of these pins have special hardware capabilities such as Pulse Width Modulation (PWM), but for this project, only 4 basic GPIO pins are needed.
digitalRead and digitalWrite functions are used to read and write digital values to pins on the Arduino. To use these functions, you must first configure the pin’s mode using pinMode().
pinMode(pin, mode) can set a particular GPIO pin to INPUT or OUTPUT, enabling digitalRead or digitalWrite
digitalRead will return either a HIGH or LOW value, depending on the voltage level present on the specified pin.
digitalWrite will set the specified pin to either a HIGH or LOW value, depending on the value you specify.
Two jumper wires are needed to connect the Arduino’s 5v power supply to the breadboard’s power rails.
Connect the green, yellow, and red LEDs to pins 3, 4, and 5 respectively as shown. Use a 220 ohm current limiting resistor in series with each LED. Make sure the short leg on the LED goes to ground, and the long leg to the Arduino.
Add a button as shown. Connect one side to 5v, and the other side to pin 2. Add a 10k ohm pull down resistor between pin 2 and ground so that whenever the button is not being pressed, any latent charge is discharged to ground.
The Arduino IDE is a free, open-source development environment used to write, compile, and upload code to an Arduino or compatible microcontroller. It is available for Windows, Mac, and Linux operating systems. This section will explain how to download and install the Arduino IDE on Windows, how to set it up for use with an Arduino Uno, and how to upload the blink sketch to test that everything works.
Download the Arduino IDE from the Arduino website. Go to https://www.arduino.cc/en/Main/Software and download the installer of your choice.
Once the download is complete, open the file and follow the prompts to install the Arduino IDE.
Next, connect your Arduino Uno to your computer using a USB cable. Windows should automatically install the driver if needed.
Once the installation is complete, open the Arduino IDE.
Using the drop down selector at the top of the Arduino IDE, select Arduino Uno. Make sure that there is a COM port listed. If you don’t see a COM port here, then the Arduino IDE is not able to see the Arduino Uno. If you see a COM port but it says “Unknown” instead of Arduino Uno, select the board manually as shown below.
Now that everything is set up, we can upload a sketch to test that everything is working. In the Arduino IDE, go to File > Examples > 01.Basics > Blink. This will open the blink sketch in the IDE.
Click the upload button in the Arduino IDE to compile and upload the sketch to your Arduino Uno. Once the upload is complete, you should see the LED on the Arduino Uno board blink once per second.
Create a new project in the Arduino IDE by clicking File > New. Save the project and give it a name such as “TrafficLight”
Click Sketch > Show Sketch Folder to open the folder containing all the files in this sketch. Right now, there is only TrafficLight.ino. Copy into this folder the TrafficLight.c and TrafficLight.h files from the downloaded zip file containing the generated code. Rename TrafficLight.c to TrafficLight.cpp.
Go back to the Arduino IDE.
There should be two new tabs at the top for the two files added.
Open the TrafficLight.txt file from the same zip file.
After copying and pasting the generated code into the TrafficLight.ino file, it should look like this.
After importing the code generated by Collimator, the loop() function must be configured to run the main function periodically. Since this example is not very time sensitive, it is fine to set dt_ms to a constant 1000 so our time step is 1 second. In the declarations at the top of the ino file, define dt_ms as shown.
Add a delay at the end of the loop.
Before any GPIO pins can be used for button input or LED output, the pinMode must be set.
Check the button state using digitalRead() as shown.
Update each LED’s state using digitalWrite() as shown.
Press the arrow button to compile and upload the sketch. If there are no compilation errors, the sketch should start running within a few seconds and the LEDs will light up.