From 7452d6aae8c16986eb4b320deee868a6cc724263 Mon Sep 17 00:00:00 2001 From: waldhauserlu78556 Date: Sat, 13 May 2023 15:19:27 +0200 Subject: [PATCH] SoilMoisture, Camera (and GPS) added --- requirements.txt | 6 +- software/roboter/raspy/defines.py | 1 + software/roboter/raspy/functions.py | 37 ++++++++++--- software/roboter/raspy/raspy_sensors.py | 74 +++++++++++++++++++++++-- 4 files changed, 103 insertions(+), 15 deletions(-) diff --git a/requirements.txt b/requirements.txt index c983847..f2128e4 100644 --- a/requirements.txt +++ b/requirements.txt @@ -29,4 +29,8 @@ urllib3==1.26.14 Werkzeug==2.2.3 zipp==3.15.0 python-ev3dev2==2.1.0.post1 -pytest \ No newline at end of file +pytest +pip==23.1.2 +# spidev==3.6 +# picamera==1.13 +numpy==1.19.5 \ No newline at end of file diff --git a/software/roboter/raspy/defines.py b/software/roboter/raspy/defines.py index 30880a4..929cf64 100644 --- a/software/roboter/raspy/defines.py +++ b/software/roboter/raspy/defines.py @@ -21,6 +21,7 @@ Topics = { "ROBOT_DATA_PICTURE": "ROBOT/DATA/PICTURE", "ROBOT_DATA_ERROR": "ROBOT/DATA/ERROR", "ROBOT_DATA_ROBOTREADY": "ROBOT/DATA/ROBOTREADY", + "ROBOT_DATA_PICTURE": "ROBOT/DATA/PICTURE", "BACKEND_ACTION_DRIVE": "BACKEND/ACTION/DRIVE", "BACKEND_ACTION_DRIVEPALL": "BACKEND/ACTION/DRIVEALL", diff --git a/software/roboter/raspy/functions.py b/software/roboter/raspy/functions.py index 84fcaa4..cf89136 100644 --- a/software/roboter/raspy/functions.py +++ b/software/roboter/raspy/functions.py @@ -21,7 +21,6 @@ def measure_send_data(plantID, actionID, client: mqtt.Client): sensorData = Sensors.readSensors() except Exception as e: logging.error(str(e)) - # TODO Error message MQTT client.publish(Topics["ROBOT_DATA_ERROR"], str(e), qos=1) sensorData["PlantID"] = plantID @@ -48,7 +47,6 @@ def drive_plant_thread(plantID, actionID, client: mqtt.Client): logging.error(f"Robot Error {errorCode} occurred") logging.info("Drive Plant aborted, Robot at starting position") client.publish(Topics["ROBOT_DATA_ERROR"], "Drive Plant aborted, Robot at starting position", qos=1) - #TODO decide about robot occupied message client.publish(Topics["ROBOT_DATA_ROBOTREADY"], "True", qos=1) return @@ -56,6 +54,9 @@ def drive_plant_thread(plantID, actionID, client: mqtt.Client): logging.info("Measuring Sensors") measure_send_data(plantID, actionID, client) + # FIXME Send Picture + # sendPicture() + logging.info("Robot driving home") errorCode = os.system(f'sshpass -p maker ssh robot@ev3dev.local python3 /home/robot/Programme/drive_back.py {plantID}') @@ -63,25 +64,24 @@ def drive_plant_thread(plantID, actionID, client: mqtt.Client): logging.error(f"Robot Error {errorCode} occurred") logging.info(f"Drive Home aborted, Robot at plant {plantID}") client.publish(Topics["ROBOT_DATA_ERROR"], f"Drive Home aborted, Robot at plant {plantID}", qos=1) - #TODO decide about robot occupied message client.publish(Topics["ROBOT_DATA_ROBOTREADY"], "True", qos=1) return logging.info("Robot home") - #TODO decide about robot occupied message client.publish(Topics["ROBOT_DATA_ROBOTREADY"], "True", qos=1) #region MQTT callbacks +# TODO Test with all sensors 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 Args: - clients (mqtt.Client): current mqtt client + client (mqtt.Client): current mqtt client userdata (_type_): _description_ message (mqtt.MQTTMessage): received DRIVE message with PlantID and ActionID """ @@ -93,8 +93,6 @@ def drive_plant(client: mqtt.Client, userdata, message: mqtt.MQTTMessage): actionID = dictMessage["ActionID"] logging.info(f"Received Drive-request to plant {plantID}, ActionID: {actionID}") - - #TODO decide about robot occupied message client.publish(Topics["ROBOT_DATA_ROBOTREADY"], "False", qos=1) thread = threading.Thread(target= drive_plant_thread, args=(plantID, actionID, client), daemon=True) @@ -107,7 +105,7 @@ def get_position(clients: mqtt.Client, userdata, message: mqtt.MQTTMessage): Function to send actual GPS position via MQTT in form of POSITION Args: - clients (mqtt.Client): current mqtt client + client (mqtt.Client): current mqtt client userdata (_type_): _description_ message (mqtt.MQTTMessage): received message """ @@ -129,7 +127,7 @@ def get_BatteryStatus(client: mqtt.Client, userdata, message: mqtt.MQTTMessage): 5V -> 0% Args: - clients (mqtt.Client): current mqtt client + client (mqtt.Client): current mqtt client userdata (_type_): _description_ message (mqtt.MQTTMessage): received message """ @@ -151,4 +149,25 @@ def get_BatteryStatus(client: mqtt.Client, userdata, message: mqtt.MQTTMessage): } client.publish(Topics["ROBOT_DATA_BATTERY"], json.dumps(battery, indent=4), qos=1) +# TODO Test needed +def sendPicture(client: mqtt.Client): + """ + Takes picture and publish via MQTT + + Args: + client (mqtt.Client): current mqtt client + """ + try: + Sensors.takePicture() + except Exception as e: + logging.error(str(e)) + client.publish(Topics["ROBOT_DATA_ERROR"], str(e), qos=1) + + with open("picture.txt", "rb") as f: + file = f.read() + byteArr = bytearray(file) + print(byteArr) + client.publish(Topics["ROBOT_DATA_IMAGE"], byteArr) + print("Published") + #endregion \ No newline at end of file diff --git a/software/roboter/raspy/raspy_sensors.py b/software/roboter/raspy/raspy_sensors.py index 0500902..455ff5e 100644 --- a/software/roboter/raspy/raspy_sensors.py +++ b/software/roboter/raspy/raspy_sensors.py @@ -3,6 +3,8 @@ import adafruit_dht import adafruit_tsl2561 import board import json +import spidev +from picamera import PiCamera from defines import SENSORDATA @@ -34,7 +36,7 @@ def readDHT22(): def readTSL2561(): """ - Reads TSL2561 brightness in Lux + Reads TSL2561 brightness in Lux and returns integer value Raises: Exception: If TSL2561 not connected properly @@ -57,8 +59,36 @@ def readTSL2561(): return brightness +def readMCP3008(): + """ + Reads YL-69 via MCP3008 ADC soil moisture in percent and returns float value + + Raises: + Exception: If YL-69 not connected properly + + Returns: + float: soil moisture [%] + """ + + channel = 0 # Input channel into MCP3008 ADC + try: + spi = spidev.SpiDev() + spi.open(0,0) + spi.max_speed_hz = 1000000 + except: + raise Exception("YL69 not connected") + + val = spi.xfer2([1,(8+channel) << 4, 0]) + data = ((val[1] & 3) << 9) +val[2] + percentage = data - 680 # Return values between ~1780 and ~680 + percentage = round((1100 - percentage) / 1100, 2) # 680 -> 100% moisture, 1780 -> 0% moisture + + if percentage > 1 or percentage < 0: # If not connected values above 100% appear + percentage = 0 + raise Exception("YL69 not connected") + + return percentage -# TODO SoilMoisture Sensor Function # TODO Function for all sensors @@ -69,6 +99,7 @@ def readSensors(): Raises: Exception: DHT22 not connected Exception: TSL2561 not connected + Exception: YL69 not connected Returns: dict: Sensordata @@ -76,6 +107,7 @@ def readSensors(): sensorData = SENSORDATA errorMessage = "" + # read DHT22 try: sensorData["AirTemperature"], sensorData["AirHumidity"] = readDHT22() except Exception as e: @@ -83,12 +115,20 @@ def readSensors(): sensorData["AirTemperature"] = 0 errorMessage = str(e) + "\n" + # read TSL2561 try: sensorData["Brightness"] = readTSL2561() except Exception as e: sensorData["Brightness"] = 0 # otherwise old value errorMessage = errorMessage + str(e) + "\n" + # read YL-69 + try: + sensorData["SoilMoisture"] = readMCP3008() + except Exception as e: + sensorData["SoilMoisture"] = 0 + errorMessage = errorMessage + str(e) + "\n" + # combined error message if errorMessage != "": raise Exception(errorMessage) @@ -96,16 +136,25 @@ def readSensors(): return sensorData -# TODO - take picture function +# TODO - Test needed def takePicture(): """ Take picture and return picture Returns: _type_: _description_ """ - picture = "" + try: + camera = PiCamera() + except: + raise Exception("Camera not connected") + return + + camera.start_preview() + camera.capture("picture.png") + print("Camera on") + camera.stop_preview() - return picture + return # TODO - read position with sensor @@ -118,3 +167,18 @@ def readPosition(): """ position = "" return position + + +# Testing + +def main(): + value = SENSORDATA + try: + takePicture() + except Exception as e: + print(str(e)) + + print(value) + +if __name__ == "__main__": + main() \ No newline at end of file