Many carts are lost each year because people steal them.For the stores it represent a huge money loss.Indeed, a cart is worth 150 - 340 Euros.
As part of our third year of engineering school in Unilasalle Amiens (ex ESIEE), in the RIOC (Réseaux Informatiques et Objets Connectés) section, we decided to create a connected cart as part of our IOT/LPWAN Project
It's an 50 hours project
We were imposed to use LoRa technologie for implementing our connected object.
It also requiered some software (React, Node, MySQL) and modeling (OnShape) skills for the creation of this projet.
Objectives of the projectThe objectives of our project is to prevent thief to steal hypermarket cart and optimizing the cart functionement.
We can do it by installing :
- A GPS Antenna in our cart to locate it.
- An RFID Card Reader to unlock the cart using fidelity card of the client.
- Also, the cart is locked by an electromagnetic valve which is unlock by the fidelity card.
We chose to use the LoRaWAN protocol to ensure the communication between our connected car and the React application dashboard.
We decided to use this protocol for several reasons :
- First, because it's a long range protocol which is useful for GPS Tracking.(8-11 km)
- Also, our connected cart don't need to receive frames continuously.
- Finally,it doesn't require a lot of energy which is good for maintenance.
Our module is split in 2 component.
The GPS part which allow us to locate our cart.The other part allow us to use RFID and the Electromagnet.
In our module, the GPS location is handle by a GPS Antenna which allow us to get the latitude and longitude coordinates.
The GPS is connected to our Arduino UNO through a GPS Shield.The GPS Antenna is connected to our Arduino UNO.It send coordinate into it.
Once the Arduino UNO receive the coordinates, we send them through TTN.
To send the data through TTN we convert it to bytes which fit to the requiered format. (uintf8_t)
CodeoftheArduinoUNO
#include <lmic.h>
#include <hal/hal.h>
#include <SPI.h>
#include <SoftwareSerial.h>
#include <TinyGPS++.h>
// 82 67 C6 E2 1B E9 43 9D D3 F7 44 F0 E6 F7 A6 8C
static const PROGMEM u1_t NWKSKEY[16] = { 0x82, 0x67, 0xC6, 0xE2, 0x1B, 0xE9, 0x43, 0x9D, 0xD3, 0xF7, 0x44, 0xF0, 0xE6, 0xF7, 0xA6, 0x8C };
// 0x04, 0x58, 0x09, 0x5D, 0x21, 0xD8, 0x63, 0x3F, 0x3D, 0xAE, 0xF1, 0x13, 0x73, 0x1A, 0x99, 0x70
static const u1_t PROGMEM APPSKEY[16] = { 0x04, 0x58, 0x09, 0x5D, 0x21, 0xD8, 0x63, 0x3F, 0x3D, 0xAE, 0xF1, 0x13, 0x73, 0x1A, 0x99, 0x70 };
// 260B3CF7
static const u4_t DEVADDR = 0x260B3CF7;
// Function to send char to The Things Network
static const int RXPin = 0, TXPin = 1;
static const uint32_t GPSBaud = 9600;
// The TinyGPS++ object
TinyGPSPlus gps;
// The serial connection to the GPS device
SoftwareSerial ss(RXPin, TXPin);
// These callbacks are only used in over-the-air activation, so they are
// left empty here (we cannot leave them out completely unless
// DISABLE_JOIN is set in config.h, otherwise the linker will complain).
void os_getArtEui (u1_t* buf) { }
void os_getDevEui (u1_t* buf) { }
void os_getDevKey (u1_t* buf) { }
// static uint8_t mydata[100]
static uint8_t mydata[] = {0,0,0,0,0,0,0,0,0,0,0};
static osjob_t initjob,sendjob,blinkjob;
// Schedule TX every this many seconds (might become longer due to duty
// cycle limitations).
const unsigned TX_INTERVAL = 3;
// Pin mapping
const lmic_pinmap lmic_pins = {
.nss = 10,
.rxtx = LMIC_UNUSED_PIN,
.rst = 9,
.dio = {2, 6, 7},
};
void onEvent (ev_t ev) {
// Serial.print(os_getTime());
// Serial.print(": ");
switch(ev) {
case EV_SCAN_TIMEOUT:
Serial.println(F("EV_SCAN_TIMEOUT"));
break;
case EV_BEACON_FOUND:
Serial.println(F("EV_BEACON_FOUND"));
break;
case EV_BEACON_MISSED:
Serial.println(F("EV_BEACON_MISSED"));
break;
case EV_BEACON_TRACKED:
Serial.println(F("EV_BEACON_TRACKED"));
break;
case EV_JOINING:
Serial.println(F("EV_JOINING"));
break;
case EV_JOINED:
Serial.println(F("EV_JOINED"));
break;
case EV_RFU1:
Serial.println(F("EV_RFU1"));
break;
case EV_JOIN_FAILED:
Serial.println(F("EV_JOIN_FAILED"));
break;
case EV_REJOIN_FAILED:
Serial.println(F("EV_REJOIN_FAILED"));
break;
case EV_TXCOMPLETE:
// Serial.println(F("EV_TXCOMPLETE (includes waiting for RX windows)"));
if (LMIC.txrxFlags & TXRX_ACK)
// Serial.println(F("Received ack"));
if (LMIC.dataLen) {
// Serial.println(F("Received "));
// Serial.println(LMIC.dataLen);
// Serial.println(F(" bytes of payload"));
}
// Schedule next transmission
os_setTimedCallback(&sendjob, os_getTime()+sec2osticks(TX_INTERVAL), do_send);
// Serial.println("EV_TXCOMPLETE (includes waiting for RX windows)");
// if(LMIC.dataLen) {
// // data received in rx slot after tx
// Serial.print("Data Received: ");
// Serial.write(LMIC.frame+LMIC.dataBeg, LMIC.dataLen);
// Serial.println();
// }
// // Schedule next transmission
// os_setTimedCallback(&sendjob, os_getTime()+sec2osticks(TX_INTERVAL), do_send);
break;
case EV_LOST_TSYNC:
Serial.println(F("EV_LOST_TSYNC"));
break;
case EV_RESET:
Serial.println(F("EV_RESET"));
break;
case EV_RXCOMPLETE:
// data received in ping slot
Serial.println(F("EV_RXCOMPLETE"));
break;
case EV_LINK_DEAD:
Serial.println(F("EV_LINK_DEAD"));
break;
case EV_LINK_ALIVE:
Serial.println(F("EV_LINK_ALIVE"));
break;
default:
Serial.println(F("Unknown event"));
break;
}
}
void do_send(osjob_t* j){
if (LMIC.opmode & OP_TXRXPEND) {
Serial.println(F("OP_TXRXPEND, not sending"));
} else {
//mydata[0]=0;
LMIC_setTxData2(1, mydata, sizeof(mydata)-1, 0);
}
}
const int inPin = 8;
int val = 0;
void setup() {
pinMode(inPin,INPUT);
Serial.begin(9600);
ss.begin(GPSBaud);
while(!Serial);
Serial.println("Starting");
#ifdef VCC_ENABLE
// For Pinoccio Scout boards
pinMode(VCC_ENABLE, OUTPUT);
digitalWrite(VCC_ENABLE, HIGH);
delay(1000);
#endif
// LMIC init
os_init();
// Reset the MAC state. Session and pending data transfers will be discarded.
LMIC_reset();
//LMIC_setClockError(MAX_CLOCK_ERROR * 1/100);
// Set static session parameters. Instead of dynamically establishing a session
// by joining the network, precomputed session parameters are be provided.
#ifdef PROGMEM
// On AVR, these values are stored in flash and only copied to RAM
// once. Copy them to a temporary buffer here, LMIC_setSession will
// copy them into a buffer of its own again.
uint8_t appskey[sizeof(APPSKEY)];
uint8_t nwkskey[sizeof(NWKSKEY)];
memcpy_P(appskey, APPSKEY, sizeof(APPSKEY));
memcpy_P(nwkskey, NWKSKEY, sizeof(NWKSKEY));
LMIC_setSession (0x1, DEVADDR, nwkskey, appskey);
#else
// If not running an AVR with PROGMEM, just use the arrays directly
LMIC_setSession (0x1, DEVADDR, NWKSKEY, APPSKEY);
#endif
// Disable link check validation
LMIC_setLinkCheckMode(0);
// TTN uses SF9 for its RX2 window.
LMIC.dn2Dr = DR_SF9;
// Set data rate and transmit power (note: txpow seems to be ignored by the library)
LMIC_setDrTxpow(DR_SF7,14);
// Start job
do_send(&sendjob);
}
void loop() {
os_runloop_once();
while (ss.available() > 0){
val = digitalRead(inPin);
//delay(200);
mydata[9] = val;
gps.encode(ss.read());
if (gps.location.isUpdated()){
Serial.print("Latitude= ");
Serial.print(gps.location.lat()*10000, 6);
Serial.print(" Longitude= ");
Serial.println(gps.location.lng(), 6);
double _lat = gps.location.lat();
byte *ptr;
ptr = (byte*) &_lat;
for (int i = 0; i < 4; i++)
{
byte m = *ptr;
Serial.print(m,HEX);
mydata[i] = m;
ptr++;
}
double _lng = gps.location.lng();
byte *ptr2;
ptr2 = (byte*) &_lng;
for (int i = 0; i < 4; i++)
{
byte m = *ptr2;
Serial.print(m,HEX);
mydata[4+i] = m;
ptr2++;
}
//mydata[0] = gps.location.lat();//gps.location.lat();
//mydata[1] = gps.location.lng();//gps.location.lng();
}
}
}
RFID & Electro-magnetIn our project, RFID allows us to unlock the cart using a customer card.In our project, we also locked the cart with an electromagnet.By swiping a customer card, the cart is unlocked because the electromagnet is demagnetized.
The customer can locked his cart by re swiping his customer card.
All information about the cart is displayed on an LCD screen.All the component are connect to an Arduino Leonardo through a breadboard.
Our module is equipped with a monitoring application.
This allows first and foremost the localization of the shopping carts.
The application allows you to select a cart that you want to track and monitor.
Moreover, the application also allows to collect other data such as the number of use, the number of kilometers covered by a cart, to know if a cart is in use and finally to know if a cart is lost.
This application has been developped using React for the front-end and for the back-end we have been using nodejs.
We have an application server that allows us to query a database, but above all it allows us to intercept the frames sent by TTN.
As a reminder, in our use, TTN sends bytes containing our coordinates and other information.
So our server must process these data to retranscribe them to the application.
When we receive the bytes, we convert them to hexadecimal :
function bytesToHex(bytes) {
for (var hex = [], i = 0; i < bytes.length; i++) {
hex.push((bytes[i] >>> 4).toString(16));
hex.push((bytes[i] & 0xF).toString(16));
}
return hex.join("");
}
Then we reverse the chain and split it by 2
function reverseString(str) {
var newString = '';
for (var i = str.length - 2; i >= 0; i -= 2) {
newString += str[i] + str[i + 1];
}
return newString;
}
Finally, we pass the string to a function that converts a hexadecimal string to a float Float - Big Endian (ABCD)
function hexStringToFloat(hexString) {
const hex = parseInt(hexString, 16);
const sign = hex >> 31 ? -1 : 1;
const exponent = (hex >> 23) & 0xFF;
return sign * (hex & 0x7fffff | 0x800000) * 1.0 / Math.pow(2, 23) * Math.pow(2, (exponent - 127));
}
All this steps give us our usable data.
3D PrintingOur connected shopping cart is actually a module that we install in the shopping carts.
We had to create a box adapted to the different components of the module.
We have created a box using software onshape.
The Thing Network is a global collaborative Internet of Things ecosystem that creates networks, devices and solutions using LoRaWAN technologie.
This technology allows objects to transmit small amounts of information while consuming very little energy.
It is possible to use this network freely but it is also possible to help extend the network by deploying gateways.
Currently the network consists of more than 40, 000 contributors grouped in more than 400 communities in 90 countries having deployed more than 4000 gateways.
ReactReact is a free JavaScript library developed by Facebook since 2013.
The main goal of this library is to facilitate the creation of single-page web applications, via the creation of components depending on a state and generating an HTML page at each state change.
MySQLMySQL is a relational database management system (RDBMS).
It is distributed under a dual GPL and proprietary license.
It is one of the most widely used database management software in the world, both by the general public (mainly web applications) and by professionals, in competition with Oracle, PostgreSQL and Microsoft SQL Server.
OnshapeOnshape is a computer-aided design software system, delivered over the Internet via a software-as-a-service model.
NodeJSNode.js is a free software platform in JavaScript, oriented towards highly concurrent event-driven network applications that must be able to scale.
It uses the V8 virtual machine, the libuv library for its event loop, and implements the CommonJS specifications under the MIT license.
Among the native modules of Node.js, we find http which allows the development of HTTP server. This allows, when deploying websites and web applications developed with Node.js, not to install and use web servers such as Nginx or Apache.
Concretely, Node.js is a low-level environment allowing the execution of JavaScript on the server side.
Translated with www.DeepL.com/Translator (free version)
PresentationConclusionWe've found this project very interesting.
It allow us to applicate what we learn during LPWAN courses.
It also requiered other skills like web application skills and back-end skills.
We are very proud to have been able to build this cart module which make us think about storage data, web application and the internet of things.
Comments
Please log in or sign up to comment.