From 6116fa37e4558065b5631da7c687379fc6753941 Mon Sep 17 00:00:00 2001 From: Alihan Date: Thu, 18 May 2023 19:31:09 +0300 Subject: [PATCH] implement emergency stop & better exception handling --- brain/brain.py | 5 ++-- brain/brain_base.py | 32 ++++++++++++++++++++ brain/brain_openai.py | 22 +++----------- commander/commands.py | 6 ++++ commander/routes/route_command.py | 49 +++++++++++++++++++++---------- manage.sh | 21 ++++++------- settings/admin.yml | 2 -- 7 files changed, 89 insertions(+), 48 deletions(-) create mode 100644 brain/brain_base.py diff --git a/brain/brain.py b/brain/brain.py index f89967d..cfb2868 100644 --- a/brain/brain.py +++ b/brain/brain.py @@ -6,7 +6,8 @@ brain = CloudChatBrain() while True: try: brain.listen() - brain.understand() - brain.command() + if not brain.is_emergency(brain.cmd_prompt): + brain.understand() + brain.command() except Exception as e: print(f"##### SOMETHING WENT WRONG ###### \n {e}") diff --git a/brain/brain_base.py b/brain/brain_base.py new file mode 100644 index 0000000..c4d3e15 --- /dev/null +++ b/brain/brain_base.py @@ -0,0 +1,32 @@ +import os + +from commander.commands import CommandHandler + + + +class BaseBrain: + def __init__(self): + self.command_handler = CommandHandler() + + @property + def sys_prompt(self): + return self._read_prompt() + + def _read_prompt(self): + prompt_file_name = "prompt.txt" + for root, dirs, files in os.walk("./"): + if prompt_file_name in files: + prompt_filepath = os.path.join(root, prompt_file_name) + with open(prompt_filepath, "r") as f: + return f.read() + + def is_emergency(self, input): + if input == "q": + print("##### BASE BRAIN: EMERGENCY STOP DETECTED!!! #####") + self.command_handler.handle({"command": "emergency"}) + return True + else: + return False + + def listen(self): + self.cmd_prompt = input("\n\nwhat should I do now?\n(enter q for emergency)\n\t") diff --git a/brain/brain_openai.py b/brain/brain_openai.py index acd4bbe..0635467 100644 --- a/brain/brain_openai.py +++ b/brain/brain_openai.py @@ -6,7 +6,7 @@ import ast import openai -from commander.commands import CommandHandler +from brain_base import BaseBrain from settings.config import settings @@ -16,22 +16,11 @@ class CloudSTTBrain: print("not implemented") -class CloudChatBrain: +class CloudChatBrain(BaseBrain): + def __init__(self): + super().__init__() openai.api_key = settings.OPENAI_API_KEY - self.command_handler = CommandHandler() - - @property - def sys_prompt(self): - return self._read_prompt() - - def _read_prompt(self): - prompt_file_name = "prompt.txt" - for root, dirs, files in os.walk("./"): - if prompt_file_name in files: - prompt_filepath = os.path.join(root, prompt_file_name) - with open(prompt_filepath, "r") as f: - return f.read() def _is_valid_json(self, answer): try: @@ -45,9 +34,6 @@ class CloudChatBrain: self.cmd_prompt = None self.response = None - def listen(self): - self.cmd_prompt = input("\n\nwhat should I do now?\n\t") - def understand(self): self.response = openai.ChatCompletion.create( model="gpt-3.5-turbo", diff --git a/commander/commands.py b/commander/commands.py index c281f62..fadd8f0 100644 --- a/commander/commands.py +++ b/commander/commands.py @@ -42,6 +42,10 @@ class CommandHandler: def _end_session(self): response = requests.get(f"{self.COMMANDER_COMMANDS_URL}/end") print(response.json()) + + def _emergency(self): + response = requests.get(f"{self.COMMANDER_COMMANDS_URL}/emergency") + print(response.json()) def handle(self, cmd: dict): #print(f"commanding for: {cmd}") @@ -59,5 +63,7 @@ class CommandHandler: self._takeoff() elif cmd["command"] == "land": self._land() + elif cmd["command"] == "emergency": + self._emergency() else: raise ValueError(f"Uknown command object: {cmd}") diff --git a/commander/routes/route_command.py b/commander/routes/route_command.py index d023e8f..e07874d 100644 --- a/commander/routes/route_command.py +++ b/commander/routes/route_command.py @@ -45,14 +45,17 @@ def takeoff(): try: tello.connect() except Exception as e: - return {"msg": "failed to connect"} + return {"msg": "command failed", "reason": "failed to connect"} if tello.is_flying: return {"msg": "already flying"} - tello.takeoff() - stats_collector.start_collecting() - + try: + tello.takeoff() + stats_collector.start_collecting() + except Exception as e: + return { "msg": "command failed", "reason": e } + if tello.is_flying: return {"msg": "ok"} else: @@ -63,8 +66,11 @@ def land(): if not tello.is_flying: return {"msg": "already on land"} - tello.land() - stats_collector.stop_collecting() + try: + tello.land() + stats_collector.stop_collecting() + except Exception as e: + return { "msg": "command failed", "reason": e } if not tello.is_flying: return {"msg": "ok"} @@ -76,10 +82,13 @@ def turn(direction: str, degree: int): if degree < 1 or degree > 360: return {"degree must be between 1 and 360"} - if direction == "right": - tello.rotate_clockwise(degree) - elif direction == "left": - tello.rotate_counter_clockwise(degree) + try: + if direction == "right": + tello.rotate_clockwise(degree) + elif direction == "left": + tello.rotate_counter_clockwise(degree) + except Exception as e: + return { "msg": "command failed", "reason": e } return {"msg": "ok"} @@ -93,14 +102,22 @@ def turn(direction: str, distance: int): try: tello.move(direction, distance) except Exception as e: - return { - "msg": "command failed", - "reason": e - } + return { "msg": "command failed", "reason": e } return {"msg": "ok"} +@router.get("/emergency") +def emercengy_stop(): + try: + tello.emergency() + return {"msg": "ok"} + except Exception as e: + return { "msg": "command failed", "reason": e } + @router.get("/end") def end_flight_session(): - tello.end() - return {"msg": "ok"} + try: + tello.end() + return {"msg": "ok"} + except Exception as e: + return { "msg": "command failed", "reason": e } diff --git a/manage.sh b/manage.sh index 80258b0..3ce9c87 100755 --- a/manage.sh +++ b/manage.sh @@ -9,7 +9,7 @@ DRONE_INTERFACE=$(yq '.commander.drone_interface' < settings/admin.yml) DRONE_WPA_SUPP_CONF=$(yq '.commander.drone_wpa_supp' < settings/admin.yml) NET_INTERFACE=$(yq '.commander.net_interface' < settings/admin.yml) NET_WPA_SUPP_CONF=$(yq '.commander.net_wpa_supp' < settings/admin.yml) -ENV_FOR_DYNACONF=$(yq '.commander.env_for_dynaconf' < settings/admin.yml) +#ENV_FOR_DYNACONF=$(yq '.commander.env_for_dynaconf' < settings/admin.yml) pids_dir='./pids' if [[ ! -d "$pids_dir" ]]; then @@ -70,11 +70,11 @@ start_commander_service() { } talk_to_drone() { - ENV_FOR_DYNACONF=$ENV_FOR_DYNACONF python brain/brain.py + ENV_FOR_DYNACONF=$1 python brain/brain.py } kill_everything() { - for p in $pids_dir/*.txt; do echo "killing $p"; sudo pkill $(cat "$p"); done + for p in $pids_dir/*.txt; do echo "killing $p"; sudo pkill -15 $(cat "$p"); done } remote_shutdown() { @@ -102,7 +102,7 @@ elif [ "$1" == "connect-drone" ]; then elif [ "$1" == "disconnect-drone" ]; then wpa_supp_pid_file="$pids_dir/wpa_supp_pid.txt" if [ -f "$wpa_supp_pid_file" ]; then - sudo pkill -P $(cat $wpa_supp_pid_file) + sudo pkill -15 -P $(cat $wpa_supp_pid_file) echo "stopped drone connection via wpa_supp" fi @@ -115,7 +115,7 @@ elif [ "$1" == "get-dhcp" ]; then elif [ "$1" == "kill-dhcp" ]; then dhcp_ip_pid_file="$pids_dir/dhcp_ip_pid.txt" if [ -f "$dhcp_ip_pid_file" ]; then - sudo pkill -P $(cat $dhcp_ip_pid_file) + sudo pkill -15 -P $(cat $dhcp_ip_pid_file) echo "killed dhcp client" fi @@ -132,7 +132,7 @@ elif [ "$1" == "start-jupyter" ]; then elif [ "$1" == "stop-jupyter" ]; then jupyter_pid_file="$pids_dir/jupyter_pid.txt" if [ -f "$jupyter_pid_file" ]; then - pkill -P $(cat $jupyter_pid_file) + pkill -15 -P $(cat $jupyter_pid_file) echo "stopped jupyter" fi @@ -146,7 +146,8 @@ elif [ "$1" == "start-cs" ]; then elif [ "$1" == "stop-cs" ]; then codeserver_pid_file="$pids_dir/codeserver_pid.txt" if [ -f "$codeserver_pid_file" ]; then - pkill -P $(cat $codeserver_pid_file) + sudo pkill -15 -P $(cat $codeserver_pid_file) + sudo killport 8888 echo "stopped code server" fi @@ -168,7 +169,7 @@ elif [ "$1" == "stop-commander" ]; then commander_pid_file="$pids_dir/commander_pid.txt" if [ -f "$commander_pid_file" ]; then sudo killport 8889 - pkill -P $(cat $commander_pid_file) + sudo pkill -15 -P $(cat $commander_pid_file) echo "stopped commander" fi @@ -185,7 +186,7 @@ elif [ "$1" == "finish-flight" ]; then kill_everything echo "flight finished" elif [ "$1" == "start-talking" ]; then - talk_to_drone + talk_to_drone $2 ###################### ## INFO @@ -199,7 +200,7 @@ else - start-/ stop-jupyter - start-/ stop-cs - start-/ stop-commander [port] - - start-talking + - start-talking tuncel / commander - turn-off - prepare-/ finish-flight" fi diff --git a/settings/admin.yml b/settings/admin.yml index fb6faeb..0494d9a 100644 --- a/settings/admin.yml +++ b/settings/admin.yml @@ -7,5 +7,3 @@ commander: wpa_supp_djituad0_plus.conf net_wpa_supp: wpa_supp_uadis.conf - env_for_dynaconf: - commander