Md. Khairul Alam
Published © GPL3+

Covid Warrior 1

A 4WD Robot which deactivates pathogens including COVID-19 utilizing UVC light from a surface.

AdvancedFull instructions providedOver 2 days2,224

Things used in this project

Hardware components

DFRobot Rover 5 Tank Chassis
×1
Raspberry Pi 3 Model B
Raspberry Pi 3 Model B
×1
Camera Module
Raspberry Pi Camera Module
×1
Arduino UNO
Arduino UNO
×1
Adafruit Motor Shield for Arduino kit - v1.2
×1
PIR Motion Sensor (generic)
PIR Motion Sensor (generic)
×4
HC-05 Bluetooth Module
HC-05 Bluetooth Module
×1
Li-ion battery
×1

Software apps and online services

MIT App Inventor 2
MIT App Inventor 2
Arduino IDE
Arduino IDE
Raspbian
Raspberry Pi Raspbian

Hand tools and fabrication machines

3D Printer (generic)
3D Printer (generic)
Soldering iron (generic)
Soldering iron (generic)
Multitool, Screwdriver
Multitool, Screwdriver

Story

Read more

Schematics

Schematic

Fritzing schematic for Arduino and Adafruit Motor Shield

Reference

Far-UVC

Dose-response

Reference

Reference

Mobile App View (Page1)

Mobile App View (Page2)

Mobile App View (Page2)

Screenshot of App Development

Developed by MIT App Inventor

Screenshot of App Development {2}

MIT App Inventor View

Raspberry Pi Camera Connection

Code

Arduino Code

Arduino
#include <AFMotor.h>
#include <SoftwareSerial.h>
SoftwareSerial bluetoothSerial(9, 10); // RX, TX

AF_DCMotor front_right(1);
AF_DCMotor front_left(2);
AF_DCMotor back_right(3);
AF_DCMotor back_left(4);

int pir1 = 14;
int pir2 = 15;
int pir3 = 16;
int pir4 = 17;

boolean pirStat1 = false;
boolean pirStat2 = false; 
boolean pirStat3 = false; 
boolean pirStat4 = false;  

int vuc_lamp = 13;

int manualSpeed = 160;

boolean living_object = false; 

char btCommand = 'S';
char prevCommand = 'A';
int velocity = 0;   
unsigned long timer0 = 2000;  //Stores the time (in millis since execution started) 
unsigned long timer1 = 0;  //Stores the time when the last command was received from the phone

String inputString = "";
String command = "";
String value = "";
boolean stringComplete = false; 

void setup() {
  
  bluetoothSerial.begin(9600); //set the baud rate for your bluetooth mode
  
  pinMode(pir1, INPUT);
  pinMode(pir2, INPUT);
  pinMode(pir3, INPUT);
  pinMode(pir4, INPUT);
  pinMode(uvc_lamp, OUTPUT);
  
  // turn on motor
  front_right.setSpeed(150);
  front_left.setSpeed(150);
  back_right.setSpeed(150);
  back_left.setSpeed(150);
 
  front_right.run(RELEASE);
  front_left.run(RELEASE);
  back_right.run(RELEASE);
  back_left.run(RELEASE);

  inputString.reserve(50);  // reserve 50 bytes in memory to save for string manipulation 
  command.reserve(50);
  value.reserve(50);
}

void loop() {

//  front_right.setSpeed(manualSpeed);
//  front_left.setSpeed(manualSpeed);
//  back_right.setSpeed(manualSpeed);
//  back_left.setSpeed(manualSpeed);

  pirStat1 = digitalRead(pir1);
  pirStat2 = digitalRead(pir2);
  pirStat3 = digitalRead(pir3);
  pirStat4 = digitalRead(pir4); //if any sensor detect motor state goes to high
   
  if (pirStat1 == HIGH || pirStat2 == HIGH || pirStat3 == HIGH || pirStat4 == HIGH) {            // if motion detected
   living_object = true; 
  }  
  bluetoothControl();
  
}

motor.run(FORWARD);
motor.run(BACKWARD);
motor.run(RELEASE);

void run_forward(){
   front_right.run(FORWARD);
   front_left.run(FORWARD);
   back_right.run(FORWARD);
   back_left.run(FORWARD);
 }

void run_backward(){
   front_right.run(BACKWARD);
   front_left.run(BACKWARD);
   back_right.run(BACKWARD);
   back_left.run(BACKWARD);
 }

void stop_position(){
   front_right.run(RELEASE);
   front_left.run(RELEASE);
   back_right.run(RELEASE);
   back_left.run(RELEASE);
 }

void rotate_write(){
   front_right.run(BACKWARD);
   front_left.run(FORWARD);
   back_right.run(BACKWARD);
   back_left.run(FORWARD);
 }

void rotate_left(){
   front_right.run(FORWARD);
   front_left.run(BACKWARD);
   back_right.run(FORWARD);
   back_left.run(BACKWARD);
 }


 void serialEvent() {
  while (bluetoothSerial.available()) {
    // get the new byte:
    char inChar = (char)bluetoothSerial.read(); 
    //Serial.write(inChar);
    // add it to the inputString:
    inputString += inChar;
    // if the incoming character is a newline or a carriage return, set a flag
    // so the main loop can do something about it:
    if (inChar == '\n' || inChar == '\r') {
      stringComplete = true;
    } 
  }
}


void bluetoothControl(){
  if(bluetoothSerial.available() > 0){ 
    timer1 = millis();   
    prevCommand = btCommand;
    btCommand = bluetoothSerial.read(); 
    //Change pin mode only if new command is different from previous.   
    if(btCommand!=prevCommand){
      //Serial.println(command);
      switch(btCommand){
      case 'F':  
        run_forward();
        break;
      case 'B':  
        run_backward();
        break;
      case 'L':  
        rotate_left();
        break;
      case 'R':
        rotate_right();
        break;
      case 'S':  
        stop_position();
        break; 
      case 'U':  //uvc 
        if(!living_object)
          digitalWrite(uvc_lamp, HIGH);
        break;
      case 'V':  //uvc 
        digitalWrite(uvc_lamp, LOW);
        break;       
      default:  //Get velocity
        if(btCommand=='q'){
          velocity = 255;  //Full velocity
          manualSpeed = velocity;
        }
        else{ 
          //Chars '0' - '9' have an integer equivalence of 48 - 57, accordingly.
          if((btCommand >= 48) && (btCommand <= 57)){ 
            //Subtracting 48 changes the range from 48-57 to 0-9.
            //Multiplying by 25 changes the range from 0-9 to 0-225.
            velocity = (btCommand - 48)*25;       
            manualSpeed = velocity;
          }
        }
      }
    }
  } 
}

Code for Raspberry Pi

Python
This code is used to webstream video from raspberry pi using pi camera.
# Web streaming example
# Source code from the official PiCamera package
# http://picamera.readthedocs.io/en/latest/recipes2.html#web-streaming

import io
import picamera
import logging
import socketserver
from threading import Condition
from http import server

PAGE="""\
<html>
<head>
<title>COVID Warrior Robot</title>
</head>
<body>
<center><h3>COVID Warrior Robot</h3></center>
<center><img src="stream.mjpg" width="380" height="340"></center>
</body>
</html>
"""

class StreamingOutput(object):
    def __init__(self):
        self.frame = None
        self.buffer = io.BytesIO()
        self.condition = Condition()

    def write(self, buf):
        if buf.startswith(b'\xff\xd8'):
            # New frame, copy the existing buffer's content and notify all
            # clients it's available
            self.buffer.truncate()
            with self.condition:
                self.frame = self.buffer.getvalue()
                self.condition.notify_all()
            self.buffer.seek(0)
        return self.buffer.write(buf)

class StreamingHandler(server.BaseHTTPRequestHandler):
    def do_GET(self):
        if self.path == '/':
            self.send_response(301)
            self.send_header('Location', '/index.html')
            self.end_headers()
        elif self.path == '/index.html':
            content = PAGE.encode('utf-8')
            self.send_response(200)
            self.send_header('Content-Type', 'text/html')
            self.send_header('Content-Length', len(content))
            self.end_headers()
            self.wfile.write(content)
        elif self.path == '/stream.mjpg':
            self.send_response(200)
            self.send_header('Age', 0)
            self.send_header('Cache-Control', 'no-cache, private')
            self.send_header('Pragma', 'no-cache')
            self.send_header('Content-Type', 'multipart/x-mixed-replace; boundary=FRAME')
            self.end_headers()
            try:
                while True:
                    with output.condition:
                        output.condition.wait()
                        frame = output.frame
                    self.wfile.write(b'--FRAME\r\n')
                    self.send_header('Content-Type', 'image/jpeg')
                    self.send_header('Content-Length', len(frame))
                    self.end_headers()
                    self.wfile.write(frame)
                    self.wfile.write(b'\r\n')
            except Exception as e:
                logging.warning(
                    'Removed streaming client %s: %s',
                    self.client_address, str(e))
        else:
            self.send_error(404)
            self.end_headers()

class StreamingServer(socketserver.ThreadingMixIn, server.HTTPServer):
    allow_reuse_address = True
    daemon_threads = True

with picamera.PiCamera(resolution='640x480', framerate=24) as camera:
    output = StreamingOutput()
    #Uncomment the next line to change your Pi's Camera rotation (in degrees)
    #camera.rotation = 90
    camera.start_recording(output, format='mjpeg')
    try:
        address = ('', 8000)
        server = StreamingServer(address, StreamingHandler)
        server.serve_forever()
    finally:
        camera.stop_recording()

App Source

Scratch
MIT App Inventor Source aia
No preview (download only).

Credits

Md. Khairul Alam

Md. Khairul Alam

64 projects • 568 followers
Developer, Maker & Hardware Hacker. Currently working as a faculty at the University of Asia Pacific, Dhaka, Bangladesh.

Comments