feat: add navigator dog_bridge module

This commit is contained in:
Scruff AI
2026-03-25 15:49:08 +07:00
parent 460bb8c4eb
commit 7ecfafa1f2
+136
View File
@@ -0,0 +1,136 @@
"""dog_bridge.py — TCP bridge between Navigator and Freenove Robot Dog.
HARDWARE STATUS: NOT YET WIRED
This file is a ready-to-use client for when the Freenove Robot Dog Kit
is assembled and running its Server.py on the Raspberry Pi. It requires:
Pi-side changes (NOT yet applied):
- Command.py: add CMD_FOOTPAD = "CMD_FOOTPAD"
- Server.py: add measuring_footpad() method + elif handler
Hardware wiring (NOT yet done):
- 4x 500g FSR sensors on footpads, each with 10kOhm pull-down
- FSR front-left -> ADS7830 channel 1
- FSR front-right -> ADS7830 channel 2
- FSR rear-left -> ADS7830 channel 3
- FSR rear-right -> ADS7830 channel 4
Connection: WiFi TCP to Pi IP, port 5001 (commands), 8001 (video).
"""
import socket
import threading
class DogBridge:
"""TCP client for commanding the Freenove Robot Dog and reading sensors."""
def __init__(self, host, cmd_port=5001):
self.host = host
self.cmd_port = cmd_port
self.sock = None
self.lock = threading.Lock()
self._buffer = ""
def connect(self):
self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.sock.connect((self.host, self.cmd_port))
self.sock.settimeout(2.0)
def disconnect(self):
if self.sock:
self.sock.close()
self.sock = None
def send_cmd(self, cmd_str):
"""Send a command string (e.g. 'CMD_MOVE_FORWARD#8')."""
with self.lock:
self.sock.sendall((cmd_str + "\n").encode("utf-8"))
def recv_response(self):
"""Read one newline-delimited response from the dog."""
with self.lock:
while "\n" not in self._buffer:
chunk = self.sock.recv(1024).decode("utf-8")
if not chunk:
raise ConnectionError("Dog disconnected")
self._buffer += chunk
line, self._buffer = self._buffer.split("\n", 1)
return line
# --- Movement ---
def move_forward(self, speed=8):
self.send_cmd(f"CMD_MOVE_FORWARD#{speed}")
def move_backward(self, speed=8):
self.send_cmd(f"CMD_MOVE_BACKWARD#{speed}")
def turn_left(self, speed=8):
self.send_cmd(f"CMD_TURN_LEFT#{speed}")
def turn_right(self, speed=8):
self.send_cmd(f"CMD_TURN_RIGHT#{speed}")
def stop(self):
self.send_cmd("CMD_MOVE_STOP#")
# --- Sensors ---
def get_distance(self):
"""Ultrasonic distance in cm."""
self.send_cmd("CMD_SONIC#")
resp = self.recv_response() # CMD_SONIC#<cm>
return float(resp.split("#")[1])
def get_battery(self):
"""Battery voltage (2S LiPo, ~6.4-8.4V range)."""
self.send_cmd("CMD_POWER#")
resp = self.recv_response() # CMD_POWER#<volts>
return float(resp.split("#")[1])
def get_footpads(self):
"""Per-foot pressure readings (0-255 each, 500g FSR sensors).
Returns dict with keys: front_left, front_right, rear_left, rear_right.
Requires Pi-side CMD_FOOTPAD handler (see module docstring).
"""
self.send_cmd("CMD_FOOTPAD#")
resp = self.recv_response() # CMD_FOOTPAD#FL#FR#RL#RR
parts = resp.split("#")
return {
"front_left": int(parts[1]),
"front_right": int(parts[2]),
"rear_left": int(parts[3]),
"rear_right": int(parts[4]),
}
# --- Posture & Head ---
def set_head(self, angle):
"""Set head servo angle."""
self.send_cmd(f"CMD_HEAD#{angle}")
def relax(self):
"""Disengage all servos."""
self.send_cmd("CMD_RELAX#")
def balance_on(self):
"""Enable IMU-based self-balancing."""
self.send_cmd("CMD_BALANCE#1")
def balance_off(self):
self.send_cmd("CMD_BALANCE#0")
def set_height(self, height):
"""Adjust standing height."""
self.send_cmd(f"CMD_HEIGHT#{height}")
# --- LED & Buzzer ---
def buzzer(self, state):
"""state: '1' on, '0' off."""
self.send_cmd(f"CMD_BUZZER#{state}")
def led(self, index, r, g, b):
"""Set LED color. index: 0-based LED number."""
self.send_cmd(f"CMD_LED#{index}#{r}#{g}#{b}")