NERDDISCO commited on
Commit
6a83670
Β·
1 Parent(s): 1a7b22d

feat: added releaseMotors

Browse files
examples/robot-control-web/components/CalibrationPanel.tsx CHANGED
@@ -11,8 +11,6 @@ import { Badge } from "./ui/badge.js";
11
  import {
12
  calibrate,
13
  releaseMotors,
14
- WebSerialPortWrapper,
15
- createSO100Config,
16
  type WebCalibrationResults,
17
  type LiveCalibrationData,
18
  type CalibrationProcess,
@@ -64,22 +62,13 @@ export function CalibrationPanel({ robot, onFinish }: CalibrationPanelProps) {
64
  setMotorData(initialData);
65
  }, [motorNames]);
66
 
67
- // βœ… Release motor torque
68
  const releaseMotorTorque = useCallback(async () => {
69
  try {
70
  setIsPreparing(true);
71
  setStatus("πŸ”“ Releasing motor torque - joints can now be moved freely");
72
 
73
- if (!robot.robotType) {
74
- throw new Error("Robot type not configured");
75
- }
76
-
77
- // Create port and get motor config
78
- const port = new WebSerialPortWrapper(robot.port);
79
- await port.initialize();
80
-
81
- const config = createSO100Config(robot.robotType);
82
- await releaseMotors(port, config.motorIds);
83
 
84
  setStatus("βœ… Joints are now free to move - set your homing position");
85
  } catch (error) {
 
11
  import {
12
  calibrate,
13
  releaseMotors,
 
 
14
  type WebCalibrationResults,
15
  type LiveCalibrationData,
16
  type CalibrationProcess,
 
62
  setMotorData(initialData);
63
  }, [motorNames]);
64
 
65
+ // Release motor torque
66
  const releaseMotorTorque = useCallback(async () => {
67
  try {
68
  setIsPreparing(true);
69
  setStatus("πŸ”“ Releasing motor torque - joints can now be moved freely");
70
 
71
+ await releaseMotors(robot);
 
 
 
 
 
 
 
 
 
72
 
73
  setStatus("βœ… Joints are now free to move - set your homing position");
74
  } catch (error) {
examples/test-sequential-operations.ts CHANGED
@@ -3,14 +3,7 @@
3
  * Tests: findPort β†’ calibrate β†’ releaseMotors β†’ teleoperate
4
  */
5
 
6
- import {
7
- findPort,
8
- calibrate,
9
- releaseMotors,
10
- teleoperate,
11
- WebSerialPortWrapper,
12
- createSO100Config,
13
- } from "@lerobot/web";
14
 
15
  let isRunning = false;
16
 
@@ -68,21 +61,15 @@ window.runSequentialTest = async function () {
68
  log(`βœ… Found robot: ${robot.name} (${robot.robotType})`);
69
  log(` Serial: ${robot.serialNumber}`);
70
 
71
- // Step 2: Release motors first, then calibrate
72
  log("\n2️⃣ Releasing motors for calibration setup...");
73
 
74
  if (!robot.robotType) {
75
  throw new Error("Robot type not configured");
76
  }
77
 
78
- // Release motors so you can move the arm during calibration
79
- log("πŸ”§ Creating port and config for motor release...");
80
- const setupPort = new WebSerialPortWrapper(robot.port);
81
- await setupPort.initialize();
82
- const setupConfig = createSO100Config(robot.robotType);
83
-
84
- log(`πŸ”“ Releasing ${setupConfig.motorIds.length} motors...`);
85
- await releaseMotors(setupPort, setupConfig.motorIds);
86
  log("βœ… Motors released - you can now move the arm freely!");
87
 
88
  // Now start calibration
@@ -275,12 +262,6 @@ window.runSequentialTest = async function () {
275
  log("⏱️ Auto-stopping teleoperation for test...");
276
  teleoperationProcess.stop();
277
  log("\nπŸŽ‰ All sequential operations completed successfully!");
278
- log(
279
- "\nπŸ“ RESULT: The current approach works but is too complex for users!"
280
- );
281
- log(
282
- "πŸ“ Users shouldn't need WebSerialPortWrapper and createSO100Config!"
283
- );
284
  setButtonState(false);
285
  }, 8000);
286
  } catch (error: any) {
 
3
  * Tests: findPort β†’ calibrate β†’ releaseMotors β†’ teleoperate
4
  */
5
 
6
+ import { findPort, calibrate, releaseMotors, teleoperate } from "@lerobot/web";
 
 
 
 
 
 
 
7
 
8
  let isRunning = false;
9
 
 
61
  log(`βœ… Found robot: ${robot.name} (${robot.robotType})`);
62
  log(` Serial: ${robot.serialNumber}`);
63
 
64
+ // Step 2: Release motors first for calibration setup
65
  log("\n2️⃣ Releasing motors for calibration setup...");
66
 
67
  if (!robot.robotType) {
68
  throw new Error("Robot type not configured");
69
  }
70
 
71
+ log("πŸ”“ Releasing all motors...");
72
+ await releaseMotors(robot);
 
 
 
 
 
 
73
  log("βœ… Motors released - you can now move the arm freely!");
74
 
75
  // Now start calibration
 
262
  log("⏱️ Auto-stopping teleoperation for test...");
263
  teleoperationProcess.stop();
264
  log("\nπŸŽ‰ All sequential operations completed successfully!");
 
 
 
 
 
 
265
  setButtonState(false);
266
  }, 8000);
267
  } catch (error: any) {
packages/web/src/index.ts CHANGED
@@ -9,6 +9,7 @@
9
  export { calibrate } from "./calibrate.js";
10
  export { teleoperate } from "./teleoperate.js";
11
  export { findPort } from "./find_port.js";
 
12
 
13
  // Browser support utilities
14
  export {
@@ -48,4 +49,3 @@ export {
48
  createSO100Config,
49
  SO100_KEYBOARD_CONTROLS,
50
  } from "./robots/so100_config.js";
51
- export { releaseMotors } from "./utils/motor-communication.js";
 
9
  export { calibrate } from "./calibrate.js";
10
  export { teleoperate } from "./teleoperate.js";
11
  export { findPort } from "./find_port.js";
12
+ export { releaseMotors } from "./release_motors.js";
13
 
14
  // Browser support utilities
15
  export {
 
49
  createSO100Config,
50
  SO100_KEYBOARD_CONTROLS,
51
  } from "./robots/so100_config.js";
 
packages/web/src/release_motors.ts ADDED
@@ -0,0 +1,70 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /**
2
+ * User-facing motor release functionality
3
+ * Simple API - pass in robotConnection, motors get released
4
+ *
5
+ * Handles robot configuration and port management internally
6
+ */
7
+
8
+ import { WebSerialPortWrapper } from "./utils/serial-port-wrapper.js";
9
+ import { createSO100Config } from "./robots/so100_config.js";
10
+ import { releaseMotors as releaseMotorsLowLevel } from "./utils/motor-communication.js";
11
+ import type { RobotConnection } from "./types/robot-connection.js";
12
+
13
+ /**
14
+ * Release robot motors (allows free movement by hand)
15
+ * Perfect for calibration setup or manual positioning
16
+ *
17
+ * @param robotConnection - Connected robot with configured type
18
+ * @param motorIds - Optional specific motor IDs to release (defaults to all motors for robot type)
19
+ * @throws Error if robot type not configured or motorIds invalid
20
+ */
21
+ export async function releaseMotors(
22
+ robotConnection: RobotConnection,
23
+ motorIds?: number[]
24
+ ): Promise<void> {
25
+ // Validate robot type is configured
26
+ if (!robotConnection.robotType) {
27
+ throw new Error(
28
+ "Robot type is required to release motors. Please configure the robot first."
29
+ );
30
+ }
31
+
32
+ // Validate robot connection
33
+ if (!robotConnection.isConnected || !robotConnection.port) {
34
+ throw new Error(
35
+ "Robot is not connected. Please use findPort() to connect first."
36
+ );
37
+ }
38
+
39
+ // Create port wrapper for communication
40
+ const port = new WebSerialPortWrapper(robotConnection.port);
41
+ await port.initialize();
42
+
43
+ // Get robot-specific configuration
44
+ let robotConfig;
45
+ if (robotConnection.robotType.startsWith("so100")) {
46
+ robotConfig = createSO100Config(robotConnection.robotType);
47
+ } else {
48
+ throw new Error(`Unsupported robot type: ${robotConnection.robotType}`);
49
+ }
50
+
51
+ // Determine which motors to release
52
+ const motorsToRelease = motorIds || robotConfig.motorIds;
53
+
54
+ // Validate motorIds are valid for this robot type
55
+ if (motorIds) {
56
+ const invalidMotors = motorIds.filter(
57
+ (id) => !robotConfig.motorIds.includes(id)
58
+ );
59
+ if (invalidMotors.length > 0) {
60
+ throw new Error(
61
+ `Invalid motor IDs [${invalidMotors.join(", ")}] for ${
62
+ robotConnection.robotType
63
+ }. Valid IDs: [${robotConfig.motorIds.join(", ")}]`
64
+ );
65
+ }
66
+ }
67
+
68
+ // Release the motors using low-level function
69
+ await releaseMotorsLowLevel(port, motorsToRelease);
70
+ }