Added PythonDoc and simplified drive thread

This commit is contained in:
waldluis 2023-04-24 15:48:53 +02:00
parent 0c08ab1d8b
commit b798e138fa
2 changed files with 156 additions and 105 deletions

View File

@ -1,98 +1,104 @@
"""
created by waldluis
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
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 paho.mqtt.client as mqtt
import json import json
import threading import threading
import os import os
import signal
import time import time
from raspy_sensors import RaspySensors from raspy_sensors import RaspySensors
from software.defines import Topics from software.defines import Topics, RASPI_CLIENT_ID, MQTT_BROKER_GLOBAL
#region global Varaibles #region global Varaibles
#sensors:RaspySensors()
leftRight = 50
plantID = 0
sensorData = { sensors: RaspySensors
"Air Temperature [°C]" : 0,
"Air Humidity [%]" : 0,
"Earth Humidity [%]" : 0,
"Brightness [Lux]" : 0,
"Plant ID": 0,
"Action ID": 0
}
gpsPosition = {
"Position": 0,
"Action ID": 0
}
batteryStatus = {
"Battery": 0,
"Action ID": 0
}
#endregion #endregion
#region global functions #region global functions
def measure_send_data(plantID, actionID): # TODO auslagern
'''Measure data for one plant via sensor class and send via MQTT''' def measure_send_data(plantID, actionID, client: mqtt.Client):
"""
Reads all sensors and publishes data via MQTT
Args:
plantID (_type_): plant to measure
actionID (_type_): current ID of driving action
client (mqtt.Client): current mqtt client for publishing
"""
sensorData = sensors.readSensors() sensorData = sensors.readSensors()
sensorData["Plant_ID"] = plantID sensorData["PlantID"] = plantID
sensorData["Action_ID"] = actionID sensorData["ActionID"] = actionID
client.publish(Topics["ROBOT_DATA_SENSORDATA"], json.dumps(sensorData, indent=4)) client.publish(Topics["ROBOT_DATA_SENSORDATA"], json.dumps(sensorData, indent=4))
# TODO auslagern
def drive_plant_thread(plantID, actionID, client: mqtt.Client):
"""
Function to drive to plant according to number from MQTT message in thread
Meassure and publish data via MQTT
Drive home to starting point
Args:
plantID (_type_): plant to measure
actionID (_type_): current ID of driving action
client (mqtt.Client): current mqtt client for publishing
"""
os.system(f'sshpass -p maker ssh robot@ev3dev.local python3 /home/robot/Programme/plant_{plantID}.py')
#CHECK if working properly
print("Measuring Sensors")
measure_send_data(plantID, actionID, client)
def drive_home():
'''Function to drive robot back to starting position in thread'''
print("Robot driving home") print("Robot driving home")
if plantID % 2 == 0:
leftRight = -50 #rotating left
else:
leftRight = 50 #rotating right
os.system(f'sshpass -p maker ssh robot@ev3dev.local python3 /home/robot/Programme/drive_back.py {leftRight}') os.system(f'sshpass -p maker ssh robot@ev3dev.local python3 /home/robot/Programme/drive_back.py {leftRight}')
print("Robot home") print("Robot home")
#TODO decide about robot occupied message #TODO decide about robot occupied message
#client.publish("ROBOT/DATA/OCCUPIED", "false") #client.publish("ROBOT/DATA/OCCUPIED", "false")
def on_connect(client: mqtt.Client, userdata, flags, rc):
"""
This method gets called, when it connects to a mqtt broker.
It is used to subscribe to the specific topics
def drive_plant_thread(): Args:
'''Function to drive to plant according to number from MQTT message in thread''' client (mqtt.Client): current mqtt client
os.system(f'sshpass -p maker ssh robot@ev3dev.local python3 /home/robot/Programme/plant_{plantID}.py') userdata (_type_): _description_
print("Raising Signal to meassure") flags (_type_): _description_
signal.raise_signal(signal.SIGUSR1) rc (_type_): _description_
#TODO alles hier ohne weitere Threads """
if rc == 0:
#Add callbacks
client.message_callback_add("ROBOT/DATA", send_data_json) #Testing
client.message_callback_add(Topics["ROBOT_ACTION_DRIVE"], drive_plant)
client.message_callback_add(Topics["ROBOT_ACTION_GETPOSITION"], get_position)
client.message_callback_add(Topics["ROBOT_ACTION_GETBATTERY"], get_BatteryStatus)
#Subscribe to topics
client.subscribe("ROBOT/DATA") #Testing
client.subscribe(Topics["ROBOT_ACTION_DRIVE"])
client.subscribe(Topics["ROBOT_ACTION_GETPOSITION"])
client.subscribe(Topics["ROBOT_ACTION_GETBATTERY"])
def init_mqtt(): print("MQTT initialized")
'''Initialise MQTT client'''
mqttBroker = "mqtt.eclipseprojects.io"
global client
client = mqtt.Client("Robot")
#Add callbacks
client.message_callback_add("ROBOT/DATA", send_data_json) #Testing
client.message_callback_add(Topics["ROBOT_ACTION_DRIVE"], drive_plant)
client.message_callback_add(Topics["ROBOT_ACTION_GETPOSITION"], get_position)
client.message_callback_add(Topics["ROBOT_ACTION_GETBATTERY"], get_BatteryStatus)
client.connect(mqttBroker) #Has to be before subscribing
#Subscribe to topics
client.subscribe("ROBOT/DATA") #Testing
client.subscribe(Topics["ROBOT_ACTION_DRIVE"])
client.subscribe(Topics["ROBOT_ACTION_GETPOSITION"])
client.subscribe(Topics["ROBOT_ACTION_GETBATTERY"])
def signal_measure(signum, frame):
'''Signal function to measure one plant and start driving home'''
print("Measuring Sensors")
#measure_send_data()
print("Driving Home")
drive_home()
#endregion #endregion
# TODO auslagern
#region MQTT callbacks #region MQTT callbacks
#Testing #Testing
@ -102,30 +108,43 @@ def send_data_json(clients: mqtt.Client, userdata, message: mqtt.MQTTMessage):
print("Received data: ", json.dumps(dataDict)) print("Received data: ", json.dumps(dataDict))
# CHECK if working properly
def drive_plant(clients: mqtt.Client, userdata, message: mqtt.MQTTMessage): def drive_plant(clients: mqtt.Client, userdata, message: mqtt.MQTTMessage):
'''Function to drive to plant according to request """
Starting Drive in Thread''' Function to drive to plant according to request
global plantID, leftRight Starting Drive in Thread
#TODO define MQTT message
plantID = int(message.payload.decode("UTF-8")) Args:
clients (mqtt.Client): current mqtt client
userdata (_type_): _description_
message (mqtt.MQTTMessage): received message
"""
dictMessage = json.loads(str(message.payload.decode("UTF-8")))
plantID = dictMessage["PlantID"]
actionID = dictMessage["ActionID"]
print(f"received drive to plant {plantID}") print(f"received drive to plant {plantID}")
if plantID % 2 == 0: thread = threading.Thread(target= drive_plant_thread, args=(plantID, actionID, clients), daemon=True)
leftRight = -50 #rotating left
else:
leftRight = 50 #rotating right
thread = threading.Thread(target= drive_plant_thread, daemon=True)
thread.start() thread.start()
def get_position(clients: mqtt.Client, userdata, message: mqtt.MQTTMessage): def get_position(clients: mqtt.Client, userdata, message: mqtt.MQTTMessage):
'''Callback function for GPS position request """
Function to send actual GPS position via MQTT''' Callback function for GPS position request
Function to send actual GPS position via MQTT
#[ ]TODO Write Sensor Function Args:
client.publish("ROBOT/DATA/POSITION", json.dumps(gpsPosition, indent=4)) clients (mqtt.Client): current mqtt client
userdata (_type_): _description_
message (mqtt.MQTTMessage): received message
"""
# TODO Write Sensor Function
position = {
"Position": ""
}
clients.publish(Topics["ROBOT_DATA_POSITION"], json.dumps(position, indent=4))
def get_BatteryStatus(clients: mqtt.Client, userdata, message: mqtt.MQTTMessage): def get_BatteryStatus(clients: mqtt.Client, userdata, message: mqtt.MQTTMessage):
@ -134,13 +153,17 @@ def get_BatteryStatus(clients: mqtt.Client, userdata, message: mqtt.MQTTMessage)
Function to read battery status from ev3 and send via MQTT Function to read battery status from ev3 and send via MQTT
Args: Args:
clients (mqtt.Client): _description_ clients (mqtt.Client): current mqtt client
userdata (_type_): _description_ userdata (_type_): _description_
message (mqtt.MQTTMessage): _description_ message (mqtt.MQTTMessage): received message
""" """
#[ ]TODO read Battery battery = {
client.publish("ROBOT/DATA/BATTERY", json.dumps(batteryStatus, indent=4)) "Battery": 0.0
}
#TODO read Battery
clients.publish(Topics["ROBOT_DATA_BATTERY"], json.dumps(battery, indent=4))
#endregion #endregion
@ -152,13 +175,15 @@ def main():
Initialises MQTT and Sensors Initialises MQTT and Sensors
Runs forever and controlls all robot functions Runs forever and controlls all robot functions
""" """
# CHECK if global
#TODO on_connect global sensors
init_mqtt() sensors = RaspySensors()
print("MQTT initialized") client = mqtt.Client(RASPI_CLIENT_ID)
signal.signal(signal.SIGUSR1, signal_measure) client.on_connect = on_connect
client.connect(MQTT_BROKER_GLOBAL)
# dataDict = {} #Testing # dataDict = {} #Testing
# CHECK forever or start
client.loop_start() client.loop_start()
print("Starting Loop") print("Starting Loop")

View File

@ -5,10 +5,17 @@ import board
import json import json
class RaspySensors: class RaspySensors:
'''Class to handle all sensors''' """
Class to handle all sensors
Returns:
_type_: _description_
"""
def __init__(self) -> None: def __init__(self) -> None:
'''Init all Sensors''' """
Init all Sensors
"""
#[ ]TODO Message if Error #[ ]TODO Message if Error
@ -20,46 +27,65 @@ class RaspySensors:
#global Variables #global Variables
self.sensorData ={ self.sensorData ={
"Air Temperature [°C]" : 0, "AirTemperature": 0.0,
"Air Humidity [%]" : 0, "AirHumidity" : 0.0,
"Earth Humidity [%]" : 0, "SoilMoisture" : 0.0,
"Brightness [Lux]" : 0, "Brightness" : 0,
"Plant ID": 0, "PlantID": 0,
"Action ID": 0 "ActionID": 0
} }
def readSensors(self): def readSensors(self):
'''Read all Sensors and return Dictionary with data''' """
Read all Sensors and return Dictionary with data
Returns:
sensordata (dict): all data of sensors
"""
#read DHT22 #read DHT22
#if Error reading Data try again #if Error reading Data try again
while True: while True:
try: try:
self.sensorData["Air Temperature [°C]"] = self.dht22.temperature self.sensorData["AirTemperature"] = self.dht22.temperature
self.sensorData["Air Humidity [%]"] = self.dht22.humidity self.sensorData["AirHumidity"] = self.dht22.humidity
except: except:
continue continue
break break
#read TSL2561 #read TSL2561
self.sensorData["Brightness [Lux]"] = round(self.tsl2561.lux, 2) self.sensorData["Brightness"] = round(self.tsl2561.lux, 2)
return self.sensorData return self.sensorData
#[ ]TODO - take picture function #TODO - take picture function
def takePicture(self): def takePicture(self):
'''Take picture and return image''' """
Take picture and return image
Returns:
_type_: _description_
"""
return self.image return self.image
#[ ]TODO #TODO - read position with sensor
def readPosition(self): def readPosition(self):
'''Read and return Position''' """
Read and return Position
Returns:
_type_: _description_
"""
return self.position return self.position
#[ ]TODO #TODO - read battery from EV3
def readBattery(self): def readBattery(self):
'''Read and return battery of ev3''' """
Read and return battery of ev3
Returns:
_type_: _description_
"""
return self.battery return self.battery