1111 OperatingMode ,
1212)
1313
14- DEFAULT_PORT = " /dev/ttyACM0"
14+ DEFAULT_PORT = os . getenv ( "FEETECH_PORT" , " /dev/ttyACM0")
1515HALF_TURN_DEGREE = 180
1616
1717GENERAL_ACTIONS = {"sleep" , "print" }
2424
2525def probe_scan_ids (port : str ) -> dict [int , str ]:
2626 """
27- 探针扫描 ID 范围,返回 {id: model_name}(只含在线电机)。
28- 仅做 ping,不对电机写寄存器;断开时不关力矩。
27+ Probe ID range and return {id: model_name} (only online motors).
28+ Only ping, do not write to registers; do not disable torque on disconnect.
2929 """
3030
3131 probe_bus = build_bus (port , {})
@@ -58,7 +58,7 @@ def probe_scan_ids(port: str) -> dict[int, str]:
5858
5959def build_motors_from_scan (port : str ):
6060 """
61- 基于 probe_scan_ids 结果,构建 motors 字典(名称统一为 motor_<id>)。
61+ Build motors dict based on probe_scan_ids results (names unified as motor_<id>).
6262 """
6363 from lerobot .motors .motors_bus import Motor , MotorNormMode
6464 found = probe_scan_ids (port )
@@ -125,13 +125,13 @@ def _motor_angle_from_position(position):
125125
126126def get_motors_states (port ):
127127 """
128- 动态表格显示电机状态;总是先扫描 [scan_start, scan_end],只显示在线电机。
129- - 传了 motors 也不会直接用,而是按 ID 范围扫描后重建 motors(保证不读离线 ID)
128+ Display motor states in a dynamic table; always scan [scan_start, scan_end] first, showing only online motors.
129+ - Even if motors are passed, they are not used directly; motors are rebuilt after scanning the ID range (ensuring no offline IDs are read)
130130 """
131131 import time , sys , shutil
132132 from lerobot .motors .motors_bus import Motor , MotorNormMode
133133
134- # ---------- ANSI 工具 ----------
134+ # ---------- ANSI Utils ----------
135135 CSI = "\x1b ["
136136 def _hide_cursor (): sys .stdout .write (f"{ CSI } ?25l" ); sys .stdout .flush ()
137137 def _show_cursor (): sys .stdout .write (f"{ CSI } ?25h" ); sys .stdout .flush ()
@@ -152,17 +152,17 @@ def F(v, w, a=">"):
152152 f"{ F (st .get ('Temperature' ),4 )} | { F (st .get ('Port' ,'-' ),16 ,'<' )} " )
153153 return row [:maxw ] if len (row ) > maxw else row
154154
155- # ---------- 第一步:用探针扫描在线电机 ----------
155+ # ---------- Step 1: Scan for online motors using probe ----------
156156
157157 motors = build_motors_from_scan (port )
158158 if not motors :
159159 print (f"No motors found in ID range [{ SCAN_START } , { SCAN_END } ] on { port } ." )
160160 return
161161
162162
163- # ---------- 第二步:用“只包含在线电机”的字典进入动态显示 ----------
163+ # ---------- Step 2: Enter dynamic display using dict containing only online motors ----------
164164 bus = build_bus (port , motors )
165- if not _connect_bus (bus ): # 你的辅助函数里保持 handshake=False 更稳
165+ if not _connect_bus (bus ): # Keep handshake=False in helper function for stability
166166 return
167167
168168 try :
@@ -213,7 +213,7 @@ def F(v, w, a=">"):
213213
214214
215215 maxw = _term_width ()
216- sep = "-" * min (maxw , 140 ) # 由 120 放宽到 140
216+ sep = "-" * min (maxw , 140 ) # Widened from 120 to 140
217217 header = (f"{ 'NAME' :<15} | { 'ID' :>3} | { 'POS' :>6} | { 'OFF' :>6} | { 'ANG' :>6} | "
218218 f"{ 'LOAD' :>6} | { 'ACC' :>6} | { 'VOLT' :>4} | { 'CURR(MA)' :>8} | { 'TEMP' :>4} | PORT" )
219219 header = header [:maxw ] if len (header ) > maxw else header
@@ -235,7 +235,7 @@ def F(v, w, a=">"):
235235 except KeyboardInterrupt :
236236 pass
237237 finally :
238- # 关键:不要在断开时去“对所有电机”关力矩,避免离线 ID 报错
238+ # Key: Do not disable torque for "all motors" on disconnect to avoid errors from offline IDs.
239239 try :
240240 bus .disconnect (disable_torque = False )
241241 finally :
@@ -248,9 +248,9 @@ def configure_motor_id(port: str, current_id: int, new_id: int):
248248 current_id = int (current_id )
249249 new_id = int (new_id )
250250 if current_id == new_id :
251- raise SystemExit ("current_id == new_id,没有必要改。 " )
251+ raise SystemExit ("current_id == new_id, no change needed. " )
252252
253- # 1) 先用“裸总线”去 ping 校验(不带 motors 映射,避免库做多余事)
253+ # 1) Ping check using "bare bus" (without motors mapping to avoid extra library actions)
254254 probe_bus = FeetechMotorsBus (port = port , motors = {})
255255 try :
256256 probe_bus .connect (handshake = False )
@@ -265,11 +265,11 @@ def configure_motor_id(port: str, current_id: int, new_id: int):
265265 pass
266266
267267 if not ok_cur :
268- raise SystemExit (f"[ABORT] 未发现 ID={ current_id } 在线,放弃改 ID。 " )
268+ raise SystemExit (f"[ABORT] ID={ current_id } not online, aborting ID change. " )
269269 if ok_new :
270- raise SystemExit (f"[ABORT] 目标 ID={ new_id } 已被占用,放弃改 ID。 " )
270+ raise SystemExit (f"[ABORT] Target ID={ new_id } is occupied, aborting ID change. " )
271271
272- # 2) 用“只包含 current_id 的单电机字典”建立总线(名字无所谓,只要 id 是 current_id)
272+ # 2) Build bus with single-motor dict containing current_id (name doesn't matter, as long as id is current_id)
273273 tmp_name = f"motor_{ current_id } "
274274 one_motor = {
275275 tmp_name : Motor (id = current_id , model = DEFAULT_FEETECH_MODEL , norm_mode = MotorNormMode .RANGE_0_100 )
@@ -280,7 +280,7 @@ def configure_motor_id(port: str, current_id: int, new_id: int):
280280 bus .connect (handshake = False )
281281 print (f"Connected on port { bus .port } (current_id={ current_id } )" )
282282
283- # 保险:解锁 & 力矩处理(按你电机需要,可调整/删掉)
283+ # Safety: Unlock & Torque handling (adjust/remove as needed)
284284 try :
285285 bus .write ("Lock" , tmp_name , 0 , normalize = False )
286286 except Exception :
@@ -290,12 +290,12 @@ def configure_motor_id(port: str, current_id: int, new_id: int):
290290 except Exception :
291291 pass
292292
293- # 3) 直接对“当前 id 的那颗”写寄存器: ID = new_id
293+ # 3) Directly write register for "current id": ID = new_id
294294 bus .write ("ID" , tmp_name , new_id , normalize = False )
295295 time .sleep (0.2 )
296296
297- # 4) 改后校验:当前 id 应该失联, new_id 应该在线
298- # 这里用一个“空 bus”去 ping,避免受 motors 映射影响
297+ # 4) Post-change verify: current id should be offline, new_id should be online
298+ # Use an "empty bus" to ping here to avoid being affected by motors mapping
299299 probe_bus2 = FeetechMotorsBus (port = port , motors = {})
300300 try :
301301 probe_bus2 .connect (handshake = False )
@@ -309,7 +309,7 @@ def configure_motor_id(port: str, current_id: int, new_id: int):
309309
310310 if ok_cur2 or not ok_new2 :
311311 raise SystemExit (
312- f"[VERIFY FAIL] 改后验证失败: ID={ current_id } 仍在线 ={ ok_cur2 } , ID={ new_id } 在线 ={ ok_new2 } "
312+ f"[VERIFY FAIL] Post-change verify failed: ID={ current_id } still online ={ ok_cur2 } , ID={ new_id } online ={ ok_new2 } "
313313 )
314314
315315 print (f"[OK] Changed ID { current_id } -> { new_id } (model={ DEFAULT_FEETECH_MODEL } )" )
@@ -386,16 +386,16 @@ def move_motor_to_position(
386386 position : int ,
387387 ):
388388 """
389- 直接用数值ID控制电机到指定 position(原始ticks)。
390- - 不需要 motors{},不需要电机名。
391- - 默认确保处于“位置模式”,必要时切换。
389+ Control motor directly by numeric ID to specified position (raw ticks).
390+ - No motors{} or motor names needed.
391+ - Default to ensuring "Position Mode", switching if necessary.
392392 """
393393 tmp_name = f"motor_{ int (motor_id )} "
394394 one_motor = {
395395 tmp_name : Motor (id = int (motor_id ), model = DEFAULT_FEETECH_MODEL , norm_mode = MotorNormMode .RANGE_0_100 )
396396 }
397397
398- # 可选:简单范围夹取( 12bit 0~4095;按你家实际寄存器范围调整)
398+ # Optional: Simple range clamping ( 12bit 0~4095; adjust according to your register range)
399399 try :
400400 position = int (position )
401401 position = max (0 , min (4095 , position ))
@@ -407,7 +407,7 @@ def move_motor_to_position(
407407 bus .connect (handshake = False )
408408 print (f"Connected on port { bus .port } (ID={ motor_id } )" )
409409
410- # 若不确定电机当前模式,保险起见切到“位置模式”
410+ # Switch to "Position Mode" for safety if current mode is uncertain
411411 bus .disable_torque (tmp_name )
412412 bus .write ("Operating_Mode" , tmp_name , OperatingMode .POSITION .value , normalize = False )
413413 bus .enable_torque (tmp_name )
0 commit comments