@@ -1,4 +1,13 @@ | |||
#!/usr/bin/env python3 | |||
""" | |||
created by waldhauser | |||
This file contains the programm to drive the arm back to middle | |||
This file is needed for the color code drive operation | |||
The plant where the robot is has to be passed as argument | |||
""" | |||
from ev3dev2.motor import Motor, OUTPUT_B, OUTPUT_C, SpeedPercent | |||
import sys | |||
@@ -1,4 +1,13 @@ | |||
#!/usr/bin/env python3 | |||
""" | |||
created by waldhauser | |||
This file contains the programm to drive the arm back to middle and drive the robot back to home | |||
This file is needed for the hard code driving operations | |||
The plant where the robot is has to be passed as argument | |||
""" | |||
from ev3dev2.motor import Motor, LargeMotor, OUTPUT_A, OUTPUT_B, OUTPUT_C, OUTPUT_D, SpeedPercent | |||
from ev3dev2.sensor.lego import TouchSensor, UltrasonicSensor | |||
from ev3dev2.sensor import INPUT_1, INPUT_4 | |||
@@ -31,8 +40,6 @@ while True: | |||
motorRight.on(SpeedPercent(-25)) | |||
break | |||
sensorTouch.wait_for_pressed(timeout_ms=None, sleep_ms=10) | |||
motorLeft.off() | |||
motorRight.off() |
@@ -1,4 +1,14 @@ | |||
#!/usr/bin/env python3 | |||
""" | |||
created by waldhauser | |||
This file contains the programm to drive the robot back to the starting position | |||
This file is needed for the color code drive operation | |||
No arguments are needed | |||
The end is determined by the UltraSonic- and TouchSensor | |||
""" | |||
from ev3dev2.motor import LargeMotor, OUTPUT_A, OUTPUT_D, SpeedPercent | |||
from ev3dev2.sensor.lego import TouchSensor, UltrasonicSensor | |||
from ev3dev2.sensor import INPUT_1, INPUT_4 |
@@ -1,9 +1,11 @@ | |||
#!/usr/bin/env pybricks-micropython | |||
''' | |||
Script to drive robot to plant. | |||
Plant number is passed as argument. | |||
''' | |||
""" | |||
created by waldhauser | |||
This file contians the programm to drive to a specific plant based on the color codes | |||
The plant where the robot is has to be passed as argument | |||
""" | |||
from ev3dev2.motor import Motor, LargeMotor, OUTPUT_A, OUTPUT_B, OUTPUT_C, OUTPUT_D, SpeedPercent | |||
from ev3dev2.sensor.lego import ColorSensor |
@@ -1,65 +0,0 @@ | |||
#!/usr/bin/env pybricks-micropython | |||
from pybricks.hubs import EV3Brick | |||
from pybricks.ev3devices import (Motor, TouchSensor, ColorSensor, | |||
InfraredSensor, UltrasonicSensor, GyroSensor) | |||
from pybricks.parameters import Port, Stop, Direction, Button, Color | |||
from pybricks.tools import wait, StopWatch, DataLog | |||
from pybricks.robotics import DriveBase | |||
from pybricks.media.ev3dev import SoundFile, ImageFile | |||
import sys | |||
def fun_1(ev3): | |||
pass | |||
def fun_2(a,b): | |||
return 1 | |||
def move_1(mo_forward_1, mo_forward_2, mo_le_ri, mo_up_down): | |||
wait(2000) | |||
#move forward | |||
mo_forward_1.run_target(500, 1250,wait=False) | |||
mo_forward_2.run_target(500, 1250) | |||
#move arm | |||
mo_le_ri.run_target(200,-50) | |||
#move sensors | |||
mo_up_down.run_target(500,2500) | |||
wait(2000) | |||
mo_up_down.run_target(500,0) | |||
#move arm | |||
mo_le_ri.run_target(200,0) | |||
#move backwards | |||
mo_forward_1.run_target(500, 0,wait=False) | |||
mo_forward_2.run_target(500, 0) | |||
def move_2(): | |||
pass | |||
def move_3(): | |||
pass | |||
ev3 = EV3Brick() | |||
motor_forward_1 = Motor(Port.A) | |||
motor_forward_2 = Motor(Port.D) | |||
motor_le_ri = Motor(Port.B, Direction.COUNTERCLOCKWISE, [8, 56]) #with gear for angle | |||
motor_up_down = Motor(Port.C) | |||
#n = int(sys.argv[1]) | |||
#if n == 1: | |||
move_1(motor_forward_1,motor_forward_2,motor_le_ri,motor_up_down) | |||
@@ -1,5 +1,11 @@ | |||
#!/usr/bin/env pybricks-micropython | |||
""" | |||
created by waldhauser | |||
This file contians the programm to drive a specfic plant with a certain distance to drive | |||
""" | |||
from ev3dev2.motor import Motor, LargeMotor, ServoMotor, OUTPUT_A, OUTPUT_B, OUTPUT_C, OUTPUT_D, SpeedPercent | |||
motorRight = LargeMotor(OUTPUT_A) |
@@ -1,5 +1,11 @@ | |||
#!/usr/bin/env pybricks-micropython | |||
""" | |||
created by waldhauser | |||
This file contians the programm to drive a specfic plant with a certain distance to drive | |||
""" | |||
from ev3dev2.motor import Motor, LargeMotor, ServoMotor, OUTPUT_A, OUTPUT_B, OUTPUT_C, OUTPUT_D, SpeedPercent | |||
motorRight = LargeMotor(OUTPUT_A) |
@@ -1,5 +1,11 @@ | |||
#!/usr/bin/env pybricks-micropython | |||
""" | |||
created by waldhauser | |||
This file contians the programm to drive a specfic plant with a certain distance to drive | |||
""" | |||
from ev3dev2.motor import Motor, LargeMotor, ServoMotor, OUTPUT_A, OUTPUT_B, OUTPUT_C, OUTPUT_D, SpeedPercent | |||
motorRight = LargeMotor(OUTPUT_A) |
@@ -1,5 +1,11 @@ | |||
#!/usr/bin/env pybricks-micropython | |||
""" | |||
created by waldhauser | |||
This file contians the programm to drive a specfic plant with a certain distance to drive | |||
""" | |||
from ev3dev2.motor import Motor, LargeMotor, ServoMotor, OUTPUT_A, OUTPUT_B, OUTPUT_C, OUTPUT_D, SpeedPercent | |||
motorRight = LargeMotor(OUTPUT_A) |
@@ -1,5 +1,11 @@ | |||
#!/usr/bin/env pybricks-micropython | |||
""" | |||
created by waldhauser | |||
This file contians the programm to drive a specfic plant with a certain distance to drive | |||
""" | |||
from ev3dev2.motor import Motor, LargeMotor, ServoMotor, OUTPUT_A, OUTPUT_B, OUTPUT_C, OUTPUT_D, SpeedPercent | |||
motorRight = LargeMotor(OUTPUT_A) |
@@ -1,5 +1,11 @@ | |||
#!/usr/bin/env pybricks-micropython | |||
""" | |||
created by waldhauser | |||
This file contians the programm to drive a specfic plant with a certain distance to drive | |||
""" | |||
from ev3dev2.motor import Motor, LargeMotor, ServoMotor, OUTPUT_A, OUTPUT_B, OUTPUT_C, OUTPUT_D, SpeedPercent | |||
motorRight = LargeMotor(OUTPUT_A) |
@@ -1,3 +1,10 @@ | |||
""" | |||
created by waldhauser | |||
This file contains the functions for the mainProg.py. | |||
The functions are part of three groups, MQTT-callbacks, functions for external threads and one normal function. | |||
""" | |||
import paho.mqtt.client as mqtt | |||
import json | |||
import threading | |||
@@ -29,21 +36,27 @@ def measure_send_data(plantID, actionID, client: mqtt.Client): | |||
sensorData["ActionID"] = actionID | |||
client.publish(Topics["ROBOT_DATA_SENSORDATA"], json.dumps(sensorData, indent=4), qos=1) | |||
#region Thread | |||
# Functions to be executed in external Thread to not block the mainProg | |||
# Functions contain the drive and sensor measurement operations | |||
def drive_plant_thread(plantID, actionID, client: mqtt.Client): | |||
""" | |||
Function to drive to plant according to number from MQTT message in thread | |||
Drive programm based on hardcoded drive programms specific for each plant | |||
Only possible to drive to one plant per execution | |||
Meassure and publish data via MQTT | |||
Drive home to starting point | |||
***If color codes are working properly this function is not needed anymore*** | |||
Args: | |||
plantID (_type_): plant to measure | |||
actionID (_type_): current ID of driving action | |||
client (mqtt.Client): current mqtt client for publishing | |||
""" | |||
# FIXME Change to color code driving | |||
errorCode = os.system(f'sshpass -p maker ssh robot@ev3dev.local python3 /home/robot/Programme/plant_{plantID}.py') | |||
# errorCode = os.system(f'sshpass -p maker ssh robot@ev3dev.local python3 /home/robot/Programme/drive_plant.py {plantID}') | |||
if errorCode != 0: | |||
if errorCode == 65280: | |||
@@ -84,12 +97,16 @@ def drive_plant_thread(plantID, actionID, client: mqtt.Client): | |||
def drive_plant_all_thread(plantIDs: list, actionID, client: mqtt.Client): | |||
""" | |||
Function to drive to plants according to numbers from MQTT message in thread | |||
Function to drive to plants according to numbers from MQTT message in thread, one or more plants possible | |||
PlantIDs have to be in ascending order | |||
Drive programm based on color codes in the flowerbed | |||
Meassure and publish data for all plants via MQTT | |||
Drive home to starting point | |||
***If color codes are working properly, only this function is needed for drive operations*** | |||
Args: | |||
plantIDs (list): Plants to drive to | |||
plantIDs (list): Plants to drive to, plants have to be in ascending order | |||
actionID (_type_): ActionID from Backend for whole drive action | |||
client (mqtt.Client): current MQTT client | |||
""" | |||
@@ -118,6 +135,7 @@ def drive_plant_all_thread(plantIDs: list, actionID, client: mqtt.Client): | |||
return | |||
# Read Sensors and store data, take picture | |||
logging.info("Measuring Sensors") | |||
try: | |||
sensordata = {} | |||
@@ -167,14 +185,19 @@ def drive_plant_all_thread(plantIDs: list, actionID, client: mqtt.Client): | |||
logging.info("Robot home") | |||
client.publish(Topics["ROBOT_DATA_ROBOTREADY"], "True", qos=1) | |||
#endregion | |||
#region MQTT callbacks | |||
# Functions to be called by the MQTT callbacks | |||
# Starting the drive operations in threads or executing the small operations directly | |||
def drive_plant(client: mqtt.Client, userdata, message: mqtt.MQTTMessage): | |||
""" | |||
Function to drive to plant according to request | |||
Starting Drive in Thread to not block main programm | |||
***If color codes are working properly this function is not needed anymore*** | |||
Args: | |||
client (mqtt.Client): current mqtt client | |||
userdata (_type_): _description_ | |||
@@ -198,6 +221,8 @@ def drive_plant_all(client: mqtt.Client, userdata, message: mqtt.MQTTMessage): | |||
Function to drive to plants according to request | |||
Starting Drive in Thread to not block main programm | |||
***If color codes are working properly, only this function is needed for drive operations*** | |||
Args: | |||
client (mqtt.Client): current MQTT client | |||
userdata (_type_): _description_ | |||
@@ -214,11 +239,14 @@ def drive_plant_all(client: mqtt.Client, userdata, message: mqtt.MQTTMessage): | |||
thread = threading.Thread(target= drive_plant_all_thread, args=(plantIDs, actionID, client), daemon=True) | |||
thread.start() | |||
def get_position(clients: mqtt.Client, userdata, message: mqtt.MQTTMessage): | |||
""" | |||
Callback function for GPS position request | |||
Function to send actual GPS position via MQTT in form of POSITION | |||
***Not implemented, available GPS-sensor was not working*** | |||
Args: | |||
client (mqtt.Client): current mqtt client | |||
userdata (_type_): _description_ | |||
@@ -237,7 +265,9 @@ def get_position(clients: mqtt.Client, userdata, message: mqtt.MQTTMessage): | |||
def get_batteryStatus(client: mqtt.Client, userdata, message: mqtt.MQTTMessage): | |||
""" | |||
Callback function for battery status request | |||
Function to read battery status from ev3 and send via MQTT in form of BATTERY | |||
Function to read battery status from EV3 and send via MQTT in form of BATTERY | |||
Reading battery level via SSH script execution | |||
Battery level shown in Volts: | |||
8,5V -> 100% | |||
5V -> 0% | |||
@@ -255,9 +285,9 @@ def get_batteryStatus(client: mqtt.Client, userdata, message: mqtt.MQTTMessage): | |||
client.publish(Topics["ROBOT_DATA_ERROR"], "Robot not connected", qos=1) | |||
return | |||
batteryLevel = round(batteryLevel / 1000000, 2) # Voltage | |||
batteryLevel = round(batteryLevel / 1000000, 2) # Conversion to Volt | |||
batteryLevel = batteryLevel - 5 | |||
batteryLevel = round(batteryLevel / 3.5, 3) *100 # Percentage | |||
batteryLevel = round(batteryLevel / 3.5, 3) *100 # Conversion to Percentage, 8,5V -> 100%, 5V -> 0% | |||
battery = { | |||
"Battery": batteryLevel | |||
@@ -270,6 +300,8 @@ def sendPicture(client: mqtt.Client): | |||
""" | |||
Takes picture and publish via MQTT | |||
***Pictures can not be send until now -> assumption of reaching maximum payload limit*** | |||
Args: | |||
client (mqtt.Client): current mqtt client | |||
""" |
@@ -1,12 +1,12 @@ | |||
""" | |||
created by waldluis | |||
created by waldlhauser | |||
This file contains the main script for the RaspberryPi of smart garden project | |||
It has the task to control the EV3 robot and take measurements with the mounted sensor | |||
It has the task to control the EV3 robot and take measurements with the mounted sensors | |||
The sensor data is published to MQTT topics to be available for the backend server | |||
Used protocol for interaction: mqtt (paho-mqtt module) | |||
Interaction with the EV3 via SSH | |||
""" | |||
""" | |||
import paho.mqtt.client as mqtt | |||
import functions |
@@ -1,4 +1,11 @@ | |||
# from picamera import PiCamera | |||
""" | |||
created by waldhauser | |||
This file contains the functions to read the sensors DHT22, TSL2561, earth humidity with MCP3008 ADC and RaspberryPi camera | |||
Every sensor can be read on its own | |||
Reading all sensors is possible with the readSensors() function and provides the data in the format of SENSORDATA dictionary | |||
""" | |||
import adafruit_dht | |||
import adafruit_tsl2561 | |||
import board | |||
@@ -83,7 +90,6 @@ def readMCP3008(): | |||
percentage = round(((1100 - percentage) / 1100) *100, 2) # 680 -> 100% moisture, 1780 -> 0% moisture | |||
if percentage > 100 or percentage < 0: # If not connected values above 100% appear | |||
percentage = 0 | |||
raise Exception("YL69 not connected") | |||
return percentage | |||
@@ -92,6 +98,7 @@ def readMCP3008(): | |||
def readSensors(sensorData): | |||
""" | |||
Read DHT22, TSL2561 and Humidity Sensor | |||
Dictionary is passed to ensure that values are available when errors occur | |||
Args: | |||
sensorData (dictionary): Dictionary of type SENSORDATA | |||
@@ -107,25 +114,25 @@ def readSensors(sensorData): | |||
try: | |||
sensorData["AirTemperature"], sensorData["AirHumidity"] = readDHT22() | |||
except Exception as e: | |||
sensorData["AirHumidity"] = 0 # otherwise old value | |||
sensorData["AirHumidity"] = 0 # No value returend if error occurs -> setting dummy value | |||
sensorData["AirTemperature"] = 0 | |||
errorMessage = str(e) + "\n" | |||
errorMessage = str(e) + "\n" # Appending received error message to later forward all occured errors | |||
# read TSL2561 | |||
try: | |||
sensorData["Brightness"] = readTSL2561() | |||
except Exception as e: | |||
sensorData["Brightness"] = 0 # otherwise old value | |||
errorMessage = errorMessage + str(e) + "\n" | |||
sensorData["Brightness"] = 0 # No value returend if error occurs -> setting dummy value | |||
errorMessage = errorMessage + str(e) + "\n" # Appending received error message to later forward all occured errors | |||
# read YL-69 | |||
try: | |||
sensorData["SoilMoisture"] = readMCP3008() | |||
except Exception as e: | |||
sensorData["SoilMoisture"] = 0 | |||
errorMessage = errorMessage + str(e) + "\n" | |||
sensorData["SoilMoisture"] = 0 # No value returend if error occurs -> setting dummy value | |||
errorMessage = errorMessage + str(e) + "\n" # Appending received error message to later forward all occured errors | |||
# combined error message | |||
# raise combined error message | |||
if errorMessage != "": | |||
raise Exception(errorMessage) | |||
@@ -133,9 +140,8 @@ def readSensors(sensorData): | |||
def takePicture(): | |||
""" | |||
Take picture and return picture | |||
Returns: | |||
_type_: _description_ | |||
Take picture and store as "picture.png" in current folder | |||
""" | |||
try: | |||
camera = PiCamera() | |||
@@ -146,14 +152,14 @@ def takePicture(): | |||
camera.capture("picture.png") | |||
camera.stop_preview() | |||
return | |||
# TODO - read position with sensor | |||
def readPosition(): | |||
""" | |||
Read and return Position | |||
***Not implemented, available GPS-sensor was not working*** | |||
Returns: | |||
_type_: _description_ | |||
""" | |||
@@ -162,7 +168,6 @@ def readPosition(): | |||
# Testing | |||
def main(): | |||
value = SENSORDATA | |||
try: |