Added PythonDoc and simplified drive thread
This commit is contained in:
parent
0c08ab1d8b
commit
b798e138fa
@ -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:
|
||||||
|
|
||||||
def init_mqtt():
|
|
||||||
'''Initialise MQTT client'''
|
|
||||||
mqttBroker = "mqtt.eclipseprojects.io"
|
|
||||||
global client
|
|
||||||
client = mqtt.Client("Robot")
|
|
||||||
|
|
||||||
#Add callbacks
|
#Add callbacks
|
||||||
client.message_callback_add("ROBOT/DATA", send_data_json) #Testing
|
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_DRIVE"], drive_plant)
|
||||||
client.message_callback_add(Topics["ROBOT_ACTION_GETPOSITION"], get_position)
|
client.message_callback_add(Topics["ROBOT_ACTION_GETPOSITION"], get_position)
|
||||||
client.message_callback_add(Topics["ROBOT_ACTION_GETBATTERY"], get_BatteryStatus)
|
client.message_callback_add(Topics["ROBOT_ACTION_GETBATTERY"], get_BatteryStatus)
|
||||||
|
|
||||||
client.connect(mqttBroker) #Has to be before subscribing
|
|
||||||
|
|
||||||
#Subscribe to topics
|
#Subscribe to topics
|
||||||
client.subscribe("ROBOT/DATA") #Testing
|
client.subscribe("ROBOT/DATA") #Testing
|
||||||
client.subscribe(Topics["ROBOT_ACTION_DRIVE"])
|
client.subscribe(Topics["ROBOT_ACTION_DRIVE"])
|
||||||
client.subscribe(Topics["ROBOT_ACTION_GETPOSITION"])
|
client.subscribe(Topics["ROBOT_ACTION_GETPOSITION"])
|
||||||
client.subscribe(Topics["ROBOT_ACTION_GETBATTERY"])
|
client.subscribe(Topics["ROBOT_ACTION_GETBATTERY"])
|
||||||
|
|
||||||
|
print("MQTT initialized")
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
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")
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user