1616from teleopit .controllers .observation import VelCmdObservationBuilder , align_motion_qpos_yaw
1717from teleopit .controllers .rl_policy import RLPolicyController
1818from teleopit .inputs .pico4_provider import Pico4InputProvider
19- from teleopit .inputs .pico_video import bridge_video_source , parse_pico_video_config
19+ from teleopit .inputs .pico_video import PicoVideoRuntime , bridge_video_source , parse_pico_video_config
2020from teleopit .inputs .realtime_packet import ControlEvent , ControlEventType
2121from teleopit .retargeting .core import RetargetingModule
2222from teleopit .runtime .common import cfg_get , require_section
5858 SharedFrameDescriptor ,
5959 SnapshotPacket ,
6060)
61- from teleopit .sim2real .mp .shm import SharedFrameRingReader , SharedFrameRingWriter
61+ from teleopit .sim2real .mp .shm import SharedFrameRingWriter
6262from teleopit .sim2real .reference_processor import Sim2RealReferenceProcessor
6363from teleopit .sim2real .remote import UnitreeRemote
6464from teleopit .sim2real .safety import Sim2RealSafetyManager
@@ -208,11 +208,8 @@ def _start_processes(self) -> None:
208208 if hand_mode != "off" :
209209 specs .append (("hand_worker" , _run_hand_worker ))
210210 video_cfg = parse_pico_video_config (cfg_get (self .cfg , "input" , {}))
211- if video_cfg .enabled and video_cfg .source not in (None , "test-pattern" ):
212- specs .append (("video_worker" , _run_video_worker ))
213- elif video_cfg .enabled and video_cfg .source == "test-pattern" :
214- # pico-bridge can generate test-pattern internally without a camera worker.
215- logger .info ("Pico video test-pattern uses pico_bridge internal source" )
211+ if video_cfg .enabled :
212+ logger .info ("Pico video runs inside pico_io so frames are pushed directly to PicoBridge" )
216213
217214 for name , target in specs :
218215 process = self ._ctx .Process (
@@ -255,12 +252,11 @@ def _main() -> None:
255252 events_pub = ZmqPublisher (endpoints .control_events_pub )
256253 health_pub = ZmqPublisher (endpoints .health_pub )
257254 command_sub = LatestSubscriber (endpoints .command_pub , COMMAND_TOPIC )
258- video_sub = (
259- LatestSubscriber ( endpoints . video_pub , VIDEO_TOPIC )
260- if video_cfg . enabled and video_cfg . source not in ( None , "test-pattern" )
261- else None
255+ video_runtime = PicoVideoRuntime (
256+ provider = provider ,
257+ config = video_cfg ,
258+ mode = "sim2real" ,
262259 )
263- frame_reader = SharedFrameRingReader ()
264260
265261 hz = float (cfg_get (_mp_cfg (cfg ), "pico_io_hz" , 120.0 ))
266262 sleep_s = 1.0 / max (hz , 1.0 )
@@ -270,7 +266,9 @@ def _main() -> None:
270266 last_video_seq = - 1
271267 last_health_s = 0.0
272268 try :
269+ video_runtime .start ()
273270 while not stop_event .is_set ():
271+ video_runtime .tick ()
274272 command = command_sub .recv_latest ()
275273 if isinstance (command , CommandPacket ) and command .command == "shutdown" :
276274 stop_event .set ()
@@ -321,15 +319,8 @@ def _main() -> None:
321319 )
322320 last_hand_seq = int (hand_snapshot .seq )
323321
324- if video_sub is not None :
325- descriptor = video_sub .recv_latest ()
326- if isinstance (descriptor , SharedFrameDescriptor ):
327- try :
328- frame = frame_reader .read (descriptor , copy = False )
329- provider .push_video_frame (np .asarray (frame , dtype = np .uint8 ))
330- last_video_seq = int (descriptor .seq )
331- except Exception as exc :
332- logger .warning ("Pico video frame dropped: %s" , exc )
322+ if video_cfg .enabled :
323+ last_video_seq = int (video_runtime .pushed_frames )
333324
334325 if now - last_health_s >= 1.0 :
335326 health_pub .publish (
@@ -349,9 +340,7 @@ def _main() -> None:
349340 last_health_s = now
350341 time .sleep (sleep_s )
351342 finally :
352- frame_reader .close ()
353- if video_sub is not None :
354- video_sub .close ()
343+ video_runtime .stop ()
355344 command_sub .close ()
356345 for publisher in (body_pub , hand_pub , controller_pub , events_pub , health_pub ):
357346 publisher .close ()
0 commit comments