Trailing the Tail

0 5165 Medium

More of a tactical, rather than practical; approach for monitoring our elephants in wild.

projectImage

Things used in this project

 

Hardware components

HARDWARE LIST
1 DFRobot FireBeetle ESP32 IOT Microcontroller (Supports Wi-Fi & Bluetooth)
1 Arduino Nano 33 BLE Sense
1 Seeed Studio Grove - LoRa Radio 868MHz
1 u-blox Ublox NEO-6M
1 Brown Dog Gadgets Solar Cockroach Vibrating Disc Motor
1 Raspberry Pi 3 Model B+
1 Helium Developer Kit
1 RTL SDR dongle
1 868 MHz LoRa External Antenna
1 GSM/CDMA External Antenna
3 Lithium Thionyl Chloride Battery

Software apps and online services

 

Arduino IDE

 

Avnet IoT Connect

 

Edge Impulse Studio

 

IBM Watson

Hand tools and fabrication machines

 

Soldering Station, Hobbyist

Story

 

Elephant Poach Stats

 

African elephants are split into two distinct species: the African bush elephant, the most prevalent species, and the smaller African forest elephant. The bush elephant is the world’s largest living species of land animal. In both African elephant species the males and females have tusks; these are modified incisors that can grow to weigh dozens of kilograms and are used for a variety of essential purposes in an elephant’s daily life. These tusks are a significant source of ivory which is used in ivory ornaments and jewelry.

Poaching, habitat loss, and human conflict have led to the devastating loss of millions of elephants across Africa in the last 100 years.

 

For an instance, in Zakouma National Park in Chad, the population plummeted from 4, 300 elephants to just 450 in just eight short years due to poaching.

projectImage
projectImage
projectImage
projectImage
projectImage

Hardware

 

The proposed hardware (Packet'u'Tracker) utilizes the capabilities of Nano 33 BLE Sense board due to onboard availability of myriad sensors and comforting support of machine-learning, combining with BLE5.0.

projectImage

Apart from the mentioned, Packet'u' additionally combines SX1276-(IN867) LoRa module, U-Blox NEO-6M GPS receiver, FET powered vibration disc(hap-feed), and external antennas for GPS and LoRa, powered via 3x1/2 AA Lithium Thionyl Chloride primary batteries(ideal for the purpose, as discussed in the webinar sessions).

projectImage

The idea is to attach the Packet'u'Tracker on the tail of the elephants unlike conventional neck based collars. !!The idea shouldn't be misjudged pertaining to hardware-safety or animal-discomfort!!

 

Primary reasons for the above approach are: higher attachment costs, a slight continual load, even for the land's biggest animal(imagine carrying a piece of brick over your neck for ten years of your life:: normal counter-weights and belt amount for over 10 Kgs.), minimum input of the animal's behavior.

 

Counter to which, the device should be lighter, stealthy and provide active method of animal behavior analysis.

By directly attaching the sensor unit at the tail, one can get behavioural insights such as: elephants have an extraordinary degree of control over tail movement, when an elephant’s tail is swishing from side to side swatting away flies, it is happy. As soon as the tail goes stiff, normally held out to one side, it means that the elephant is anxious. At this point it may even start to run from you, normally swivelling over its shoulder to keep an eye on you as it tries to get away.

 

The above fact can be utilized in conjunction with sensor fusion and machine learning model for predicting the distress pattern or the animal behavior.

 

 

 

Features of the Packet'u'

 

Gets GPS fix/day(default) or 2 positional fixes(specific condition is achieved).

 

Broadcasts raw accelerometer along with Roll, Pitch and Yaw values.

 

Predicts ambient light-levels based on the values of color-sensor(APDS9960).

 

Vibration disc has been provided(experimental) to confirm the sensory-feedback(specific condition is achieved).

Broadcasts the programmed Elephant I.D. and ambient temperature values(HTS221).

 

If the target (elephant armed with Packet'u') reaches the off-zone limits of the geofence, LoRa RSSI signal is referenced and reported, for providing comparative GPS position.

 

In case, the target maintains zero-activity for specified interval, a local feedback is produced by vibration disc to invoke sensory-feedback from the target, failing to which an emergency beacon is transmitted to the gateway along with the current position, fix and additional sat-data.

 

and establishes LoRa NLOS/LOS link with the gateway.

 

 

 

Features of the Gateway

Uses Raspberry Pi 3B+ as processor for incoming Packet'u' signals.

 

ESP32 based 14 Channel(individual) scanning of wifi signals within 25-30m radius and logged to Wireshark for post-processing and analysis.

 

PacketMonitor32 by Stefan Kremser aka Spacehuhn, (slightly modded for forked support of Wireshark on WinOS through SerialShark script.)

 

Realtek RTL2832 based software defined radio combined with PiSDR OS (supporting functionality like Gpredict, rpitx, Soapy Remote, GNURadio and others), that would be utilized to capture and sniff RF signals(tests performed for GSM/CDMA carrier signals) for detecting human-presence within the specific scan-zone.

 

Establishes LoRa link with Packet'u' through dedicated STMicroelectronics B-L072Z-LRWAN(Helium Dev base board).

 

 

 

Test & Build.

projectImage
projectImage
projectImage

Setting the IoT Connect

 

1. Sign up for Avnet IoT Connect.

 

2. Install IoT Connect Python SDK (Standard with support for Symmetric Key and x509 Certificate based authentication for azure iothub), (for usage on Raspberry Pi) recommended Python 3(/2).

 

3. Power up and login to the terminal on Pi, go into the IoTConnect folder and use pip3 to install the iotconnect SDK

 

cd /boot/iotconnect-sdk-python-v2.0-1/iotconnect-sdk

 

pip3 install iotconnect-sdk-2.0.tar.gz

 

4. Setup Device Dashboard in IoTConnect:

 

-Create a Template in the IoTConnect Dashboard. Devices -> Templates -> Create Template.

 

-Save Template after filling in information.

 

-Create Attributes Example and Save.

 

-Create Twin Property and Save.

 

-In the IotConnect Dashboard go Devices -> Devices -> Create Device.

 

-Make the Unique ID and Display name unique for to you. Select your entity and select the Basic_1 template. Select save. DONE.

 

5. Run the IoTConnect Example (Run example_py3.py or firmware.py from SDK Sample folder).

 

python3./example_py3.py

 

6. Get UniqueID and CPID from Company Profile tab.

 

7. After a moment, you will get the data prompt in IoT Connect dashboard. Additionally, you can also access the Twin Property or create custom dashboard as per requirements.

projectImage
projectImage
projectImage

- Additionally we can also pipe the device-data into IBM Watson Cloud, as per convenience.

The Gateway may Cry..

projectImage
projectImage
projectImage
projectImage
projectImage
projectImage

Conclusion

 

Further improving on the hardware and (maybe to utilize) the capabilities of Lacuna Network and Cloud offloaded Ephemeris based position estimation are still a dream realized to be true.

Schematics

 

Connection block diagram

projectImage

Code

 

Packet'u' Tracker Node

Arduino

CODE
// Packet'u'[ElephantEdgeNode].
#define DECLINATION +0.36 // Target location-specific.
#include <Arduino_LSM9DS1.h>
#include <Arduino_HTS221.h>
#include <Arduino_APDS9960.h>
#include <Adafruit_GPS.h>
#define GPSSerial Serial1
#include <LoRa.h>
Adafruit_GPS GPS(&GPSSerial);
// Set GPSECHO to 'false' to turn off echoing the GPS data to the Serial console
// Set to 'true' to debug and listen to the raw GPS sentences
#define GPSECHO false
int EID = 31;
float temperature;
uint32_t timer = millis();
float yaw, roll, pitch;
float X, Y, Z, l, m, n, r;
int R, G, B, avg;

void setup()
{
  Serial.begin(115200);
  GPS.begin(9600);
  LoRa.begin(865E6);
  IMU.begin(); 
  HTS.begin();
  APDS.begin();
  pinMode(3, OUTPUT); //HapticsEnabled.
  // uncomment this line to turn on RMC (recommended minimum) and GGA (fix data) including altitude
  GPS.sendCommand(PMTK_SET_NMEA_OUTPUT_RMCGGA);
  // uncomment this line to turn on only the "minimum recommended" data
  //GPS.sendCommand(PMTK_SET_NMEA_OUTPUT_RMCONLY);
  GPS.sendCommand(PMTK_SET_NMEA_UPDATE_1HZ);
  GPS.sendCommand(PGCMD_ANTENNA);
  delay(1000);
  GPSSerial.println(PMTK_Q_RELEASE);
}

void loop()
{
  // read data from the GPS in the 'main loop'
  char c = GPS.read();
  if (GPSECHO)
    if (c) Serial.print(c);
  if (GPS.newNMEAreceived()) {
    if (!GPS.parse(GPS.lastNMEA()))
      return;
  }
  // every 2 seconds, print out the current position & stat
  if (millis() - timer > 10000) {
    timer = millis(); // reset the timer
    Serial.print("\nTime: ");
    if (GPS.hour < 10) { Serial.print('0'); }
    Serial.print(GPS.hour, DEC); Serial.print(':');
    if (GPS.minute < 10) { Serial.print('0'); }
    Serial.print(GPS.minute, DEC); Serial.print(':');
    if (GPS.seconds < 10) { Serial.print('0'); }
    Serial.print(GPS.seconds, DEC); Serial.print('.');
    if (GPS.milliseconds < 10) {
      Serial.print("00");
    } else if (GPS.milliseconds > 9 && GPS.milliseconds < 100) {
      Serial.print("0");
    }
    Serial.print(GPS.milliseconds);
    Serial.print("\tDate: ");
    Serial.print(GPS.day, DEC); Serial.print('/');
    Serial.print(GPS.month, DEC); Serial.print("/20");
    Serial.println(GPS.year, DEC);
    Serial.print("Fix: "); Serial.print((int)GPS.fix);
    //Serial.print(" quality: "); Serial.println((int)GPS.fixquality);
    if (GPS.fix) {
      Serial.print("\tLocation: ");
      Serial.print(GPS.latitude, 4); Serial.print(GPS.lat);
      Serial.print(", ");
      Serial.print(GPS.longitude, 4); Serial.println(GPS.lon);
      Serial.print("Speed (knots): "); Serial.print(GPS.speed);
      //Serial.print("Angle: "); Serial.println(GPS.angle);
      //Serial.print("Altitude: "); Serial.println(GPS.altitude);
      Serial.print("\tSatellites: "); Serial.println((int)GPS.satellites);
    }
  }
  if (millis() - timer > 500) {
  GetIMU();
  GetAmbTemp();
  GetAmbLight();
  /*PacketizingLoRaTransmissions*/
  LoRa.beginPacket();
  LoRa.print("P'u':");  
  LoRa.print(EID);
  LoRa.print(",[");LoRa.print(GPS.latitude, 4);LoRa.print(GPS.lat);LoRa.print("],[");
  LoRa.print(GPS.longitude, 4);LoRa.print(GPS.lon);LoRa.print("],");
  LoRa.print((int)GPS.fix);LoRa.print(",[");LoRa.print((int)GPS.satellites);LoRa.print("],[");

  if (GPS.hour < 10) { LoRa.print('0'); }LoRa.print(GPS.hour, DEC); LoRa.print(':');
  if (GPS.minute < 10) { LoRa.print('0'); }LoRa.print(GPS.minute, DEC); LoRa.print(':');
  if (GPS.seconds < 10) { LoRa.print('0'); }LoRa.print(GPS.seconds, DEC);LoRa.print("],");

  LoRa.print(temperature,0);LoRa.print("°C,");LoRa.print("[P:");LoRa.print(pitch, 2);
  LoRa.print("],[R:");LoRa.print(r, 0);LoRa.print("],[B:");LoRa.print(yaw, 0);LoRa.print("],[X:");
  LoRa.print(X);LoRa.print("],[Y:");LoRa.print(Y);LoRa.print("],[Z:");LoRa.print(Z);LoRa.print("],[Lux:"); 
  LoRa.print(avg);LoRa.print("]");
  LoRa.endPacket();
  }
}

void GetAmbTemp() {
  temperature = HTS.readTemperature();
}

void GetAmbLight() {
  if (APDS.colorAvailable()) {
    APDS.readColor(R, G, B);
  }
    avg = (R+G+B)/3; 
}

void GetIMU() {
  if ( (IMU.accelerationAvailable()) && (IMU.magneticFieldAvailable()) ){
    IMU.readAcceleration(X, Y, Z);
    IMU.readMagneticField(l, m, n);
    roll = atan2(Y, Z);
    pitch = atan2(-X, sqrt(Y * Y + Z * Z));
  if (n == 0)
    yaw = (m < 0) ? PI : 0;
  else
    yaw = atan2(m, n);
    yaw -= DECLINATION * PI / 180;
  if (yaw > PI) yaw += (PI);
  else if (yaw > -PI) yaw += (PI);
  // Converting Radians to Degrees:
  pitch *= 180.0 / PI;
  roll  *= 180.0 / PI;
  yaw *= 180.0 / PI;
  r = roll+90;
  }
}

Packet'u' Scanner Gateway(ST-LRWAN)

Arduino

CODE
// ST-LRWAN based LoRa Receiver[ElephantEdgeNode].

#include "LoRaRadio.h"

void setup( void )
{
    Serial.begin(115200); 
    while (!Serial) { }

    LoRaRadio.begin(867000000);

    LoRaRadio.setFrequency(867000000);
    LoRaRadio.setTxPower(14);
    LoRaRadio.setBandwidth(LoRaRadio.BW_125);
    LoRaRadio.setSpreadingFactor(LoRaRadio.SF_7);
    LoRaRadio.setCodingRate(LoRaRadio.CR_4_5);
    LoRaRadio.setLnaBoost(true);
    LoRaRadio.receive(5000);
}

void loop( void )
{
int packetSize = LoRaRadio.parsePacket();
if (packetSize) {
    //Serial.print("Received packet: ");
    while (LoRaRadio.available()) {
    Serial.print((char)LoRaRadio.read());
    }
    Serial.print("(RSSI: ");
            Serial.print(LoRaRadio.packetRssi());
            Serial.print(", SNR: ");
            Serial.print(LoRaRadio.packetSnr());
            Serial.println(")");                                  
    }
}

SerialShark code for streaming .pcap file in Wireshark

Python

CODE
# Made by @xdavidhu (github.com/xdavidhu, https://xdavidhu.me/)

import serial
import io
import os
import subprocess
import signal
import time

try:
    serialportInput = input("[?] Select a serial port (default '/dev/ttyUSB0'): ")
    if serialportInput == "":
        serialport = "/dev/ttyUSB0"
    else:
        serialport = serialportInput
except KeyboardInterrupt:
    print("\n[+] Exiting...")
    exit()

try:
    canBreak = False
    while not canBreak:
        boardRateInput = input("[?] Select a baudrate (default '921600'): ")
        if boardRateInput == "":
            boardRate = 921600
            canBreak = True
        else:
            try:
                boardRate = int(boardRateInput)
            except KeyboardInterrupt:
                print("\n[+] Exiting...")
                exit()
            except Exception as e:
                print("[!] Please enter a number!")
                continue
            canBreak = True
except KeyboardInterrupt:
    print("\n[+] Exiting...")
    exit()

try:
    filenameInput = input("[?] Select a filename (default 'capture.pcap'): ")
    if filenameInput == "":
        filename = "capture.pcap"
    else:
        filename = filenameInput
except KeyboardInterrupt:
    print("\n[+] Exiting...")
    exit()

canBreak = False
while not canBreak:
    try:
        ser = serial.Serial(serialport, boardRate)
        canBreak = True
    except KeyboardInterrupt:
        print("\n[+] Exiting...")
        exit()
    except:
        print("[!] Serial connection failed... Retrying...")
        time.sleep(2)
        continue

print("[+] Serial connected. Name: " + ser.name)
counter = 0
f = open(filename,'wb')

check = 0
while check == 0:
    line = ser.readline()
    if b"<<START>>" in line:
        check = 1
        print("[+] Stream started...")
    #else: print '"'+line+'"'

print("[+] Starting up wireshark...")
cmd = "tail -f -c +0 " + filename + " | wireshark -k -i -"
p = subprocess.Popen(cmd, stdout=subprocess.PIPE,
                       shell=True, preexec_fn=os.setsid)

try:
    while True:
        ch = ser.read()
        f.write(ch)
        f.flush()
except KeyboardInterrupt:
    print("[+] Stopping...")
    os.killpg(os.getpgid(p.pid), signal.SIGTERM)

f.close()
ser.close()
print("[+] Done.")

Git repo - ElephantEdge_code

icon ElephantEdge-main.zip 51KB Download(0)

The article was first published in hackster, March 4 2022

cr: https://www.hackster.io/374408/trailing-the-tail-663dc4

author: Night R, Shivam Kumar Tiwari

License
All Rights
Reserved
licensBg
0