Update 2026-04-22 11:19:55
This commit is contained in:
parent
e7609b119f
commit
88e22a423b
@ -242,7 +242,7 @@ def _print_help():
|
|||||||
# ── MAIN ─────────────────────────────────────────────────────────────────────
|
# ── MAIN ─────────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
parser = argparse.ArgumentParser(description="Marcus CLI Client")
|
parser = argparse.ArgumentParser(description="Sanad CLI Client (talks to the Marcus brain over WebSocket)")
|
||||||
parser.add_argument("--ip", default=None, help="Server IP address")
|
parser.add_argument("--ip", default=None, help="Server IP address")
|
||||||
parser.add_argument("--port", type=int, default=None, help="Server port")
|
parser.add_argument("--port", type=int, default=None, help="Server port")
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
@ -250,7 +250,7 @@ def main():
|
|||||||
eth_ip = _net.get("jetson_ip", "192.168.123.164")
|
eth_ip = _net.get("jetson_ip", "192.168.123.164")
|
||||||
wlan_ip = _net.get("jetson_wlan_ip", "10.255.254.86")
|
wlan_ip = _net.get("jetson_wlan_ip", "10.255.254.86")
|
||||||
|
|
||||||
print(f"\n{C.BOLD}{C.ORANGE} MARCUS — CLI Client{C.RESET}")
|
print(f"\n{C.BOLD}{C.ORANGE} SANAD — CLI Client{C.RESET}")
|
||||||
print(f" {'═' * 40}")
|
print(f" {'═' * 40}")
|
||||||
print(f" {C.GRAY}Connection options:{C.RESET}")
|
print(f" {C.GRAY}Connection options:{C.RESET}")
|
||||||
print(f" 1) eth0 — {eth_ip}:{DEFAULT_PORT}")
|
print(f" 1) eth0 — {eth_ip}:{DEFAULT_PORT}")
|
||||||
|
|||||||
@ -140,7 +140,7 @@ def btn(parent, text, bg_color=BG3, fg_color=WHITE, font=FONT_SM, command=None,
|
|||||||
class MarcusGUI:
|
class MarcusGUI:
|
||||||
def __init__(self, root):
|
def __init__(self, root):
|
||||||
self.root = root
|
self.root = root
|
||||||
self.root.title("Marcus — Navigation Control")
|
self.root.title("Sanad — Navigation Control")
|
||||||
self.root.configure(bg=BG)
|
self.root.configure(bg=BG)
|
||||||
self.root.geometry("1360x860")
|
self.root.geometry("1360x860")
|
||||||
self.root.minsize(1000, 650)
|
self.root.minsize(1000, 650)
|
||||||
|
|||||||
@ -29,10 +29,25 @@ from Brain.marcus_brain import init_brain, process_command, get_brain_status, sh
|
|||||||
from API.camera_api import get_frame
|
from API.camera_api import get_frame
|
||||||
|
|
||||||
_net = load_config("Network")
|
_net = load_config("Network")
|
||||||
|
_cam = load_config("Camera")
|
||||||
|
|
||||||
HOST = "0.0.0.0"
|
HOST = "0.0.0.0"
|
||||||
PORT = _net.get("websocket_port", 8765)
|
PORT = _net.get("websocket_port", 8765)
|
||||||
|
|
||||||
|
|
||||||
|
def _camera_config_payload() -> dict:
|
||||||
|
"""Current camera parameters for the `camera_config` client event."""
|
||||||
|
return {
|
||||||
|
"type": "camera_config",
|
||||||
|
"profile": _cam.get("profile", "default"),
|
||||||
|
"width": _cam.get("width", 424),
|
||||||
|
"height": _cam.get("height", 240),
|
||||||
|
"fps": _cam.get("fps", 15),
|
||||||
|
"jpeg_quality": _cam.get("jpeg_quality", 70),
|
||||||
|
"pipeline_active": True, # camera thread is always on in this build
|
||||||
|
"timestamp": time.strftime("%H:%M:%S"),
|
||||||
|
}
|
||||||
|
|
||||||
connected_clients = set()
|
connected_clients = set()
|
||||||
|
|
||||||
|
|
||||||
@ -76,9 +91,13 @@ async def handler(websocket):
|
|||||||
"memory": status["memory"],
|
"memory": status["memory"],
|
||||||
"camera": status["camera"],
|
"camera": status["camera"],
|
||||||
"lidar": lidar_ok,
|
"lidar": lidar_ok,
|
||||||
"message": "Marcus server ready (full brain)",
|
"message": "Sanad server ready (full brain)",
|
||||||
}))
|
}))
|
||||||
|
|
||||||
|
# Also push current camera config so the GUI's Camera tab populates
|
||||||
|
# immediately on connect without needing an explicit get_camera round-trip.
|
||||||
|
await websocket.send(json.dumps(_camera_config_payload()))
|
||||||
|
|
||||||
try:
|
try:
|
||||||
async for message in websocket:
|
async for message in websocket:
|
||||||
data = json.loads(message)
|
data = json.loads(message)
|
||||||
@ -139,6 +158,35 @@ async def handler(websocket):
|
|||||||
"timestamp": time.strftime("%H:%M:%S"),
|
"timestamp": time.strftime("%H:%M:%S"),
|
||||||
}))
|
}))
|
||||||
|
|
||||||
|
elif msg_type == "get_camera":
|
||||||
|
await websocket.send(json.dumps(_camera_config_payload()))
|
||||||
|
|
||||||
|
elif msg_type in ("set_camera", "set_resolution"):
|
||||||
|
# The RealSense pipeline is started once at boot with values
|
||||||
|
# from config_Camera.json; hot-switching resolution would
|
||||||
|
# require tearing down and rebuilding the camera thread.
|
||||||
|
# Not implemented today — reply with a clear error so the
|
||||||
|
# GUI surfaces it rather than hanging forever waiting for
|
||||||
|
# a camera_config event that never comes.
|
||||||
|
await websocket.send(json.dumps({
|
||||||
|
"type": "error",
|
||||||
|
"message": (f"`{msg_type}` is not supported in this build — "
|
||||||
|
"camera parameters are pinned from config_Camera.json "
|
||||||
|
"at startup."),
|
||||||
|
"echo": msg_type,
|
||||||
|
"timestamp": time.strftime("%H:%M:%S"),
|
||||||
|
}))
|
||||||
|
# Still send the current config so the GUI can refresh its UI.
|
||||||
|
await websocket.send(json.dumps(_camera_config_payload()))
|
||||||
|
|
||||||
|
else:
|
||||||
|
await websocket.send(json.dumps({
|
||||||
|
"type": "error",
|
||||||
|
"message": f"Unknown message type: {msg_type!r}",
|
||||||
|
"echo": msg_type,
|
||||||
|
"timestamp": time.strftime("%H:%M:%S"),
|
||||||
|
}))
|
||||||
|
|
||||||
except websockets.exceptions.ConnectionClosed:
|
except websockets.exceptions.ConnectionClosed:
|
||||||
print(f"[Server] Client disconnected: {client}")
|
print(f"[Server] Client disconnected: {client}")
|
||||||
finally:
|
finally:
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user