Introduction: UCL Embedded - Siemens IOT Ev3 Robot
Ev3 to ESP8266 to IOT to PLC concept
Step 1: Project Overview
The project we have made is a proof of concept of a robot, that can transfer data between an EV3 to an arduino to a wifi module, to a Siemens IOT module, that is connected to a wifi modul, and last transfering the data to a Siemens S7 1700 PLC, where the data will be logged on. This could be used in a webshop storage, where the packages are gonna be transported by robots around the storage. The EV3 robot has a distance sensor on it its front that sends data back to the PLC. First it is written to the aruduino, that sends the data to the ESP8266 wifi module. The wifi module sends the data to another ESP8266 wifi module on the Siemens IOT module. The IOT module then sends the data to the Siemens PLC, that then logges it in a data log, with timestamps and tag value.
Made by: UCL/FMS Students oliv8886, joer799f and Joak1933.
Step 2: Part List
1x Siemens IOT 2040 modul
2x ESP8266 wifi modul
1x Lego Mindstorm Ev3 Box Set
1x Siemens PLC S7-1500
Step 3: I/O List and Building
In this chapter you can see all the connections of the setup. Remember to follow it pefectly, otherwise you might have problems with the code.
Step 4: Setup and Program the PLC
Description how to setup data logging
First go to “Device configuration” in Tia-portal and after that to ”Web server” and then the under “General” you “Activate web server on this module”. See first picture
Next go to “User management” and create your account to give you access into the PLC webserver. We chose to give the account full rights to ensure that it had full access to the various channels on the web server. See second picture
After creating the account itself, we advocated to “User-defined pages”. We created an empty folder on the computer desktop called "333" and then referred to it in the "HTML directory". We then clicked “generate blocks” and created the data block itself for the web server parameters. See the third picture.
The instruction WWW initializes the web server of the CPU or synchronizes user-defined web pages, in short: "user pages", with the user program in the CPU.
Together with the Web server, user web pages make it possible for the CPU to access freely designed web pages of the CPU with a web browser. Use script instructions (such as Javascript) and HTML code in user web pages to transfer data via a web browser for further processing to the CPU and to display data from the operand area of the CPU in the web browser. To synchronize the user program and the Web server, but also to initialize, call the instruction "WWW" in the user program. With the "DataLogWrite" instruction you write a data record into an existing data log. With the ID parameter you select the data log into which the data record is to be written. To create a new data record, the data log must be open. The instruction creates a new data record in the format that was specified in the DATA parameter when the data log was created. Before calling the "DataLogWrite" instruction, transfer the data to the tag that you interconnected at the DATA parameter of the "DataLogCreate" instruction. When the "DataLogWrite" instruction is executed, the transferred data is copied to the data log.
With the "DataLogCreate" instruction you create a data log. The data log is saved on the memory card or in the internal load memory in the directory "\DataLogs". The amount of data that is stored in a data log is dependent on the available space on the memory card or the storage space in the internal load memory of the CPU used. The maximum size of the generated CSV file is 500,000,000 bytes for S7-1200 CPUs, 1,000,000,000 bytes for S7-1500 CPUs. You specify the maximum number of data records that is stored in a data log in the RECORDS parameter. When the specified maximum number of data records in the data log is reached, the oldest data record is overwritten. To avoid overwriting of existing data records, use the "DataLogNewFile" instruction. The instruction is used to create a new data log with the same structure when the number specified at the RECORDS parameter is reached (return value 1 at the STATUS parameter of the "DataLogWrite" instruction). The data records are then saved in the new data log. You specify the name for the data log in the NAME parameter. The data log is created in CSV (Comma Separated Value) format. With the HEADER parameter, you create an (optional) header for the data log. Once the data log is created, it is opened automatically. This means that data can be written.
Guide we followed:
Remember to setup an UDP connection to the IOT module, so you can send data to it. We used this guide:
Attachments
Step 5: Setup and Program the IoT2000
Overview
The IoT2000 serves as a link between the PLC and one of the ESP8266 modules, specifically the one serving as an access point. It communicates with the PLC using a simple UDP-protocol over its Ethernet Port on interface X1. Communication with the ESP-module is achieved through Serial communication on its pins 0 and 1.
Of course, there's a big question of how you program an IoT2000. Well, there are a lot of ways to do it, but the simplest that we have found is to just... Treat it like an Arduino. A big, overly-complicated, very expensive Arduino. It does require a bit of setup to do so.
Setup
In order to achieve our goals with the IoT2000, we need to do the following:
- Enable your Arduino programming IDE to compile to the IoT2000
- Install the drivers for the IoT2000, so your computer can recognize it when it is plugged in
- Open Serial communication on pins 0 and 1
The IoT2000 uses an Intel Galileo chip, which is what we'll be programming. First, we'll install the Intel Galileo as a Board in the Arduino IDE.
- First, open your Arduino IDE.
- Go to the top bar and find Tools.
- In Tools, go to Board > Board Manager
- Find the Intel Galileo in the board manager, using the search-bar.
- Install the board.
Congratulations, you can now write ordinary Arduino code and compile it to a Galileo chip, although be aware that the Galileo may not have the same libraries as the Arduino. The Arduino IDE will simply treat any library imported that the Galileo cannot use as an unknown library, and will fail to compile. So don't worry, you probably won't break anything.
Next we need to install the drivers for the Galileo chip on your computer.
- Which naturally involves downloading them first from this site: https://downloadcenter.intel.com/download/26417/In...
- Unpack the files, naturally.
- Then, use a USB-to-Micro-USB cable to connect to the IOT2000's micro-usb port.
- Your computer will fail to recognize the device as anything more than a USB-connected device. Find it in your Device Manager.
- Select the device, and click Update Driver Software, then choose to find driver software on your computer.
- Navigate to where you unpacked your driver and select it.
This should be all there is to it, but fair warning: On all three laptops involved in the project, this driver successfully installed on none of them. Do not worry, though, as there is a longer, more complex method to force your computer to install the driver whether it wants to or not, but that is significantly beyond the scope of this Instructable. If you have this problem, I suggest the following google searches: "Manually install driver" "Force install driver", and godspeed.
Finally, all there is left is to make sure Serial communication is enabled.
Code
I will not write in great detail about the code here, as it is pasted in full below and has been commented to a mostly readable level. Instead I will limit myself to a general overview of the code, as well as pointing out a few crucial details of the code.
This code really only does one thing: It passes packages along. From its UDP-connection to the PLC it gets four bytes of data (two bytes each for speed and steering), and all it does with those four bytes is pass them along to the Serial connection. Similarly, on the Serial connection, it receives 2 bytes of data - a 2-byte integer for the distance measurement from the robot. All it does with this data is pass it along to the UDP-connection.
It is worth noting that if you put this code in your Arduino IDE, the include for the EthernetUdp library will not change colour to indicate that the library is valid. It is, and the code will not work without it.
It also is worth noting that the Serial communication happens on Serial1, instead of Serial. Serial targets all Serial ports, including the USB-port, whereas Serial1 specifically targets pins 0 and 1. There is, similarly, a Serial2 for communicating on pins 2 and 3.
It is also worth noting that the Serial communication does not work, and is the bane of this project. For some unknown reason - seriously, we have no idea what is wrong despite days of testing and research - the Tx pin (pin 1) seemingly writes full-high or full-low bytes (IE values 0 or 255) at random, nothing in between those values and no connection to the data that is actually being transmitted on Tx. Even when no data is being transmitted on Tx, Tx will still spew out 255's and 0's. It is unknown at this time whether the issue is localized to our particular IoT2000.
Here is the code for the IoT2000:
<p>#include <SPI.h><spi.h><br>#include <Ethernet.h><ethernet.h> #include <EthernetUdp.h><ethernetudp.h></ethernetudp.h></ethernet.h></spi.h></p><p>//Mac Address for UDP-connection. byte mac[] = { 0xE0, 0xDC, 0xA0, 0x1D, 0x55, 0xE3 }; unsigned int localPort = 8888; //UDP port.</p><p>//IP Addresses for the UDP connection IPAddress myIP(192, 168, 200, 1); IPAddress targetIP(192, 168, 200, 10); //PLC IP-address</p><p>const int espPacketSize = 2; //Size of incoming data from esp in bytes const int udpPacketSize = 4; //Size of incoming data from udp in bytes</p><p>byte udpPacketBuffer[udpPacketSize]; //Buffer for holding data received from UDP connection byte espPacketBuffer[espPacketSize]; //Buffer for holding data received from ESP connection</p><p>EthernetUDP Udp;</p><p>//Time variables for restricting test-transmissions to once every second. timeLast is the time of the last transmission, delayTime is how long to wait before transmitting again. long timeLast; long delayTime = 1000;</p><p>void setup() { //Open serial connection and await a connection Serial.begin(9600); Serial1.begin(9600); //Open Ethernet port Serial.println("Start Ethernet connection"); Ethernet.begin(mac,myIP); //Open UDP port Serial.println("Start UDP protocol"); Udp.begin(localPort); Serial.println("Done Setup"); }</p><p>void loop() { //Check for received data on UDP connection, if there is any (>0 bytes received), read the data and write it to the ESP module via Serial connection. if(Udp.parsePacket() > 0) { Serial.print("Received from UDP: "); Udp.read(udpPacketBuffer,udpPacketSize); int spd = word(udpPacketBuffer[0],udpPacketBuffer[1]); int dir = word(udpPacketBuffer[2],udpPacketBuffer[3]); Serial.print(spd); Serial.print(", "); Serial.println(dir); //Serial.write(udpPacketBuffer,udpPacketSize); } //Check for received data on ESP connection, if there is any (>0 bytes received), read the data and write it to the UDP-connected device, via the Ethernet port. if(Serial1.readBytes((char*)espPacketBuffer, espPacketSize) > 0) { //Flip the received word. We don't know why, but the byte we get comes in the wrong order. byte espbuff = espPacketBuffer[0]; espPacketBuffer[0] = espPacketBuffer[1]; espPacketBuffer[1] = espbuff; //Send on UDP (to PLC) Udp.beginPacket(targetIP, localPort); Udp.write(espPacketBuffer, espPacketSize); Udp.endPacket(); //Print to serial monitor Serial.print("Received from ESP: "); int dst = word(espPacketBuffer[0], espPacketBuffer[1]); Serial.println(dst); } </p>
Step 6: Setup and Program the ESP8266 Modules
Overview
There are two ESP8266's in this project. One is attached to the IoT2000, and acts as a WiFi access point. The other is attached to the Arduino connected to the EV3, and connects to the other's WiFi network.
The two modules differ in really only one aspect: That one is an Access Point. They handle the data the same way, sending on Serial whatever they receive on WiFi, and sending on WiFi whatever they receive on Serial. And of course, they expect different packet sizes, since we are transmitting four bytes from the PLC to the EV3, but only two bytes from the EV3 to the PLC.
But before we can program the ESP modules to perform these tasks, they must first be "flashed". This involves setting up a specific temporary circuit, which will allow us to upload code to the ESP8266.
Setup Flash Mode
Before you can program the ESP module, you have to flash it!
Look at the second picture, to see flashing setup. We used the following guide to flash the ESP module:
https://techiesms.com/iot-projects/esp01-projects/...
Before we can actually program the ESP, we have to have the right board installed in our Arduino IDE. This is easily done from the Boards Manager, similar to what we did when installing the Galileo chip for the IoT2000. EXCEPT WITH ONE CRUCIAL DIFFERENCE: The Arduino IDE needs a download link to look for the ESP8266 package, which is not included in the Arduino board manager by default.
To provide this link, go to File > Preferences. There you will find the field "Additional Board Manager URLs:". Add this link:
https://arduino.esp8266.com/stable/package_esp8266...
After that, it really is as simple as finding the ESP8266 in the Board manager and installing it and then setting it as the current board. Once you have done so, you will notice a lot more drop downs below Board. Do not touch any of those. Only pay attention to Board and Port, as usual.
Programming
With the ESP in flash mode, it is now possible to program it. First we will program the Access Point ESP-module, which is the module that is attached to the IoT2000. Its code looks like this. It is a modified WiFi example, hence the copyright notice at the top.
<p>/*<br> Copyright (c) 2015, Majenko Technologies All rights reserved.</p><p> Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:</p><p> * * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.</p><p> * * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.</p><p> * * Neither the name of Majenko Technologies nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.</p><p> THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *</p><p>* Create a WiFi access point and provide a web server on it. */</p><p>#include <ESP8266WiFi.h> #include <WiFiClient.h> #include <WiFiUdp.h></p><p>#ifndef APSSID #define APSSID "RoboIOT" #define APPSK "thereisnospoon" #endif</p><p>const int serialPacketSize = 4; byte serialPacketBuffer[serialPacketSize]; const int wifiPacketSize = 2; byte wifiPacketBuffer[wifiPacketSize]; IPAddress myIP = {192, 168, 1, 1}; IPAddress subnet = {255, 255, 255, 0}; IPAddress targetIP; const int localPort = 8888; //UDP port WiFiUDP Udp;</p><p>/* Set these to your desired credentials. */ const char *ssid = APSSID; const char *password = APPSK;</p><p>void setup() { Serial.begin(9600); Serial.println(); Serial.println("Configuring access point..."); /* You can remove the password parameter if you want the AP to be open. */ WiFi.softAPConfig(myIP, myIP, subnet); WiFi.softAP(ssid, password); </p><p> myIP = WiFi.softAPIP(); Serial.print("AP IP address: "); Serial.println(myIP); targetIP = myIP; targetIP[3] = 2; Serial.println("Start UDP..."); Udp.begin(localPort); Serial.println("Setup complete."); }</p><p>void loop() { /* //Check for available Serial data and write it to the buffer if(Serial.readBytes(serialPacketBuffer, serialPacketSize) > 0); { //Broadcast Serial data. Udp.beginPacket(targetIP, localPort); Udp.write(serialPacketBuffer, serialPacketSize); Udp.endPacket(); } */ //Check for available WiFi data and write it to the buffer if(Udp.parsePacket() > 0) { Udp.read(wifiPacketBuffer, wifiPacketSize); Serial.write(wifiPacketBuffer, wifiPacketSize); } }</p>
Like the IoT, the code primarily just consists of routing between two different connections, this time between a WiFi-UDP connection and the Serial connection. Beyond that, there is of course some setup code for the WiFi network. There is not much more to say about it, you can pretty much just copy-paste the code, move some things around and replace variables through trial and error if you want yours to do something slightly differently. Heck, that is exactly what we did to arrive at the above (and below) code.
So, now it is time to unplug this ESP8266 module and replace it with the other module - the one for the WiFi Client. Although, you may want to replace the network SSID and Security Key to something else.
<p>#include <ESP8266WiFi.h> #include <WiFiClient.h> #include <WiFiUdp.h></p><p>#ifndef STASSID #define STASSID "RoboIOT" #define STAPSK "thereisnospoon" #endif</p><p>const int serialPacketSize = 2; byte serialPacketBuffer[serialPacketSize]; const int wifiPacketSize = 4; byte wifiPacketBuffer[wifiPacketSize]; IPAddress targetIP; const int localPort = 8888; //UDP port WiFiUDP Udp;</p><p>const char* ssid = STASSID; const char* password = STAPSK;</p><p>///const char* host = "djxmmx.net"; ///const uint16_t port = 17;</p><p>void setup() { Serial.begin(115200);</p><p> // We start by connecting to a WiFi network</p><p> Serial.println(); Serial.println(); Serial.print("Connecting to "); Serial.println(ssid);</p><p> /* Explicitly set the ESP8266 to be a WiFi-client, otherwise, it by default, would try to act as both a client and an access-point and could cause network-issues with your other WiFi-devices on your WiFi-network. */ WiFi.mode(WIFI_STA); WiFi.begin(ssid, password); IPAddress statGateway = {192, 168, 1, 1}; IPAddress statIP = statGateway; statIP[3] = 2; IPAddress statSubnet = {255, 255, 255, 0}; WiFi.config(statIP, statGateway, statSubnet); while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); } Udp.begin(localPort); Serial.println(""); Serial.println("WiFi connected"); Serial.println("IP address: "); Serial.println(WiFi.localIP()); targetIP = WiFi.localIP(); targetIP[3] = 1; } void loop() { //Check for available Serial data and write it to the buffer if(Serial.readBytes(serialPacketBuffer, serialPacketSize) > 0); { //Broadcast Serial data. Udp.beginPacket(targetIP, localPort); Udp.write(serialPacketBuffer, serialPacketSize); Udp.endPacket(); } //Check for available WiFi data and write it to the buffer if(Udp.parsePacket() > 0) { Udp.read(wifiPacketBuffer, wifiPacketSize); Serial.write(wifiPacketBuffer, wifiPacketSize); } }</p>
And as you may notice, this code is almost exactly the same as that of the WiFi Access Point, with the exception of course of having replaced the network setup-code with code for connection to the existing network. Remember to change the SSID and Security Key for the network if you are not using the same network ID and security as we are.
Setup Normal Mode
With the ESP-modules programmed, it is time to connect them as in their normal mode. Look at the third picture to see the wiring for the normal setup. Note that when Flashing the device we connected Rx to Rx and Tx to Tx. That is not the case in normal mode. Here we want Rx to Tx and Tx to Rx.
And remember to remove the Reset-to-ground connection from the Arduino.
Step 7: Setup and Program the Arduino
In this chapter we have put all the code for the arduino that is connected to the EV3 and Wifi module on one side and the IOT module that also is connected to another wifi module.
The EV3_Write_Final.ino need to be uploaded to the arduino mega that is connected to Lego Mindstorm EV3. The code is explained in the comments inside the code.
The IOTUDP.ino need to be uploaded on the Siemens IOT Module. The code is explained in the comments inside the code. Remeber to change mac and ip adress (last thing is only needed if you changed the ip adress).
The WifuAP.ino needs to go on the wifi module connected to the IOT. The code is explained in the comments inside the code. Remeber to setup the SSID and Password you would like to the acess point.
The wifuClient.ino need to go on the wifi module connected to the arduino at the EV3. The code is explained in the comments inside the code. Remember if you have changed the SSID and password in the Acess point, you also need to make the same changes in the Client, otherwise they wont connect.
Step 8: Setup and Program the EV3
For the Lego Mindstorm setup you need some extra programmering blocks to transfer data the data from the mindstorm to the arduino. We used this guide to setup the correct wiring and download the extra programmering blocks:
https://www.dexterindustries.com/howto/connecting-...
In the mindstorm software we used the block called I2C, both the read and write block, since we need a variable for the motors (read from arduino) and a variable for the distance sensor (write to arduino).
Attachments
Step 9: Conclusion & Result
So, if you have followed all instructions, you should have the same thing we have now:
An Ev3 robot that drives around measuring distances, which transmits those distances to the PLC via several devices, and which is in turn remote controlled from the PLC. A triumph of Cross-Platform-Integration, achieving communication between five unique programmable devices, seamlessly and smoothly communicating with each other.
Except, of course, that you, like us, probably do not have that. Sure the EV3 will drive around and measure things, but it is not remote controlled - and it is not (only) because of the code that bypasses the communication and just makes the EV3 drive around manually. It is because the connection breaks at a critical point: The Serial output from the IoT2000 is putting out extreme values seemingly at random on its Serial connection. It reads fine on Serial, and all other communications - the Ethernet connection, the WiFi connection, the I2C connection, they all work smoothly. But for some unknown reason the IoT can only send gibberish on its Serial connection, even while it receives normally.
Why does it do this? We have no idea. After about 40 man-hours of testing and research we still have no idea, and the limited official support and documentation available for the IoT2000 offers no salvation, either. For all we know, our model is just broken. If your setup is working flawlessly then it is likely that our IoT2000 is just broken.
All hope is not lost, though, you can enable an I2C connection on the IoT2000's pins A4 and A5. We did not try that due to the approaching deadline, but you can always try it if you want. Let us know if that works out better for you.
Anyway, that is all she wrote for this one. Enjoy.