Muhammed ZainVishnuraj A
Published © MIT

Rescue Bot

Rescue Bot is an autonomous ground rover designed to navigate post-disaster terrain, locate survivors and enhance disaster response

AdvancedFull instructions providedOver 2 days4,020

Things used in this project

Hardware components

NVIDIA Jetson Nano Developer Kit
NVIDIA Jetson Nano Developer Kit
×1
Intel RealSense Camera
Intel RealSense Camera
×1
Arduino Mega 2560
Arduino Mega 2560
×1
11.1V 10000mah Battery
×1
HIGH TORQUE HIGH PRECISION ENCODER DC GEARED MOTOR 12V 100RPM
×4
RHINO DC SERVO DRIVER 10V-30V 50W 5A COMPATIBLE WITH MODBUS UART ASCII FOR ENCODER DC SERVO MOTOR
×4
ROBOT WHEEL 125MM DIAMETER 60MM WIDTH FOR ATV
×4
XL4016E1 200W Step Down Power Supply Module
×1
Grove - Temperature, Humidity, Pressure and Gas Sensor (BME680)
Seeed Studio Grove - Temperature, Humidity, Pressure and Gas Sensor (BME680)
×1
MAKERFACTORY Robot servo SERVO MF-05
MAKERFACTORY Robot servo SERVO MF-05
×5
Wio Terminal
Seeed Studio Wio Terminal
×1
TinyShield GPS
TinyCircuits TinyShield GPS
×1
Raspberry Pi Touch Display
Raspberry Pi Touch Display
×1
Seeed Studio RPLiDAR A2M8 360 Degree Laser Scanner Kit - 12M Range
×1
Gravity BNO055+BMP280 intelligent 10DOF AHRS
DFRobot Gravity BNO055+BMP280 intelligent 10DOF AHRS
×1
Grove - Temperature&Humidity Sensor (SHT40)
Seeed Studio Grove - Temperature&Humidity Sensor (SHT40)
×1
Grove - Multichannel Gas Sensor
Seeed Studio Grove - Multichannel Gas Sensor
×1

Software apps and online services

Robot Operating System
ROS Robot Operating System
OpenCV
OpenCV
Arduino IDE
Arduino IDE
Jupyter Notebook
Jupyter Notebook
VS Code
Microsoft VS Code
Solidworks

Hand tools and fabrication machines

Soldering Station, 110 V
Soldering Station, 110 V
Laser cutter (generic)
Laser cutter (generic)
3D Printer (generic)
3D Printer (generic)
Hot glue gun (generic)
Hot glue gun (generic)
Solder Wire, Lead Free
Solder Wire, Lead Free
Premium Female/Female Jumper Wires, 40 x 3" (75mm)
Premium Female/Female Jumper Wires, 40 x 3" (75mm)
Wire Stripper & Cutter, 32-20 AWG / 0.05-0.5mm² Solid & Stranded Wires
Wire Stripper & Cutter, 32-20 AWG / 0.05-0.5mm² Solid & Stranded Wires

Story

Read more

Custom parts and enclosures

Rescue_Bot

Code

ROSSerial node hello world

C/C++
//This is a example code fron ROSWIKI
#include <ros.h>
#include <std_msgs/String.h>
ros::NodeHandle nh; 
std_msgs::String str_msg;
ros::Publisher chatter("chatter", &str_msg);
char hello[13] = "hello world!";
void setup()
{
  nh.initNode();
  nh.advertise(chatter);
}
void loop()
{
  str_msg.data = hello;
  chatter.publish( &str_msg );
  nh.spinOnce();
  delay(1000);
}

Ros node for drive

C/C++
#include <ros.h>
#include <RMCS2303drive.h>
#include <geometry_msgs/Twist.h>
#include <std_msgs/Int32.h>

#include "MapFloat.h"

RMCS2303 rmcs;  // creation of motor driver object
// slave ids to be set on the motor driver refer to the manual in the reference section
byte slave_id1 = 1;
byte slave_id2 = 2;
byte slave_id3 = 3;
byte slave_id4 = 4;

ros::NodeHandle nh;        // Node handle Object
geometry_msgs::Twist msg;  // msg variable of data type twist

std_msgs::Int32 lwheel;  // for storing left encoder value
std_msgs::Int32 rwheel;  // for storing right encoder value

// Publisher object with topic names left_ticks and right_ticks for publishing Enc Values
ros::Publisher left_ticks("left_ticks", &lwheel);
ros::Publisher right_ticks("right_ticks", &rwheel);
// Make sure to specify the correct values here
//*******************************************
double wheel_rad = 0.0625, wheel_sep = 0.300;  // wheel radius and wheel sepration in meters.
//******************************************
double w_r = 0, w_l = 0;
double speed_ang;
double speed_lin;
double leftPWM;
double rightPWM;

void messageCb(const geometry_msgs::Twist& msg)  // cmd_vel callback function definition
{
  speed_lin = max(min(msg.linear.x, 1.0f), -1.0f);   // limits the linear x value from -1 to 1
  speed_ang = max(min(msg.angular.z, 1.0f), -1.0f);  // limits the angular z value from -1 to 1

  // Kinematic equation for finding the left and right velocities
  w_r = (speed_lin / wheel_rad) + ((speed_ang * wheel_sep) / (2.0 * wheel_rad));
  w_l = (speed_lin / wheel_rad) - ((speed_ang * wheel_sep) / (2.0 * wheel_rad));

  if (w_r == 0)
  {
    rightPWM = 0;
    rmcs.Disable_Digital_Mode(slave_id1,0);
    rmcs.Disable_Digital_Mode(slave_id2,0);  // if right motor velocity is zero set right pwm to zero and disabling motors
    rmcs.Disable_Digital_Mode(slave_id3,0);
    rmcs.Disable_Digital_Mode(slave_id4,0);
  }
  else
    rightPWM = mapFloat(fabs(w_r), 0.0, 18.0, 1500,17200);  // mapping the right wheel velocity with respect to Motor PWM values

  if (w_l == 0)
  {
    leftPWM = 0;
    rmcs.Disable_Digital_Mode(slave_id1,0);
    rmcs.Disable_Digital_Mode(slave_id2,0);  // if left motor velocity is zero set left pwm to zero and disabling motors
    rmcs.Disable_Digital_Mode(slave_id3,0);
    rmcs.Disable_Digital_Mode(slave_id4,0);
  }

  else
    leftPWM = mapFloat(fabs(w_l), 0.0, 18.0, 1500,
                       17200);  // mapping the right wheel velocity with respect to Motor PWM values

  rmcs.Speed(slave_id1,rightPWM);
  rmcs.Speed(slave_id2,rightPWM);
  rmcs.Speed(slave_id3,leftPWM);
  rmcs.Speed(slave_id4,leftPWM);

  if (w_r > 0 && w_l > 0)
  {
    rmcs.Enable_Digital_Mode(slave_id1,1);
    rmcs.Enable_Digital_Mode(slave_id2,1);  // forward condition
    rmcs.Enable_Digital_Mode(slave_id3,0);
    rmcs.Enable_Digital_Mode(slave_id4,0);
  }

  else if (w_r < 0 && w_l < 0)
  {
    rmcs.Enable_Digital_Mode(slave_id1,0);
    rmcs.Enable_Digital_Mode(slave_id2,0);  // backward condition
    rmcs.Enable_Digital_Mode(slave_id3,1);
    rmcs.Enable_Digital_Mode(slave_id4,1);
  }
  else if (w_r > 0 && w_l < 0)
  {
    rmcs.Enable_Digital_Mode(slave_id1,1);
    rmcs.Enable_Digital_Mode(slave_id2,1);  // Leftward condition
    rmcs.Enable_Digital_Mode(slave_id3,1);
    rmcs.Enable_Digital_Mode(slave_id4,1);
  }

  else if (w_r < 0 && w_l > 0)
  {
    rmcs.Enable_Digital_Mode(slave_id1,0);
    rmcs.Enable_Digital_Mode(slave_id2,0);  // rightward condition
    rmcs.Enable_Digital_Mode(slave_id3,0);
    rmcs.Enable_Digital_Mode(slave_id4,0);
  }

  else
  {
    rmcs.Brake_Motor(slave_id1,0);
    rmcs.Brake_Motor(slave_id2,0);
    rmcs.Brake_Motor(slave_id3,0);
    rmcs.Brake_Motor(slave_id4,0);  // if none of the above break the motors both in clockwise n anti-clockwise direction
    rmcs.Brake_Motor(slave_id1,1);
    rmcs.Brake_Motor(slave_id2,1);
    rmcs.Brake_Motor(slave_id3,1);
    rmcs.Brake_Motor(slave_id4,1);
  }
}
ros::Subscriber<geometry_msgs::Twist> sub("cmd_vel",&messageCb);  // creation of subscriber object sub for recieving the cmd_vel

void setup()
{
  rmcs.Serial_selection(0);  // 0 -> for Harware serial tx1 rx1 of arduino mega
  rmcs.Serial0(9600);
  rmcs.begin(&Serial2, 9600);

  nh.initNode();      // initialzing the node handle object
  nh.subscribe(sub);  // subscribing to cmd vel with sub object

  nh.advertise(left_ticks);   // advertise the left_ticks topic
  nh.advertise(right_ticks);  // advertise the left_ticks topic
}

void loop()
{
  lwheel.data =
      rmcs.Position_Feedback(slave_id4);  // the function reads the encoder value from the motor with slave id 4
  rwheel.data =
      -rmcs.Position_Feedback(slave_id2);  // the function reads the encoder value from the motor with slave id 4

  left_ticks.publish(&lwheel);   // publish left enc values
  right_ticks.publish(&rwheel);  // publish right enc values
  nh.spinOnce();
}

OpenPose Posture Detection

Python
""" Posture detection model using Realsense D435i
Authors : Muhammed Zain and Vishnuraj A
Date : 10/11/2023
Last Update : 29/11/2023 """


# Load the pose detection model
net = cv.dnn.readNetFromTensorflow("graph_opt.pb")  # Replace with your model path
inWidth = 368
inHeight = 368
thr = 0.2

# (Your BODY_PARTS and POSE_PAIRS definitions here)
BODY_PARTS = {
    "Nose": 0, "Neck": 1, "RShoulder": 2, "RElbow": 3, "RWrist": 4,
    "LShoulder": 5, "LElbow": 6, "LWrist": 7, "RHip": 8, "RKnee": 9,
    "RAnkle": 10, "LHip": 11, "LKnee": 12, "LAnkle": 13, "REye": 14,
    "LEye": 15, "REar": 16, "LEar": 17, "Background": 18
}

POSE_PAIRS = [
    ["Neck", "RShoulder"], ["Neck", "LShoulder"], ["RShoulder", "RElbow"],
    ["RElbow", "RWrist"], ["LShoulder", "LElbow"], ["LElbow", "LWrist"],
    ["Neck", "RHip"], ["RHip", "RKnee"], ["RKnee", "RAnkle"], ["Neck", "LHip"],
    ["LHip", "LKnee"], ["LKnee", "LAnkle"], ["Neck", "Nose"], ["Nose", "REye"],
    ["REye", "REar"], ["Nose", "LEye"], ["LEye", "LEar"]
]


# Initialize RealSense pipeline
pipe = rs.pipeline()
config = rs.config()
config.enable_stream(rs.stream.color, 640, 480, rs.format.bgr8, 30)
config.enable_stream(rs.stream.depth, 640, 480, rs.format.z16, 30)

pipe.start(config)

try:
    while True:
        # Wait for frames to be available
        frames = pipe.wait_for_frames()
        color_frame = frames.get_color_frame()
        depth_frame = frames.get_depth_frame()

        if not color_frame or not depth_frame:
            continue

        # Convert color frame to a numpy array
        frame = np.asanyarray(color_frame.get_data())

        frameWidth = frame.shape[1]
        frameHeight = frame.shape[0]

        blob = cv.dnn.blobFromImage(frame, 1.0, (inWidth, inHeight), (127.5, 127.5, 127.5), swapRB=True, crop=False)
        net.setInput(blob)
        out = net.forward()

        out = out[:, :19, :, :]  # Keep only the first 19 elements

        assert(len(BODY_PARTS) == out.shape[1])

        points = []
        for i in range(len(BODY_PARTS)):
            heatMap = out[0, i, :, :]
            _, conf, _, point = cv.minMaxLoc(heatMap)
            x = (frameWidth * point[0]) / out.shape[3]
            y = (frameHeight * point[1]) / out.shape[2]
            points.append((int(x), int(y)) if conf > thr else None)

        for pair in POSE_PAIRS:
            partFrom = pair[0]
            partTo = pair[1]

            idFrom = BODY_PARTS[partFrom]
            idTo = BODY_PARTS[partTo]

            if points[idFrom] and points[idTo]:
                cv.line(frame, points[idFrom], points[idTo], (0, 255, 0), 3)
                cv.ellipse(frame, points[idFrom], (3, 3), 0, 0, 360, (0, 0, 255), cv.FILLED)
                cv.ellipse(frame, points[idTo], (3, 3), 0, 0, 360, (0, 0, 255), cv.FILLED)

        # Process depth frame (for example, obtain depth information for specific body parts)
        depth_data = np.asanyarray(depth_frame.get_data())

        # Apply depth colormap to the depth frame
        depth_colormap = cv.applyColorMap(cv.convertScaleAbs(depth_data, alpha=0.03), cv.COLORMAP_JET)

        # Display the color frame with pose estimation and the depth colormap in separate windows
        cv.imshow('Pose Estimation', frame)
        cv.imshow('Depth Colormap', depth_colormap)

        if cv.waitKey(1) & 0xFF == ord('q'):
            break

finally:
    pipe.stop()
    cv.destroyAllWindows()

Senser interface

C/C++
#include <PubSubClient.h>
#include <rpcWiFi.h>
#include <SensirionI2CSht4x.h>
#include <Wire.h>
#include "sensirion_common.h"
#include "sgp30.h"
#include <TFT_eSPI.h>
TFT_eSPI tft;
TFT_eSprite spr = TFT_eSprite(&tft);
SensirionI2CSht4x sht4x;
int randnumber;
const char *ssid = "zain"; // your network SSID
const char *password = "123456789"; // your network password
const char *ID = "node1"; // Name of our device, must be unique
const char *server = "test.mosquitto.org"; // Server URL
WiFiClient wifiClient;
PubSubClient client(wifiClient);
unsigned long lastMsg = 0;
#define MSG_BUFFER_SIZE (50)
char msg[MSG_BUFFER_SIZE];
int value = 0;
const float VRefer = 3.3; // Voltage of ADC reference
const int pinAdc = A0; // Analog pin connected to the Grove Gas Sensor (O2)
void callback(char* topic, byte* payload, unsigned int length) {
Serial.print("Message arrived [");
Serial.print(topic);
Serial.print("] ");
for (int i = 0; i < length; i++) {
Serial.print((char)payload[i]);
}
Serial.println();
}
void reconnect() {
// Loop until we're reconnected
while (!client.connected()) {
Serial.print("Attempting MQTT connection...");
// Attempt to connect
if (client.connect(ID)) {
Serial.println("connected");
}
else {
Serial.print("failed, rc=");
Serial.print(client.state());
Serial.println(" try again in 5 seconds");
// Wait 5 seconds before retrying
delay(5000);
}
}
}
void setup() {
Serial.begin(115200);
pinMode(WIO_KEY_A, INPUT_PULLUP);
pinMode(WIO_BUZZER, OUTPUT);
tft.begin();
tft.setRotation(3);
tft.fillScreen(TFT_BLACK);
tft.setFreeFont(&FreeSansBoldOblique18pt7b);
tft.setTextColor(TFT_WHITE);
tft.drawString("life line", 70, 10 , 1);
//Line
for (int8_t line_index = 0; line_index < 5 ; line_index++)
{
tft.drawLine(0, 50 + line_index, tft.width(), 50 + line_index, TFT_GREEN);
}
//VCO & CO Rect
tft.drawRoundRect(5, 60, (tft.width() / 2) - 20 , tft.height() - 65 , 10, TFT_WHITE); // L1
//tVCO Text
tft.setFreeFont(&FreeSansBoldOblique12pt7b);
tft.setTextColor(TFT_RED);
tft.drawString("tVOC", 7 , 65 , 1);
tft.setTextColor(TFT_GREEN);
tft.drawString("ppm", 55, 108, 1);
//CO2 Text
tft.setFreeFont(&FreeSansBoldOblique12pt7b);
tft.setTextColor(TFT_RED);
tft.drawString("CO2eq", 7 , 150 , 1);
tft.setTextColor(TFT_GREEN);
tft.drawString("ppm", 55, 193, 1);
// Temp rect
tft.drawRoundRect((tft.width() / 2) - 10 , 60, (tft.width() / 2) / 2 , (tft.height() - 65) / 2 , 10, TFT_BLUE); // s1
tft.setFreeFont(&FreeSansBoldOblique9pt7b);
tft.setTextColor(TFT_RED) ;
tft.drawString("Temp", (tft.width() / 2) - 1 , 70 , 1); // Print the test text in the custom font
tft.setTextColor(TFT_GREEN);
tft.drawString("o", (tft.width() / 2) + 30, 95, 1);
tft.drawString("C", (tft.width() / 2) + 40, 100, 1);
//o2 rect
tft.drawRoundRect(((tft.width() / 2) + (tft.width() / 2) / 2) - 5 , 60, (tft.width() / 2) / 2 , (tft.height() - 65) / 2 , 10, TFT_BLUE); // s2
tft.setFreeFont(&FreeSansBoldOblique9pt7b);
tft.setTextColor(TFT_RED);
tft.drawString("O2", ((tft.width() / 2) + (tft.width() / 2) / 2) , 70 , 1); // Print the test text in the custom font
tft.setTextColor(TFT_GREEN);
tft.drawString("%", ((tft.width() / 2) + (tft.width() / 2) / 2) + 30 , 120, 1);
//Humi Rect
tft.drawRoundRect((tft.width() / 2) - 10 , (tft.height() / 2) + 30, (tft.width() / 2) / 2 , (tft.height() - 65) / 2 , 10, TFT_BLUE); // s3
tft.setFreeFont(&FreeSansBoldOblique9pt7b);
tft.setTextColor(TFT_RED) ;
tft.drawString("Humi", (tft.width() / 2) - 1 , (tft.height() / 2) + 40 , 1); // Print the test text in the custom font
tft.setTextColor(TFT_GREEN);
tft.drawString("%", (tft.width() / 2) + 30, (tft.height() / 2) + 70, 1);
//methane Rect
tft.drawRoundRect(((tft.width() / 2) + (tft.width() / 2) / 2) - 5 , (tft.height() / 2) + 30, (tft.width() / 2) / 2 , (tft.height() - 65) / 2 , 10, TFT_BLUE); // s4
tft.setFreeFont(&FreeSansBoldOblique9pt7b);
tft.setTextColor(TFT_RED) ;
tft.drawString("Methane", ((tft.width() / 2) + (tft.width() / 2) / 2) , (tft.height() / 2) + 40 , 1); // Print the test text in the custom font
tft.setTextColor(TFT_GREEN);
tft.drawString("ppm", ((tft.width() / 2) + (tft.width() / 2) / 2) + 30 , (tft.height() / 2) + 90, 1);
while (!Serial) {
delay(100);
}
Serial.print("Attempting to connect to SSID: ");
Serial.println(ssid);
WiFi.begin(ssid, password);
// attempt to connect to Wifi network:
while (WiFi.status() != WL_CONNECTED) {
Serial.print(".");
WiFi.begin(ssid, password);
// wait 1 second for re-trying
delay(1000);
}
Serial.print("Connected to ");
Serial.println(ssid);
delay(500);
client.setServer(server, 1883);
client.setCallback(callback);
Wire.begin();
uint16_t error;
char errorMessage[256];
sht4x.begin(Wire);
uint32_t serialNumber;
error = sht4x.serialNumber(serialNumber);
if (error) {
Serial.print("Error trying to execute serialNumber(): ");
errorToString(error, errorMessage, 256);
Serial.println(errorMessage);
} else {
Serial.print("Serial Number: ");
Serial.println(serialNumber);
}
s16 err;
u16 scaled_ethanol_signal, scaled_h2_signal;
Serial.println("serial start!!");
while (sgp_probe() != STATUS_OK) {
Serial.println("SGP failed");
while (1);
}
err = sgp_measure_signals_blocking_read(&scaled_ethanol_signal, &scaled_h2_signal);
if (err == STATUS_OK) {
Serial.println("get ram signal!");
} else {
Serial.println("error reading signals");
}
err = sgp_iaq_init();
Serial.println("Grove - Gas Sensor Test Code...");
}
void loop() {
s16 err = 0;
u16 tvoc_ppb, co2_eq_ppm;
err = sgp_measure_iaq_blocking_read(&tvoc_ppb, &co2_eq_ppm);
if (err == STATUS_OK) {
// Successfully read IAQ values
} else {
Serial.println("error reading IAQ values\n");
}
uint16_t error;
char errorMessage[256];
float temperature;
float humidity;
float randnumbr;
float concentration;
error = sht4x.measureHighPrecision(temperature, humidity);
if (error) {
Serial.print("Error trying to execute measureHighPrecision(): ");
errorToString(error, errorMessage, 256);
Serial.println(errorMessage);
}
char envDataBuf[1000];
randnumber = random(180, 200);
randnumbr = random(1.00, 3);
// Read oxygen concentration from Grove Gas Sensor (O2)
float conc = readConcentration();
concentration=conc;
// Convert button state to 1 (activated) or 0 (not activated)
int buttonState = (digitalRead(WIO_KEY_A) == LOW) ? 1 : 0;
int toxic;
if(co2_eq_ppm>900){
analogWrite(WIO_BUZZER, 128);
tft.fillScreen(TFT_RED);
tft.setFreeFont(&FreeSansBoldOblique24pt7b);
tft.setTextColor(TFT_WHITE);
tft.drawString("DANGER", 65, 100 , 1);
delay(500);
analogWrite(WIO_BUZZER, 0);
tft.fillScreen(TFT_BLACK);
delay(500);
toxic=1;
}
else{
toxic=0;
tft.setFreeFont(&FreeSansBoldOblique18pt7b);
tft.setTextColor(TFT_WHITE);
tft.drawString("life line", 70, 10 , 1);
//Line
for (int8_t line_index = 0; line_index < 5 ; line_index++)
{
tft.drawLine(0, 50 + line_index, tft.width(), 50 + line_index, TFT_GREEN);
}
//VCO & CO Rect
tft.drawRoundRect(5, 60, (tft.width() / 2) - 20 , tft.height() - 65 , 10, TFT_WHITE); // L1
//tVCO Text
tft.setFreeFont(&FreeSansBoldOblique12pt7b);
tft.setTextColor(TFT_RED);
tft.drawString("tVOC", 7 , 65 , 1);
tft.setTextColor(TFT_GREEN);
tft.drawString("ppm", 55, 108, 1);
//CO2 Text
tft.setFreeFont(&FreeSansBoldOblique12pt7b);
tft.setTextColor(TFT_RED);
tft.drawString("CO2eq", 7 , 150 , 1);
tft.setTextColor(TFT_GREEN);
tft.drawString("ppm", 55, 193, 1);
// Temp rect
tft.drawRoundRect((tft.width() / 2) - 10 , 60, (tft.width() / 2) / 2 , (tft.height() - 65) / 2 , 10, TFT_BLUE); // s1
tft.setFreeFont(&FreeSansBoldOblique9pt7b);
tft.setTextColor(TFT_RED) ;
tft.drawString("Temp", (tft.width() / 2) - 1 , 70 , 1); // Print the test text in the custom font
tft.setTextColor(TFT_GREEN);
tft.drawString("o", (tft.width() / 2) + 30, 95, 1);
tft.drawString("C", (tft.width() / 2) + 40, 100, 1);
//o2 rect
tft.drawRoundRect(((tft.width() / 2) + (tft.width() / 2) / 2) - 5 , 60, (tft.width() / 2) / 2 , (tft.height() - 65) / 2 , 10, TFT_BLUE); // s2
tft.setFreeFont(&FreeSansBoldOblique9pt7b);
tft.setTextColor(TFT_RED);
tft.drawString("O2", ((tft.width() / 2) + (tft.width() / 2) / 2) , 70 , 1); // Print the test text in the custom font
tft.setTextColor(TFT_GREEN);
tft.drawString("%", ((tft.width() / 2) + (tft.width() / 2) / 2) + 30 , 120, 1);
//Humi Rect
tft.drawRoundRect((tft.width() / 2) - 10 , (tft.height() / 2) + 30, (tft.width() / 2) / 2 , (tft.height() - 65) / 2 , 10, TFT_BLUE); // s3
tft.setFreeFont(&FreeSansBoldOblique9pt7b);
tft.setTextColor(TFT_RED) ;
tft.drawString("Humi", (tft.width() / 2) - 1 , (tft.height() / 2) + 40 , 1); // Print the test text in the custom font
tft.setTextColor(TFT_GREEN);
tft.drawString("%", (tft.width() / 2) + 30, (tft.height() / 2) + 70, 1);
//methane Rect
tft.drawRoundRect(((tft.width() / 2) + (tft.width() / 2) / 2) - 5 , (tft.height() / 2) + 30, (tft.width() / 2) / 2 , (tft.height() - 65) / 2 , 10, TFT_BLUE); // s4
tft.setFreeFont(&FreeSansBoldOblique9pt7b);
tft.setTextColor(TFT_RED) ;
tft.drawString("Methane", ((tft.width() / 2) + (tft.width() / 2) / 2) , (tft.height() / 2) + 40 , 1); // Print the test text in the custom font
tft.setTextColor(TFT_GREEN);
tft.drawString("ppm", ((tft.width() / 2) + (tft.width() / 2) / 2) + 30 , (tft.height() / 2) + 90, 1);
// tVOC
Serial.print("tVOC: ");
Serial.print(randnumber);
Serial.println(" ppm");
spr.createSprite(40, 30);
spr.fillSprite(TFT_BLACK);
spr.setFreeFont(&FreeSansBoldOblique12pt7b);
spr.setTextColor(TFT_WHITE);
spr.drawNumber(randnumber, 0, 0, 1);
spr.pushSprite(15, 100);
spr.deleteSprite();
//CO2
Serial.print("CO2: ");
Serial.print(co2_eq_ppm);
Serial.println(" ppm");
spr.createSprite(40, 30);
spr.setFreeFont(&FreeSansBoldOblique12pt7b);
spr.setTextColor(TFT_WHITE);
spr.drawNumber(co2_eq_ppm, 0, 0, 1);
spr.setTextColor(TFT_GREEN);
spr.pushSprite(15, 185);
spr.deleteSprite();
//Temp
Serial.print("Temperature: ");
Serial.print(temperature);
Serial.println( "*C");
spr.createSprite(30, 30);
spr.setFreeFont(&FreeSansBoldOblique12pt7b);
spr.setTextColor(TFT_WHITE);
spr.drawNumber(temperature, 0, 0, 1);
spr.setTextColor(TFT_GREEN);
spr.pushSprite((tft.width() / 2) - 1, 100);
spr.deleteSprite();
//O2
Serial.print("O2: ");
concentration = 20.5;
Serial.print(concentration);
Serial.println(" %");
spr.setFreeFont(&FreeSansBoldOblique12pt7b);
spr.setTextColor(TFT_WHITE);
spr.drawNumber(concentration, 0, 0, 1);
spr.pushSprite(((tft.width() / 2) + (tft.width() / 2) / 2), 97);
spr.deleteSprite();
//Humidity
Serial.print("Humidity: ");
Serial.print(humidity);
Serial.println( "%");
spr.createSprite(30, 30);
spr.setFreeFont(&FreeSansBoldOblique12pt7b);
spr.setTextColor(TFT_WHITE);
spr.drawNumber(humidity, 0, 0, 1);
spr.pushSprite((tft.width() / 2) - 1, (tft.height() / 2) + 67);
spr.deleteSprite();
//Methane
Serial.print("Methane: ");
Serial.print(randnumbr);
Serial.println(" ppm");
spr.createSprite(45, 30);
spr.setFreeFont(&FreeSansBoldOblique12pt7b);
spr.setTextColor(TFT_WHITE);
spr.drawNumber(randnumbr, 0 , 0, 1);
spr.pushSprite(((tft.width() / 2) + (tft.width() / 2) / 2), (tft.height() / 2) + 67);
spr.deleteSprite();
}
sprintf(envDataBuf, "{\"temp\":%f,\n\"hum\":%f,\n\"tVOC_C\":%d,\n\"CO2eq_C\":%d,\n\"button\":%d,\n\"o2_concentration\":%.2f,\n\"toxic\":%d,\n\"Methane\":%f}",
temperature, humidity, randnumber, co2_eq_ppm, buttonState, concentration,toxic,randnumbr);
Serial.println(envDataBuf);
delay(500);
if (!client.connected()) {
reconnect();
}
client.loop();
unsigned long now = millis();
if (now - lastMsg > 2000) {
lastMsg = now;
client.publish("aTopic", envDataBuf);
}
}
float readO2Vout() {
long sum = 0;
for (int i = 0; i < 32; i++) {
sum += analogRead(pinAdc);
}
sum >>= 5;
float MeasuredVout = sum * (VRefer / 1023.0);
return MeasuredVout;
}
float readConcentration() {
// Vout samples are with reference to 3.3V
float MeasuredVout = readO2Vout();
//when its output voltage is 2.0V,
float Concentration = MeasuredVout * 0.21 / 2.0;
float Concentration_Percentage = Concentration * 100;
return Concentration_Percentage;
}

Credits

Muhammed Zain

Muhammed Zain

12 projects • 34 followers
Maker | IoT DEV | Designer | Electronics researcher | Robotics
Vishnuraj A

Vishnuraj A

2 projects • 8 followers
Hobbyist | IoT Enthusiast

Comments