Student project, Faculty of Electrical Engineering, University of Belgrade

Dependencies:   SSD1308_128x64_I2C Adafruit_GFX 19E042PIM_MB_PINS

Revision:
2:4c2c7c8d608b
Parent:
1:c994530bdb3d
--- a/main.cpp	Sat Nov 27 20:33:49 2021 +0000
+++ b/main.cpp	Wed Jul 13 15:07:00 2022 +0000
@@ -1,58 +1,103 @@
 /*
- * Program implements MQTT client on a NUCLEO-L476RG board
- * using arm mbed-mqtt library and ESP-WROOM-02 WiFi modem.
- *
- * University of Belgrade - School of Electrical Engineering
- * Department of Electronics
- * Bulevar Kralja Aleksandra 73, 11120 Belgrade, Serbia
- *
- * November 2021.
- *
- */
+
+This code implements MQTT broker for Smart Industry system.
+The system sorts plastic caps based on their color (red, green or blue). 
+Proximity sensors detect the presence of the cup, color sensor determines the color and
+servo motors drive the sorting mechanism.
+
+Faculty of Electrical Engineering, University of Belgrade.
+Version (1), July 2022.
+
+*/
+
+// Include the libraries
 
 #include "mbed.h"
 #include "mb_pins.h"
 #include "platform/mbed_thread.h"
 #include "MQTTClientMbedOs.h"
-
+#include "SSD1308.h"
+#include "Adafruit_GFX.h"
+#include "Adafruit_GFX_Config.h"
+#include "Adafruit_SSD1306.h"
 
-// LED2 blinking rate:
-#define BLINKING_RATE_MS                                                     250
-// Scaler to 3v3L
-#define VOLTAGE_SCALER                                                      3.3f
-// Client yield timeout in miliseconds:
+// I2C bus pins
+#define D_SDA                  PB_14 
+#define D_SCL                  PB_13
+     
+// I2C address, 60d or 0x3c
+#define I2C_REAL_ADD                                                        0x3c
+#define I2C_ADDRESS                                            I2C_REAL_ADD << 1
+#define I2C_FREQUENCY                                                     400000
+
+// Client yield timeout in miliseconds
 #define YIELD_TIMEOUT_MS                                                    1000
-// Maximum number of networks to scan for:
-#define MAX_NETWORKS                                                          15
-// Small delay for network information printing:
+
+// Maximum number of networks to scan for
+#define MAX_NETWORKS                                                          10
+
+// Small delay for network information printing
 #define PRINTF_DELAY_MS                                                       10
 
+// Set OLED width and heigth [pixel]
+#define OLED_WIDTH_PX                                                        128
+#define OLED_HEIGHT_PX                                                        64
 
-// Left potentiometer:
-AnalogIn pot1(MB_POT1);
-// Left button on the motherboard:
-InterruptIn sw1(MB_SW1);
-// Right LED on the motherboard:
-DigitalOut led2(MB_LED2);
-// Pointer to a WiFi network object:
+// Initialize I2C for OLED display
+I2C i2c(D_SDA, D_SCL);
+
+// Initialize OLED
+Adafruit_SSD1306_I2c myOled(i2c,PB_5,I2C_ADDRESS,OLED_HEIGHT_PX,OLED_WIDTH_PX);
+
+// Variables that count the number of caps for every color
+int red;
+int green;
+int blue;
+
+// Variables used in broker decision algorithm
+int flagColor = 0;
+int flagProx1 = 0;
+int flagProx2 = 0;
+int flagStage1 = 1;
+int flagStage2 = 1;
+int notAvailable = 0;
+int poximityTreshold1 = 300;
+int poximityTreshold2 = 280;
+int currentColor = 0;
+
+// Define start button
+DigitalIn buttonStart(MB_SW1); 
+int flagStart = 0;
+
+// Pointer to a WiFi network object
 WiFiInterface *wifi;
-// Creating TCP socket:
+
+// Creating TCP socket
 TCPSocket socket;
-// Creating MQTT client using the TCP socket;
+
+// Creating MQTT client using the TCP socket
 MQTTClient client(&socket);
-// Message handler:
+
+// Message handler
 MQTT::Message message;
 
-char* topic = "mbed-sample-pub";
-char* topic_sub = "mbed-sample-sub";
-// Counter of arrived messages:
+// MQTT topics
+char* topic_pub_servo1 = "PMK_industry/micro/servo1";
+char* topic_pub_servo2 = "PMK_industry/micro/servo2";
+char* topic_sub_color = "PMK_industry/micro/color";
+char* topic_sub_proximity1 = "PMK_industry/micro/proximity1";
+char* topic_sub_proximity2 = "PMK_industry/micro/proximity2";
+
+char* receavedMessage;
+
+// Counter of arrived messages
 int arrivedcount = 0;
-// Flag indicating that button is not pressed:
-int button_pressed=0;
-// HiveMQ broker connectivity information:
+
+// HiveMQ broker connectivity information
 const char* hostname = "broker.hivemq.com";
 int port = 1883;
-// Returning a string for a provided network encryption: 
+
+// Returning a string for a provided network encryption
 const char *sec2str(nsapi_security_t sec)
 {
     switch (sec) 
@@ -73,12 +118,14 @@
     }
 }
 
+// Scan available WiFi networks
 int scan_networks(WiFiInterface *wifi)
 {
     printf("Scan:\n");
     
-    // Scan only for the number of networks, first parameter is NULL:
+    // Scan only for the number of networks, first parameter is NULL
     int count = wifi->scan(NULL, 0);
+    
     // If there are no networks, count == 0, if there is an error, counter < 0:
     if (count <= 0)
     {
@@ -86,22 +133,23 @@
         return 0;
     }
 
-    // Limit number of network arbitrary to some reasonable number:
+    // Limit number of network arbitrary to some reasonable number
     count = count < MAX_NETWORKS ? count : MAX_NETWORKS;
     
-    // Create a local pointer to an object, which is an array of WiFi APs:
+    // Create a local pointer to an object, which is an array of WiFi APs
     WiFiAccessPoint *ap = new WiFiAccessPoint[count];
-    // Now scan again for 'count' networks and populate the array of APs:
+    
+    // Now scan again for 'count' networks and populate the array of APs
     count = wifi->scan(ap, count);
     
-    // This time, the number of entries to 'ap' is returned:
+    // This time, the number of entries to 'ap' is returned
     if (count <= 0) 
     {
         printf("scan() failed with return value: %d\n", count);
         return 0;
     }
     
-    // Print out the parameters of each AP:
+    // Print out the parameters of each AP
     for (int i = 0; i < count; i++) 
     {
         printf("Network: %s secured: %s BSSID: %hhX:%hhX:%hhX:%hhx:%hhx:%hhx RSSI: %hhd Ch: %hhd\n", ap[i].get_ssid(),
@@ -117,25 +165,45 @@
     return count;
 }
 
-void messageArrived(MQTT::MessageData& md)
+// MQTT message handlers for certain topics
+void messageArrivedColor(MQTT::MessageData& md)
+{
+    MQTT::Message &message = md.message;
+    receavedMessage = (char*)message.payload;
+    
+    if (strcmp(receavedMessage,"Red") == 0 ){ flagColor = 1; }
+    else if (strcmp(receavedMessage,"Green") == 0 ) { flagColor = 2; }
+    else if (strcmp(receavedMessage, "Blue") == 0 ) { flagColor = 3; }
+    printf("Color: %.*s\r\n", message.payloadlen, (char*)message.payload);
+    
+}
+
+void messageArrivedProximity1(MQTT::MessageData& md)
 {
     MQTT::Message &message = md.message;
-    //printf("Message arrived: qos %d, retained %d, dup %d, packetid %d\r\n", message.qos, message.retained, message.dup, message.id);
-    printf("Message from the browser: %.*s\r\n", message.payloadlen, (char*)message.payload);
-    ++arrivedcount;
+    int receavedMessage = atoi((char*)message.payload);
+
+    if (receavedMessage > poximityTreshold1){ flagProx1 = 1;}
+    else { flagProx1 = 0;}
+    printf("Prox1 = %d\t", receavedMessage);
+    printf("flag = %d\r\n", flagProx1);
+    
 }
 
-void buttonFunction() {
+void messageArrivedProximity2(MQTT::MessageData& md)
+{
+    MQTT::Message &message = md.message;
+    int receavedMessage = atoi((char*)message.payload);
     
-    button_pressed=1;
-   
+    if (receavedMessage > poximityTreshold2){ flagProx2 = 1;}
+    else { flagProx2 = 0;}
+    printf("Prox2 = %d\t", receavedMessage);
+    printf("flag = %d\r\n", flagProx2);
+    
 }
 
 int main()
 {
-    // Set the interrupt event:
-    sw1.fall(&buttonFunction); 
-    
     // Create a default network interface:
     wifi = WiFiInterface::get_default_instance();
     if (!wifi) {
@@ -168,39 +236,192 @@
     
     // Open TCP socket using WiFi network interface:
     socket.open(wifi);
+    
     // Connect to the HiveMQ broker:
     socket.connect(hostname, port);
+    
     // Fill connect data with default values:
     MQTTPacket_connectData data = MQTTPacket_connectData_initializer;
+    
     // Change only ID and protocol version:
     data.MQTTVersion = 3;
-    data.clientID.cstring = "NUCLEO-L476RG-60";
+    data.clientID.cstring = "Broker";
     
-    // Connect the 
+    // Connect to the mqtt broker
     int rc = 0;
     if ((rc = client.connect(data)) != 0)
         printf("rc from MQTT connect is %d\r\n", rc);
 
-    if ((rc = client.subscribe(topic_sub, MQTT::QOS2, messageArrived)) != 0)
+    // Subscribe to topics
+    if ((rc = client.subscribe(topic_sub_color, MQTT::QOS2, messageArrivedColor)) != 0)
+        printf("rc from MQTT subscribe is %d\r\n", rc);
+        
+    if ((rc = client.subscribe(topic_sub_proximity1, MQTT::QOS2, messageArrivedProximity1)) != 0)
+        printf("rc from MQTT subscribe is %d\r\n", rc);
+        
+    if ((rc = client.subscribe(topic_sub_proximity2, MQTT::QOS2, messageArrivedProximity2)) != 0)
         printf("rc from MQTT subscribe is %d\r\n", rc);
-      
+    
+    red = 0;
+    green = 0;
+    blue = 0;
+    
+    char bufRed[15];   
+    char bufGreen[15];
+    char bufBlue[15];
+    
+    myOled.begin(); 
+    myOled.setTextSize(2);
+    myOled.setTextColor(WHITE);
+    myOled.setTextCursor(25,0);
+    myOled.printf("Press");
+    myOled.setTextCursor(25,25);
+    myOled.printf("START");
+    myOled.display();
+ 
     while (true) {
-        // Show that the loop is running by switching motherboard LED2:
-        led2 = !led2;
-        thread_sleep_for(BLINKING_RATE_MS);
-        if (button_pressed==1) {
-            button_pressed=0;      
-            // QoS 0
-            char buf[100];
-            sprintf(buf, "V(POT1) = %1.2f\r\n", pot1*VOLTAGE_SCALER);
-            message.qos = MQTT::QOS0;
-            message.retained = false;
-            message.dup = false;
-            message.payload = (void*)buf;
-            message.payloadlen = strlen(buf)+1;
-            client.publish(topic, message);
+        
+        if (!flagStart){
+        flagStart = !buttonStart;
+        thread_sleep_for(50);
+        
         }
-        // Need to call yield API to maintain connection:
-        client.yield(YIELD_TIMEOUT_MS);
+        
+        if (flagStart) {
+        
+        sprintf(bufRed, "%s %d", "Red:", red);
+        sprintf(bufGreen, "%s %d", "Green:", green);
+        sprintf(bufBlue, "%s %d", "Blue:", blue);
+        
+        myOled.clearDisplay();
+        myOled.setTextSize(2);
+        myOled.setTextColor(WHITE);
+        myOled.setTextCursor(0,0);
+        myOled.printf(bufRed);
+        myOled.setTextCursor(0,25);
+        myOled.printf(bufGreen);
+        myOled.setTextCursor(0,50);
+        myOled.printf(bufBlue);
+        myOled.display();
+        
+        // If a cap is detected at the first stage, send a command
+        // for servo1 based on the color of the cap
+        if(flagStage1 && flagProx1)
+        {
+            
+            if (flagColor == 1)
+            {
+                char buf[100];
+                sprintf(buf, "right");
+                message.qos = MQTT::QOS0;
+                message.retained = false;
+                message.dup = false;
+                message.payload = (void*)buf;
+                message.payloadlen = strlen(buf)+1;
+                client.publish(topic_pub_servo1, message);
+                flagStage1 = 0;
+                red++;
+                
+                }
+                
+                else if (flagColor == 2)
+            {
+                char buf[100];
+                sprintf(buf, "left");
+                message.qos = MQTT::QOS0;
+                message.retained = false;
+                message.dup = false;
+                message.payload = (void*)buf;
+                message.payloadlen = strlen(buf)+1;
+                client.publish(topic_pub_servo1, message);
+                flagStage1 = 0;
+                green++;
+                
+                }
+                
+                else if (flagColor == 3)
+            {
+                char buf[100];
+                sprintf(buf, "left");
+                message.qos = MQTT::QOS0;
+                message.retained = false;
+                message.dup = false;
+                message.payload = (void*)buf;
+                message.payloadlen = strlen(buf)+1;
+                client.publish(topic_pub_servo1, message);
+                flagStage1 = 0;
+                blue++;
+                
+                }
+                
+                currentColor = flagColor;
+            }
+        
+            else if(!flagStage1 && !flagProx1)
+            {
+                char buf[100];
+                sprintf(buf, "zero");
+                message.qos = MQTT::QOS0;
+                message.retained = false;
+                message.dup = false;
+                message.payload = (void*)buf;
+                message.payloadlen = strlen(buf)+1;
+                client.publish(topic_pub_servo1, message);
+                flagStage1 = 1;
+                
+                }
+        
+        // If a cap is detected at the second stage, send a command
+        // for servo2 based on the color of the cap
+        if(flagStage2 && flagProx2)
+        {
+            
+            if (currentColor == 2)
+            {
+                char buf[100];
+                sprintf(buf, "right");
+                message.qos = MQTT::QOS0;
+                message.retained = false;
+                message.dup = false;
+                message.payload = (void*)buf;
+                message.payloadlen = strlen(buf)+1;
+                client.publish(topic_pub_servo2, message);
+                flagStage2 = 0;
+                
+                }
+                
+                else if (currentColor  == 3)
+            {
+                char buf[100];
+                sprintf(buf, "left");
+                message.qos = MQTT::QOS0;
+                message.retained = false;
+                message.dup = false;
+                message.payload = (void*)buf;
+                message.payloadlen = strlen(buf)+1;
+                client.publish(topic_pub_servo2, message);
+                flagStage2 = 0;
+                
+                }
+                
+            }
+        
+            else if(!flagStage2 && !flagProx2)
+            {
+                char buf[100];
+                sprintf(buf, "zero");
+                message.qos = MQTT::QOS0;
+                message.retained = false;
+                message.dup = false;
+                message.payload = (void*)buf;
+                message.payloadlen = strlen(buf)+1;
+                client.publish(topic_pub_servo2, message);
+                flagStage2 = 1;
+                currentColor = 0;
+                
+                }
+                
+        client.yield(YIELD_TIMEOUT_MS); // Need to call yield API to maintain connection
+    }
     }
 }
\ No newline at end of file