Project Overview: TechFarming - Revolutionizing Agriculture with Data-Driven Precision
Introduction:
Greetings, dear readers! I am Lungchuingam, the mind behind "TechFarming," an ambitious agricultural e-commerce project aimed at transforming the industry through cutting-edge technologies. This endeavor seeks to create a data-driven marketing system, seamlessly integrating hardware and software to enhance farming practices.
Technical Stack:
-
Technology Stack: MySQL for the database, React for the front-end, and Express/Node for the server from the robust foundation of TechFarming.
-
Rover Design:
- Equipped with sensors, the rover's mission is to gather crucial soil parameters (pH, NPK, Moisture) and environmental data (temperature, humidity, rain).
- YOLOv5 technology powers an AI/HD camera, detecting pests and monitoring plant health.
-
Rover Control:
- Manual Operation: Implemented with a camera for user oversight and algorithms for crop avoidance.
- Autonomous Control: Utilizing LiDAR and GPS modules, the rover navigates fields, collecting valuable gray value data for analysis.
-
Data Processing:
- Computer Vision: Images and data collected by the rover are processed using CNN algorithms and TensorFlow.
- Data Storage: Continuous improvement is ensured by storing images and data for further model training and expanding datasets for enhanced learning.
Arduino Code - Rover Control:
#include <Servo.h>
#include <Wire.h>
#include <Adafruit_MotorShield.h>
#include <Adafruit_PWMServoDriver.h>
#include <SoftwareSerial.h>
#include <ESP8266WiFi.h>
#include <ESP8266HTTPClient.h>
SoftwareSerial voiceSerial(10, 11);
Adafruit_MotorShield AFMS = Adafruit_MotorShield();
Adafruit_DCMotor *frontLeftMotor = AFMS.getMotor(1);
Adafruit_DCMotor *frontRightMotor = AFMS.getMotor(2);
Adafruit_DCMotor *backLeftMotor = AFMS.getMotor(3);
Adafruit_DCMotor *backRightMotor = AFMS.getMotor(4);
Adafruit_DCMotor *additionalLeftMotor = AFMS.getMotor(5);
Adafruit_DCMotor *additionalRightMotor = AFMS.getMotor(6);
const int buzzer = 9;
const int additionalMotorSwitchPin = 7;
Servo cameraServo;
const char *ssid = "YourWiFiSSID";
const char *password = "YourWiFiPassword";
const String serverUrl = "http://localhost:9000/api/rover-control";
void setup()
{
AFMS.begin();
frontLeftMotor->setSpeed(255);
frontRightMotor->setSpeed(255);
backLeftMotor->setSpeed(255);
backRightMotor->setSpeed(255);
voiceSerial.begin(9600);
cameraServo.attach(9);
// Set up additional motor switch
pinMode(additionalMotorSwitchPin, INPUT);
pinMode(buzzer, OUTPUT);
// Connect to WiFi
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED)
{
delay(1000);
Serial.println("Connecting to WiFi...");
}
Serial.println("Connected to WiFi");
// Initialize LiDAR, GPS, and computer vision components here
}
void loop()
{
// Check for voice commands
if (voiceSerial.available() > 0)
{
String voiceCommand = voiceSerial.readStringUntil('\n');
processVoiceCommand(voiceCommand);
}
void checkServerCommands() {
// Implement code to check for commands from the server
// Example: You can use the HTTPClient to send a request to the server
// and parse the response to get the rover control command.
// Use the sendRoverControlRequest function for communication.
}
checkServerCommands();
// Implement autonomous navigation using computer vision, LiDAR, and GPS
// Add code to handle motor control based on the autonomous navigation results
// Check the additional motor switch state
if (digitalRead(additionalMotorSwitchPin) == HIGH)
{
activateAdditionalMotors();
additionalLeftMotor->setSpeed(255);
additionalRightMotor->setSpeed(255);
}
}
void processVoiceCommand(String command)
{
command.toLowerCase();
if (command.startsWith("hope"))
{
if (command.indexOf("move forward") != -1)
{
moveForward();
}
else if (command.indexOf("backward") != -1)
{
moveBackward();
}
else if (command.indexOf("turn right") != -1)
{
turnRight();
}
else if (command.indexOf("turn left") != -1)
{
turnLeft();
}
else if (command.indexOf("stop") != -1)
{
stop();
}
else if (command.indexOf("sound horn") != -1)
{
soundHorn();
}
}
else if (command.startsWith("hope! this is lucky your master, good morning"))
{
greetMaster();
}
}
void greetMaster()
{
// Implement actions when the master is greeted
// For example, you can make the rover respond in some way
}
void soundHorn()
{
for (int i = 0; i < 3; ++i) {
tone(buzzer, 1000);
delay(3000);
noTone(buzzer);
delay(2000);
}
}
void moveForward()
{
frontLeftMotor->run(FORWARD);
frontRightMotor->run(FORWARD);
backLeftMotor->run(FORWARD);
backLeftMotor->run(FORWARD);
}
void moveBackward()
{
frontLeftMotor->run(BACKWARD);
frontRightMotor->run(BACKWARD);
backRightMotor->run(BACKWARD);
backRightMotor->run(BACKWARD);
}
void turnLeft()
{
frontLeftMotor->run(BACKWARD);
frontRightMotor->run(FORWARD);
backLeftMotor->run(BACKWARD);
backRightMotor->run(FORWARD);
}
void turnRight()
{
frontLeftMotor->run(FORWARD);
frontRightMotor->run(BACKWARD);
backLeftMotor->run(FORWARD);
backRightMotor->run(BACKWARD);
}
void stop()
{
frontLeftMotor->run(RELEASE);
frontRightMotor->run(RELEASE);
backLeftMotor->run(RELEASE);
backRightMotor->run(RELEASE);
}
void activateAdditionalMotors()
{
void moveForward()
{
additionalLeftMotor->run(FORWARD);
additionalRightMotor->run(FORWARD);
}
void moveBackward()
{
additionalLeftMotor->run(BACKWARD);
additionalRightMotor->run(BACKWARD);
}
void turnLeft()
{
additionalLeftMotor->run(BACKWARD);
additionalRightMotor->run(FORWARD);
}
void turnRight()
{
additionalLeftMotor->run(FORWARD);
additionalLeftMotor->run(BACKWARD);
}
void stop()
{
additionalLeftMotor->run(RELEASE);
additionalRightMotor->run(RELEASE);
}
}
void sendRoverControlRequest(String command)
{
HTTPClient http;
http.begin(serverUrl);
http.addHeader("Content-Type", "application/json");
String requestBody = "{\"command\": \"" + command + "\"}";
int httpResponseCode = http.POST(requestBody);
http.end();
}
Arduino Code - Soil Parameters:
#include <Wire.h>
#include <Adafruit_Sensor.h>
#include <DHT.h>
#include <SoftwareSerial.h>
#include <WiFiClient.h>
#include <ESP8266WiFi.h>
#include <ESP8266HTTPClient.h>
SoftwareSerial espSerial(2, 3);
DHT dht(7, DHT22);
const char* ssid = "YourWiFiSSID";
const char* password = "YourWiFiPassword";
const char* serverUrl = "http://localhost:9000/api/soil-data";
void setup() {
Serial.begin(9600);
espSerial.begin(9600);
// Connect to Wi-Fi
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(1000);
Serial.println("Connecting to WiFi...");
}
Serial.println("Connected to WiFi");
}
void loop() {
float temperature = dht.readTemperature();
float humidity = dht.readHumidity();
// Read data from other soil sensors
float npkValue = readNPKSensor();
float phValue = readPHSensor();
float moistureValue = readMoistureSensor();
float waterValue = readWaterSensor();
if (isnan(temperature) || isnan(humidity)) {
Serial.println("Failed to read from DHT sensor");
return;
}
String data = "temperature=" + String(temperature) +
"&humidity=" + String(humidity) +
"&npk=" + String(npkValue) +
"&ph=" + String(phValue) +
"&moisture=" + String(moistureValue) +
"&water=" + String(waterValue);
sendDataToServer(data);
delay(60000);
}
float readNPKSensor() {
int npkSensorValue = analogRead(A1);
float npkValue = map(npkSensorValue, 0, 1023, 0, 10);
return npkValue;
}
float readPHSensor() {
int phSensorValue = analogRead(A2);
float phValue = map(phSensorValue, 0, 1023, 0, 14);
return phValue;
}
float readMoistureSensor() {
int moistureSensorValue = analogRead(A3);
float moistureValue = map(moistureSensorValue, 0, 1023, 0, 100);
return moistureValue;
}
float readWaterSensor() {
int waterSensorValue = analogRead(A4);
float waterValue = map(waterSensorValue, 0, 1023, 0, 100);
return waterValue;
}
void sendDataToServer(String data) {
WiFiClient client;
HTTPClient http;
http.begin(client, serverUrl);
http.addHeader("Content-Type", "application/x-www-form-urlencoded");
int httpResponseCode = http.POST(data);
if (httpResponseCode > 0) {
String response = http.getString();
Serial.println("HTTP Response Code: " + String(httpResponseCode));
Serial.println(response);
} else {
Serial.println("Error on HTTP request");
}
http.end();
}
Server Code - Rover Control:
<!-- ControllingPage.html -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Hope--Rover Control</title>
<script src="https://unpkg.com/nipplejs@0.11.0/dist/nipplejs.min.js"></script>
<script src="https://kit.fontawesome.com/a076d05399.js" crossorigin="anonymous"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css"
integrity="sha384-FfE5i1BgBpNBvKU8a4P3o2NBsKbRjIo4gg5ZUnkQXa3q2j50QC3rWUE5Xl8qDWfP" crossorigin="anonymous">
<style>
body {
margin: 0;
padding: 0;
box-sizing: border-box;
}
.rover-controlling-container {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
height: 100%;
width: 100%;
}
.rover-controlling-container h1 {
color: #744bdd;
}
.rover-controlling-container h1 span:nth-child(1) {
color: #43d843;
}
.rover-controlling-container h1 span:nth-child(2) {
color: #f5d20b;
}
#video-stream {
width: 640px;
height: 480px;
}
.rover-controlling-container .rover-controlling-buttons {
margin-top: 30px;
}
.rover-controlling-container .rover-controlling-buttons .controls table tr td button{
height: 100px;
width: 100px;
background-color: #43d843;
border-radius: 50%;
border: none;
color: #fafafa;
cursor: pointer;
transition: all .5s ease-in-out;
}
.rover-controlling-container .rover-controlling-buttons .controls table tr td button:hover{
background-color: #15ca15;
box-shadow: 5px 5px 10px #555;
}
</style>
</head>
<body>
<div class="rover-controlling-container">
<h1><span>Tech</span><span>Farming</span> Rover - Hope</h1>
<!-- Live video stream -->
<video id="video-stream" autoplay></video>
<!-- Rover controls -->
<div class="rover-controlling-buttons">
<div id="controls" class="controls">
<table>
<tr>
<td></td>
<td><button onclick="sendCommand('moveForward')">Forward</button></td>
<td></td>
</tr>
<tr>
<td> <button onclick="sendCommand('turnLeft')">Left</button></td>
<td> <button onclick="sendCommand('stop')">Stop</button></td>
<td> <button onclick="sendCommand('turnRight')">Right</button></td>
</tr>
<tr>
<td></td>
<td> <button onclick="sendCommand('moveBackward')">Backward</button></td>
<td></td>
</tr>
</table>
</div>
<button onclick="sendCommand('activateAdditionalMotors')">Activate Additional Motors</button>
</div>
<!-- Camera servo control -->
<div id="joystick-container" class="joystick">
<div id="joystick-handle"></div>
</div>
</div>
<script>
// Function to send rover control commands to the server
function sendCommand(command) {
fetch(`http://localhost:9000/api/rover-control?command=${command}`, {
method: 'POST',
});
}
// Function to start the video stream from the rover camera
async function startVideoStream() {
const videoElement = document.getElementById('video-stream');
try {
const stream = await navigator.mediaDevices.getUserMedia({ video: true });
videoElement.srcObject = stream;
} catch (error) {
console.error('Error accessing camera:', error);
}
}
function initializeJoystick() {
const joystickContainer = document.getElementById('joystick-container');
const joystickHandle = document.getElementById('joystick-handle');
// Create a joystick using nipplejs
const joystick = nipplejs.create({
zone: joystickContainer,
mode: 'static',
position: { top: '50%', left: '50%' },
color: 'blue',
});
function moveJoystickHandle(data) {
const normalizedX = data.vector.x / 50;
const normalizedY = data.vector.y / 50;
// Calculate angle and magnitude
const angle = Math.atan2(normalizedY, normalizedX) * (180 / Math.PI) + 180;
const magnitude = Math.min(100, Math.sqrt(normalizedX ** 2 + normalizedY ** 2) * 100);
// Adjust the position of the joystick handle based on joystick movements
const handleRadius = 25; // Half of the joystick handle width/height
const handleX = magnitude * Math.cos(angle * (Math.PI / 180)) - handleRadius;
const handleY = magnitude * Math.sin(angle * (Math.PI / 180)) - handleRadius;
// Update the position of the joystick handle
joystickHandle.style.transform = `translate(${handleX}px, ${handleY}px)`;
// Use JavaScript to send the camera control command to the server
fetch(`http://localhost:9000/api/rover-control?command=adjustCamera&angle=${angle}&magnitude=${magnitude}`, {
method: 'POST',
});
}
joystick.on('move', (event, data) => {
moveJoystickHandle(data);
});
// Handle mouse move event for desktop
joystickContainer.addEventListener('mousemove', (event) => {
if (event.buttons === 1) {
// Only move joystick handle if the left mouse button is pressed
const rect = joystickContainer.getBoundingClientRect();
const x = event.clientX - rect.left;
const y = event.clientY - rect.top;
const normalizedX = (x - rect.width / 2) / (rect.width / 2);
const normalizedY = (y - rect.height / 2) / (rect.height / 2);
moveJoystickHandle({ vector: { x: normalizedX * 50, y: normalizedY * 50 } });
}
});
// Handle touch move event for tablets and phones
joystickContainer.addEventListener('touchmove', (event) => {
event.preventDefault(); // Prevent default touch behavior (e.g., scrolling)
const touch = event.touches[0];
const rect = joystickContainer.getBoundingClientRect();
const x = touch.clientX - rect.left;
const y = touch.clientY - rect.top;
const normalizedX = (x - rect.width / 2) / (rect.width / 2);
const normalizedY = (y - rect.height / 2) / (rect.height / 2);
moveJoystickHandle({ vector: { x: normalizedX * 50, y: normalizedY * 50 } });
});
}
// Start the video stream when the page loads
window.onload = () => {
startVideoStream();
initializeJoystick();
};
</script>
</body>
</html>
Professional Collaboration:
For collaboration opportunities, please visit my GitHub repository. Your insights and collaboration are invaluable to the success of TechFarming.
Conclusion:
I extend my sincere gratitude for your time and consideration. Your response will undoubtedly propel TechFarming towards achieving its ambitious goals. For inquiries or collaborations, feel free to reach out.
Best regards,
Lungchuingam