Hackster is hosting Hackster Holidays, Ep. 5: Livestream & Giveaway Drawing. Watch previous episodes or stream live on Friday!Stream Hackster Holidays, Ep. 5 on Friday!
Timothy Malche
Published © MIT

Smart Shipment with TinyML

Developing a TinyML solution for the Shipping Industry that allows users to track the status of a shipment/package in real time.

IntermediateFull instructions provided5 hours2,515

Things used in this project

Hardware components

AWS IoT EduKit
Amazon Web Services AWS IoT EduKit
×1

Software apps and online services

Arduino IDE
Arduino IDE
Neuton
Neuton Tiny ML Neuton

Story

Read more

Schematics

Project Workflow

Images for Web App

Code

Smart Shipment Data Collection Firmware (Arduino Code)

Arduino
#include <M5Core2.h>

float accX = 0.0F;
float accY = 0.0F;
float accZ = 0.0F;

float gyroX = 0.0F;
float gyroY = 0.0F;
float gyroZ = 0.0F;

int times = 0;

// the setup routine runs once when M5Stack starts up
void setup(){
  // Initialize the M5Stack object
  M5.begin();
  M5.IMU.Init();
  M5.Lcd.fillScreen(BLACK);
  M5.Lcd.setTextColor(GREEN , BLACK);
  M5.Lcd.setTextSize(2);
}

// the loop routine runs over and over again forever
void loop() {

  
  // put your main code here, to run repeatedly:
  M5.IMU.getGyroData(&gyroX,&gyroY,&gyroZ);
  M5.IMU.getAccelData(&accX,&accY,&accZ);
  /*M5.IMU.getAhrsData(&pitch,&roll,&yaw);
  M5.IMU.getTempData(&temp);*/
  if(times<=10000){
    Serial.print(accX);
    Serial.print(",");
    Serial.print(accY);
    Serial.print(",");
    Serial.print(accZ);
    Serial.print(",");
   Serial.print(gyroX);
    Serial.print(",");
    Serial.print(gyroY);
    Serial.print(",");
    Serial.print(gyroZ);
    Serial.println();
  }
  
  M5.Lcd.setCursor(0, 20);
  M5.Lcd.printf("%6.2f  %6.2f  %6.2f      ", gyroX, gyroY, gyroZ);
  M5.Lcd.setCursor(220, 42);
  M5.Lcd.print(" o/s");
  M5.Lcd.setCursor(0, 65);
  M5.Lcd.printf(" %5.2f   %5.2f   %5.2f   ", accX, accY, accZ);
  M5.Lcd.setCursor(220, 87);
  M5.Lcd.print(" G");
 
  delay(20);
  times+=20;
}

Smart Shipment Web App

HTML
<html>
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/paho-mqtt/1.0.1/mqttws31.min.js" type="text/javascript"></script>
<style>
body{
	margin-left:100px;
	margin-top:20px;
}
div.polaroid {
  width: 250px;
  box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2), 0 6px 20px 0 rgba(0, 0, 0, 0.19);
  text-align: center;
  background-color:#FFFFFF;
}

div.container {
  padding: 10px;
}
</style>
</head>
<body bgcolor="#363D45">

<h2 style="color:#FFF">Smart Shipment </h2>
<div class="polaroid">

  <img id="statusimg" src="img/loading.png" alt="AISpark" style="width:80%">
  
  <div class="container">
  </div>
</div>


<script type="text/javascript">
// Create a client instance



client = new Paho.MQTT.Client("broker.hivemq.com", 8000 ,"smart_shipment_2");

// set callback handlers
client.onConnectionLost = onConnectionLost;
client.onMessageArrived = onMessageArrived;

// connect the client
client.connect({onSuccess:onConnect});


// called when the client connects
function onConnect() {
  // Once a connection has been made, make a subscription and send a message.
console.log("onConnect");
 client.subscribe("status");
  
}

// called when the client loses its connection
function onConnectionLost(responseObject) {
  if (responseObject.errorCode !== 0) {
    console.log("onConnectionLost:"+responseObject.errorMessage);
  }
}

  function doFail(e){
    console.log(e);
  }

// called when a message arrives
function onMessageArrived(message) {
  console.log("onMessageArrived:" + message.payloadString);
  document.getElementById("statusimg").src = "img/" + message.payloadString + ".png";
}

</script>
</body>
</html>

Smart Shipment Firmware (Arduino Code)

Arduino
#include <M5Core2.h>
#include <string.h>
#include <PubSubClient.h>
#include <WiFi.h>
#include "src/neuton.h"

float accX = 0.0F;
float accY = 0.0F;
float accZ = 0.0F;

float gyroX = 0.0F;
float gyroY = 0.0F;
float gyroZ = 0.0F;

const char* ssid = "YOUR_SSID";
const char* password = "YOUR_PWD";

//The broker and port are provided by http://www.mqttdashboard.com/
char *mqttServer = "broker.hivemq.com";
int mqttPort = 1883;

//Replace these 3 with the strings of your choice
const char* mqtt_client_name = "smart_shipment_1";
const char* mqtt_pub_topic = "status"; //The topic to which our client will publish


WiFiClient client;
PubSubClient mqttClient(client);

// the setup routine runs once when M5Stack starts up
void setup(){

 
  // Initialize the M5Stack object
  M5.begin();
  M5.IMU.Init();
  M5.Lcd.fillScreen(BLACK);
  M5.Lcd.setTextColor(GREEN , BLACK);
  M5.Lcd.setTextSize(2);

  Serial.begin(115200);
  WiFi.mode(WIFI_STA);                    //The WiFi is in station mode
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
      delay(500);
      Serial.print(".");
   }
  Serial.println("");  Serial.print("WiFi connected to: "); Serial.println(ssid);  Serial.println("IP address: ");     Serial.println(WiFi.localIP());
  delay(2000);
  mqttClient.setServer(mqttServer, mqttPort);

}

void send_data(char status[]){
  if (!mqttClient.connected()){
      while (!mqttClient.connected()){
         if(mqttClient.connect(mqtt_client_name)){
            Serial.println("MQTT Connected!");
            //mqttClient.subscribe(mqtt_sub_topic);
         }
         else{
            Serial.print(".");
         }
      }
   }
   mqttClient.publish(mqtt_pub_topic, status);
   Serial.println("Message published");
   mqttClient.loop();
}

// the loop routine runs over and over again forever
void loop() {

  
    // put your main code here, to run repeatedly:
  M5.IMU.getGyroData(&gyroX,&gyroY,&gyroZ);
  M5.IMU.getAccelData(&accX,&accY,&accZ);

  float inputs[] = { accX, accY, accZ, gyroX, gyroY, gyroZ};

   if (neuton_model_set_inputs(inputs) == 0)
   {

      uint16_t predictedClass;
      float* probabilities;
      char pclass[50];
                if (neuton_model_run_inference(&predictedClass, &probabilities) == 0)
                {
                    
                     if ((probabilities[predictedClass] > 0.6))
                    {
                      Serial.print(predictedClass);
                      if(predictedClass==0){
                        strcpy(pclass, "Stationary");
                      }
                      if(predictedClass==1){
                      
                        strcpy(pclass, "Moving");
                      }
                      if(predictedClass==2){
                        M5.Lcd.fillScreen(BLACK);
                        strcpy(pclass, "Picked");
                      }
                      if(predictedClass==3){
                        M5.Lcd.fillScreen(BLACK);
                        strcpy(pclass, "Wrong");
                     }
                     if(predictedClass==4){
                         M5.Lcd.fillScreen(BLACK);
                         strcpy(pclass, "Thrown");
                     }
                      Serial.print("  probability: ");
                      Serial.print(probabilities[predictedClass] * 100.0, 0);
                      Serial.println('%');

                      M5.Lcd.setCursor(0, 20);
                      M5.Lcd.printf("Class: %s %d ", pclass, predictedClass);
                      M5.Lcd.setCursor(0, 65);
                      M5.Lcd.printf("Model Accuracy: %.2f", probabilities[predictedClass] * 100.0);
                      send_data(pclass);
                      
                      
                    }
                }
      }
   delay(20);
}

Credits

Timothy Malche

Timothy Malche

17 projects • 22 followers
Maker, Educator, Researcher

Comments