#!/usr/bin/env python3 | #!/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 | from ev3dev2.motor import Motor, OUTPUT_B, OUTPUT_C, SpeedPercent | ||||
import sys | import sys | ||||
#!/usr/bin/env python3 | #!/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.motor import Motor, LargeMotor, OUTPUT_A, OUTPUT_B, OUTPUT_C, OUTPUT_D, SpeedPercent | ||||
from ev3dev2.sensor.lego import TouchSensor, UltrasonicSensor | from ev3dev2.sensor.lego import TouchSensor, UltrasonicSensor | ||||
from ev3dev2.sensor import INPUT_1, INPUT_4 | from ev3dev2.sensor import INPUT_1, INPUT_4 | ||||
motorRight.on(SpeedPercent(-25)) | motorRight.on(SpeedPercent(-25)) | ||||
break | break | ||||
sensorTouch.wait_for_pressed(timeout_ms=None, sleep_ms=10) | sensorTouch.wait_for_pressed(timeout_ms=None, sleep_ms=10) | ||||
motorLeft.off() | motorLeft.off() | ||||
motorRight.off() | motorRight.off() |
#!/usr/bin/env python3 | #!/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.motor import LargeMotor, OUTPUT_A, OUTPUT_D, SpeedPercent | ||||
from ev3dev2.sensor.lego import TouchSensor, UltrasonicSensor | from ev3dev2.sensor.lego import TouchSensor, UltrasonicSensor | ||||
from ev3dev2.sensor import INPUT_1, INPUT_4 | from ev3dev2.sensor import INPUT_1, INPUT_4 |
#!/usr/bin/env pybricks-micropython | #!/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.motor import Motor, LargeMotor, OUTPUT_A, OUTPUT_B, OUTPUT_C, OUTPUT_D, SpeedPercent | ||||
from ev3dev2.sensor.lego import ColorSensor | from ev3dev2.sensor.lego import ColorSensor |
#!/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) | |||||
#!/usr/bin/env pybricks-micropython | #!/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 | from ev3dev2.motor import Motor, LargeMotor, ServoMotor, OUTPUT_A, OUTPUT_B, OUTPUT_C, OUTPUT_D, SpeedPercent | ||||
motorRight = LargeMotor(OUTPUT_A) | motorRight = LargeMotor(OUTPUT_A) |
#!/usr/bin/env pybricks-micropython | #!/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 | from ev3dev2.motor import Motor, LargeMotor, ServoMotor, OUTPUT_A, OUTPUT_B, OUTPUT_C, OUTPUT_D, SpeedPercent | ||||
motorRight = LargeMotor(OUTPUT_A) | motorRight = LargeMotor(OUTPUT_A) |
#!/usr/bin/env pybricks-micropython | #!/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 | from ev3dev2.motor import Motor, LargeMotor, ServoMotor, OUTPUT_A, OUTPUT_B, OUTPUT_C, OUTPUT_D, SpeedPercent | ||||
motorRight = LargeMotor(OUTPUT_A) | motorRight = LargeMotor(OUTPUT_A) |
#!/usr/bin/env pybricks-micropython | #!/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 | from ev3dev2.motor import Motor, LargeMotor, ServoMotor, OUTPUT_A, OUTPUT_B, OUTPUT_C, OUTPUT_D, SpeedPercent | ||||
motorRight = LargeMotor(OUTPUT_A) | motorRight = LargeMotor(OUTPUT_A) |
#!/usr/bin/env pybricks-micropython | #!/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 | from ev3dev2.motor import Motor, LargeMotor, ServoMotor, OUTPUT_A, OUTPUT_B, OUTPUT_C, OUTPUT_D, SpeedPercent | ||||
motorRight = LargeMotor(OUTPUT_A) | motorRight = LargeMotor(OUTPUT_A) |
#!/usr/bin/env pybricks-micropython | #!/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 | from ev3dev2.motor import Motor, LargeMotor, ServoMotor, OUTPUT_A, OUTPUT_B, OUTPUT_C, OUTPUT_D, SpeedPercent | ||||
motorRight = LargeMotor(OUTPUT_A) | motorRight = LargeMotor(OUTPUT_A) |
""" | |||||
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 paho.mqtt.client as mqtt | ||||
import json | import json | ||||
import threading | import threading | ||||
sensorData["ActionID"] = actionID | sensorData["ActionID"] = actionID | ||||
client.publish(Topics["ROBOT_DATA_SENSORDATA"], json.dumps(sensorData, indent=4), qos=1) | 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): | def drive_plant_thread(plantID, actionID, client: mqtt.Client): | ||||
""" | """ | ||||
Function to drive to plant according to number from MQTT message in thread | 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 | Meassure and publish data via MQTT | ||||
Drive home to starting point | Drive home to starting point | ||||
***If color codes are working properly this function is not needed anymore*** | |||||
Args: | Args: | ||||
plantID (_type_): plant to measure | plantID (_type_): plant to measure | ||||
actionID (_type_): current ID of driving action | actionID (_type_): current ID of driving action | ||||
client (mqtt.Client): current mqtt client for publishing | 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/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 != 0: | ||||
if errorCode == 65280: | if errorCode == 65280: | ||||
def drive_plant_all_thread(plantIDs: list, 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 | Meassure and publish data for all plants via MQTT | ||||
Drive home to starting point | Drive home to starting point | ||||
***If color codes are working properly, only this function is needed for drive operations*** | |||||
Args: | 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 | actionID (_type_): ActionID from Backend for whole drive action | ||||
client (mqtt.Client): current MQTT client | client (mqtt.Client): current MQTT client | ||||
""" | """ | ||||
return | return | ||||
# Read Sensors and store data, take picture | |||||
logging.info("Measuring Sensors") | logging.info("Measuring Sensors") | ||||
try: | try: | ||||
sensordata = {} | sensordata = {} | ||||
logging.info("Robot home") | logging.info("Robot home") | ||||
client.publish(Topics["ROBOT_DATA_ROBOTREADY"], "True", qos=1) | client.publish(Topics["ROBOT_DATA_ROBOTREADY"], "True", qos=1) | ||||
#endregion | |||||
#region MQTT callbacks | #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): | def drive_plant(client: mqtt.Client, userdata, message: mqtt.MQTTMessage): | ||||
""" | """ | ||||
Function to drive to plant according to request | Function to drive to plant according to request | ||||
Starting Drive in Thread to not block main programm | Starting Drive in Thread to not block main programm | ||||
***If color codes are working properly this function is not needed anymore*** | |||||
Args: | Args: | ||||
client (mqtt.Client): current mqtt client | client (mqtt.Client): current mqtt client | ||||
userdata (_type_): _description_ | userdata (_type_): _description_ | ||||
Function to drive to plants according to request | Function to drive to plants according to request | ||||
Starting Drive in Thread to not block main programm | Starting Drive in Thread to not block main programm | ||||
***If color codes are working properly, only this function is needed for drive operations*** | |||||
Args: | Args: | ||||
client (mqtt.Client): current MQTT client | client (mqtt.Client): current MQTT client | ||||
userdata (_type_): _description_ | userdata (_type_): _description_ | ||||
thread = threading.Thread(target= drive_plant_all_thread, args=(plantIDs, actionID, client), daemon=True) | thread = threading.Thread(target= drive_plant_all_thread, args=(plantIDs, actionID, client), 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 | Callback function for GPS position request | ||||
Function to send actual GPS position via MQTT in form of POSITION | Function to send actual GPS position via MQTT in form of POSITION | ||||
***Not implemented, available GPS-sensor was not working*** | |||||
Args: | Args: | ||||
client (mqtt.Client): current mqtt client | client (mqtt.Client): current mqtt client | ||||
userdata (_type_): _description_ | userdata (_type_): _description_ | ||||
def get_batteryStatus(client: mqtt.Client, userdata, message: mqtt.MQTTMessage): | def get_batteryStatus(client: mqtt.Client, userdata, message: mqtt.MQTTMessage): | ||||
""" | """ | ||||
Callback function for battery status request | 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% | 8,5V -> 100% | ||||
5V -> 0% | 5V -> 0% | ||||
client.publish(Topics["ROBOT_DATA_ERROR"], "Robot not connected", qos=1) | client.publish(Topics["ROBOT_DATA_ERROR"], "Robot not connected", qos=1) | ||||
return | return | ||||
batteryLevel = round(batteryLevel / 1000000, 2) # Voltage | |||||
batteryLevel = round(batteryLevel / 1000000, 2) # Conversion to Volt | |||||
batteryLevel = batteryLevel - 5 | 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 = { | ||||
"Battery": batteryLevel | "Battery": batteryLevel | ||||
""" | """ | ||||
Takes picture and publish via MQTT | Takes picture and publish via MQTT | ||||
***Pictures can not be send until now -> assumption of reaching maximum payload limit*** | |||||
Args: | Args: | ||||
client (mqtt.Client): current mqtt client | client (mqtt.Client): current mqtt client | ||||
""" | """ |
""" | """ | ||||
created by waldluis | |||||
created by waldlhauser | |||||
This file contains the main script for the RaspberryPi of smart garden project | 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 | The sensor data is published to MQTT topics to be available for the backend server | ||||
Used protocol for interaction: mqtt (paho-mqtt module) | Used protocol for interaction: mqtt (paho-mqtt module) | ||||
Interaction with the EV3 via SSH | Interaction with the EV3 via SSH | ||||
""" | |||||
""" | |||||
import paho.mqtt.client as mqtt | import paho.mqtt.client as mqtt | ||||
import functions | import functions |
# 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_dht | ||||
import adafruit_tsl2561 | import adafruit_tsl2561 | ||||
import board | import board | ||||
percentage = round(((1100 - percentage) / 1100) *100, 2) # 680 -> 100% moisture, 1780 -> 0% moisture | 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 | if percentage > 100 or percentage < 0: # If not connected values above 100% appear | ||||
percentage = 0 | |||||
raise Exception("YL69 not connected") | raise Exception("YL69 not connected") | ||||
return percentage | return percentage | ||||
def readSensors(sensorData): | def readSensors(sensorData): | ||||
""" | """ | ||||
Read DHT22, TSL2561 and Humidity Sensor | Read DHT22, TSL2561 and Humidity Sensor | ||||
Dictionary is passed to ensure that values are available when errors occur | |||||
Args: | Args: | ||||
sensorData (dictionary): Dictionary of type SENSORDATA | sensorData (dictionary): Dictionary of type SENSORDATA | ||||
try: | try: | ||||
sensorData["AirTemperature"], sensorData["AirHumidity"] = readDHT22() | sensorData["AirTemperature"], sensorData["AirHumidity"] = readDHT22() | ||||
except Exception as e: | 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 | sensorData["AirTemperature"] = 0 | ||||
errorMessage = str(e) + "\n" | |||||
errorMessage = str(e) + "\n" # Appending received error message to later forward all occured errors | |||||
# read TSL2561 | # read TSL2561 | ||||
try: | try: | ||||
sensorData["Brightness"] = readTSL2561() | sensorData["Brightness"] = readTSL2561() | ||||
except Exception as e: | 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 | # read YL-69 | ||||
try: | try: | ||||
sensorData["SoilMoisture"] = readMCP3008() | sensorData["SoilMoisture"] = readMCP3008() | ||||
except Exception as e: | 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 != "": | if errorMessage != "": | ||||
raise Exception(errorMessage) | raise Exception(errorMessage) | ||||
def takePicture(): | def takePicture(): | ||||
""" | """ | ||||
Take picture and return picture | |||||
Returns: | |||||
_type_: _description_ | |||||
Take picture and store as "picture.png" in current folder | |||||
""" | """ | ||||
try: | try: | ||||
camera = PiCamera() | camera = PiCamera() | ||||
camera.capture("picture.png") | camera.capture("picture.png") | ||||
camera.stop_preview() | camera.stop_preview() | ||||
return | |||||
# TODO - read position with sensor | # TODO - read position with sensor | ||||
def readPosition(): | def readPosition(): | ||||
""" | """ | ||||
Read and return Position | Read and return Position | ||||
***Not implemented, available GPS-sensor was not working*** | |||||
Returns: | Returns: | ||||
_type_: _description_ | _type_: _description_ | ||||
""" | """ | ||||
# Testing | # Testing | ||||
def main(): | def main(): | ||||
value = SENSORDATA | value = SENSORDATA | ||||
try: | try: |