Uczymy humanoida Unitree G1 podnieść skrzynkę oburącz, przejść z nią kilka metrów i odłożyć. To nasz pierwszy własny projekt i miejsce prób przed zadaniami logistycznymi dla klientów. Zadanie wydaje się proste, ale utrzymanie skrzynki i równowagi podczas przenoszenia wymaga dopracowania chwytu i chodu, dlatego dobrze nadaje się na punkt wyjścia do bardziej złożonych zadań.
- 1. Podejściezatrzymanie przed skrzynką
- 2. Chwytdwie ręce, docisk boczny
- 3. Podniesienieregulacja sił w ramionach
- 4. Marszramiona zablokowane
- 5. Odłożeniezatrzymanie, puszczenie
Jak to robimy
- Zadanie dzielimy na kolejne etapy zamiast jednej sieci neuronowej obejmującej całość, dzięki czemu każdy etap można osobno sprawdzać i poprawiać.
- Robot zatrzymuje się przed chwytem, więc chód i manipulacja nie odbywają się jednocześnie.
- Podczas marszu ramiona trzymają stałą pozycję, a regulator chodu traktuje skrzynkę jako dodatkowy ładunek.
- Ograniczenie, które znamy z danych producenta: udźwig ramienia G1 to ok. 2 kg (EDU ok. 3 kg, zależnie od pozycji), więc zaczynamy od lekkich, sztywnych skrzynek.
Wyniki
Nie publikujemy wyników: skuteczności, czasu cyklu ani nagrań.
Kod
Kod poglądowy Kod poglądowy, jeszcze nieuruchomiony na robocie. Dwa krótkie szkice naszego zespołu pokazujące, jak planujemy zbudować zadanie. Celowo nie korzystają z Unitree SDK ani ROS 2, aby nie sugerować integracji, której jeszcze nie zbudowaliśmy. Komentarze w kodzie są w języku angielskim.
01_carry_state_machine.py · jeszcze nieuruchomiony na robocie.# ILLUSTRATIVE / PLANNED - not from our repo, not run on a robot.
# G1 two-handed box carry: the 5 stages as a fail-closed state machine.
# Licence: (c) NeoHumanoidX sp. z o.o., shown for illustration only.
from enum import Enum, auto
class Stage(Enum):
APPROACH = auto(); GRASP = auto(); LIFT = auto()
WALK = auto(); PLACE = auto(); DONE = auto(); STOPPED = auto()
NEXT = {Stage.APPROACH: Stage.GRASP, Stage.GRASP: Stage.LIFT,
Stage.LIFT: Stage.WALK, Stage.WALK: Stage.PLACE,
Stage.PLACE: Stage.DONE}
class CarryTask:
def __init__(self, skills, safety):
self.skills, self.safety = skills, safety # injected; sim first
self.stage = Stage.APPROACH
def step(self):
if self.safety.stop_requested(): # e-stop / voice stop
self.stage = Stage.STOPPED # latched until reset
return self.stage
if self.stage in (Stage.DONE, Stage.STOPPED):
return self.stage
ok = self.skills[self.stage].run() # bounded, with timeout
self.stage = NEXT[self.stage] if ok else Stage.STOPPED
return self.stage02_arm_hold_while_walking.py · jeszcze nieuruchomiony na robocie.# ILLUSTRATIVE / PLANNED - not from our repo, not run on a robot.
# Keep both hands clamped on the box while the legs walk: hold a fixed
# arm pose with gentle stiffness and watch grip force for a slipping box.
# Licence: (c) NeoHumanoidX sp. z o.o., shown for illustration only.
from dataclasses import dataclass
@dataclass
class ArmHold:
pose: list # 14 arm joint targets [rad], left + right
kp: float = 40.0 # soft enough to absorb walking sway
kd: float = 1.5
min_grip_n: float = 8.0
def hold_step(hold, read_state, send_arm_targets, on_slip):
"""One control tick (e.g. 100 Hz) during the WALK stage."""
state = read_state() # joints + hand forces
if min(state.grip_forces) < hold.min_grip_n:
on_slip() # stop walking, set box down
return False
send_arm_targets(hold.pose, kp=hold.kp, kd=hold.kd) # via the robot's SDK
return True