diff --git a/os/files/etc/environment b/os/files/etc/environment index 80f6337..3ad0e45 100644 --- a/os/files/etc/environment +++ b/os/files/etc/environment @@ -1 +1 @@ -MOABIAN=3.1.0 +MOABIAN=3.1.1 diff --git a/os/services/menu.service b/os/services/menu.service index ab596ba..10f371f 100644 --- a/os/services/menu.service +++ b/os/services/menu.service @@ -4,7 +4,7 @@ DefaultDependencies=false After=dhcpd.service [Service] -Environment="MOABIAN=3.1.0" +Environment="MOABIAN=3.1.1" Environment="PYTHONUNBUFFERED=1" WorkingDirectory=/home/pi/moab/sw ExecStart=/usr/bin/python3 menu.py --debug --verbose --reset diff --git a/sw/controllers.py b/sw/controllers.py index ad080c2..f154464 100644 --- a/sw/controllers.py +++ b/sw/controllers.py @@ -57,7 +57,7 @@ def brain_controller( max_angle=22, port=5555, client_id=123, - alert_fn=lambda toggle: None, + alert_fn=None, **kwargs, ): """ @@ -72,13 +72,18 @@ def brain_controller( endpoint. This way we don't need to know information about what the trained brain was called to navigate the json response. """ - prediction_url = f"http://localhost:{port}/v1/prediction" - # Reset memory if a v2 brain status = requests.delete(f"http://localhost:{port}/v2/clients/{client_id}") version = 2 if status.status_code == 204 else 1 - def next_action(state): + if version == 1: + prediction_url = f"http://localhost:{port}/v1/prediction" + elif version == 2: + prediction_url = f"http://localhost:{port}/v2/clients/{client_id}/predict" + else: + raise ValueError("Brain version `{self.version}` is not supported.") + + def next_action_v1(state): env_state, ball_detected, buttons = state x, y, vel_x, vel_y, sum_x, sum_y = env_state @@ -102,8 +107,6 @@ def next_action(state): info = {"status": response.status_code, "resp": response.json()} if response.ok: - if alert_fn is not None: - alert_fn(False) pitch = info["resp"]["input_pitch"] roll = info["resp"]["input_roll"] @@ -113,19 +116,64 @@ def next_action(state): # To match how the old brain works (only integer plate angles) pitch, roll = int(pitch), int(roll) - action = Vector2(-roll, pitch) - else: - if alert_fn is not None: - alert_fn(True) except requests.exceptions.ConnectionError as e: print(f"No brain listening on port: {port}", file=sys.stderr) raise BrainNotFound - except Exception as e: print(f"Brain exception: {e}") + return action, info + + def next_action_v2(state): + env_state, ball_detected, buttons = state + x, y, vel_x, vel_y, sum_x, sum_y = env_state + + observables = { + "state": { + "ball_x": x, + "ball_y": y, + "ball_vel_x": vel_x, + "ball_vel_y": vel_y, + } + } + + action = Vector2(0, 0) # Action is 0,0 if not detected or brain didn't work + info = {"status": 400, "resp": ""} + if ball_detected: + # Trap on GET failures so we can restart the brain without + # bringing down this run loop. Plate will default to level + # when it loses the connection. + try: + # Get action from brain + response = requests.post(prediction_url, json=observables) + info = {"status": response.status_code, "resp": response.json()} + + if response.ok: + concepts = info["resp"]["concepts"] + concept_name = list(concepts.keys())[0] # Just use first concept + pitch = concepts[concept_name]["action"]["input_pitch"] + roll = concepts[concept_name]["action"]["input_roll"] + + # Scale and clip + pitch = np.clip(pitch * max_angle, -max_angle, max_angle) + roll = np.clip(roll * max_angle, -max_angle, max_angle) + + # To match how the old brain works (only integer plate angles) + pitch, roll = int(pitch), int(roll) + action = Vector2(-roll, pitch) + + except requests.exceptions.ConnectionError as e: + print(f"No brain listening on port: {port}", file=sys.stderr) + raise BrainNotFound + except Exception as e: + print(f"Brain exception: {e}") return action, info - return next_action + if version == 1: + return next_action_v1 + elif version == 2: + return next_action_v2 + else: + raise ValueError("Brain version `{self.version}` is not supported.") diff --git a/sw/menu.py b/sw/menu.py index bd0a3cd..b230f34 100755 --- a/sw/menu.py +++ b/sw/menu.py @@ -154,7 +154,7 @@ def _handle_debug(ctx, param, debug): @click.command() -@click.version_option(version="3.1.0") +@click.version_option(version="3.1.1") @click.option( "-c", "--cont",