mirror of
https://github.com/soconnor0919/hristudio.git
synced 2026-05-08 13:58:55 -04:00
fix(trial-execution): handle SSH actions without requiring ROS connection
- Add startTime parameter to executeRobotActionInternal for proper duration tracking - SSH actions (animations, posture commands) now work without ROS bridge connection - Refactor executeAction to handle SSH and ROS paths separately
This commit is contained in:
@@ -181,41 +181,71 @@ export class RobotCommunicationService extends EventEmitter {
|
|||||||
* Execute a robot action
|
* Execute a robot action
|
||||||
*/
|
*/
|
||||||
async executeAction(action: RobotAction): Promise<RobotActionResult> {
|
async executeAction(action: RobotAction): Promise<RobotActionResult> {
|
||||||
|
const actionId = `action_${this.messageId++}`;
|
||||||
|
const startTime = Date.now();
|
||||||
|
|
||||||
|
// Check if this is an SSH-only action (animations, posture, arbitrary SSH commands)
|
||||||
|
const { implementation, actionId: actionType } = action;
|
||||||
|
const baseActionId = actionType.includes(".")
|
||||||
|
? actionType.split(".").pop()
|
||||||
|
: actionType;
|
||||||
|
|
||||||
|
const isAnimationAction = baseActionId?.startsWith("play_animation_");
|
||||||
|
const sshCommand = implementation.payloadMapping?.sshCommand
|
||||||
|
|| implementation.ros2?.payloadMapping?.sshCommand;
|
||||||
|
|
||||||
|
// SSH actions don't require ROS connection
|
||||||
|
if (isAnimationAction || sshCommand) {
|
||||||
|
const timeout = setTimeout(() => {
|
||||||
|
throw new Error(`SSH action timeout: ${action.actionId}`);
|
||||||
|
}, 30000);
|
||||||
|
|
||||||
|
try {
|
||||||
|
console.log(`[RobotComm] Executing SSH action: ${action.actionId}`);
|
||||||
|
const result = await this.executeRobotActionInternal(action, actionId, startTime);
|
||||||
|
clearTimeout(timeout);
|
||||||
|
return result;
|
||||||
|
} catch (error) {
|
||||||
|
clearTimeout(timeout);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Non-SSH actions require ROS connection
|
||||||
if (!this.isConnected) {
|
if (!this.isConnected) {
|
||||||
throw new Error("Not connected to ROS bridge");
|
throw new Error("Not connected to ROS bridge");
|
||||||
}
|
}
|
||||||
|
|
||||||
const startTime = Date.now();
|
// Store pending action
|
||||||
const actionId = `action_${this.messageId++}`;
|
const pending = {
|
||||||
|
resolve: (() => {}) as (result: RobotActionResult) => void,
|
||||||
return new Promise((resolve, reject) => {
|
reject: (() => {}) as (error: Error) => void,
|
||||||
// Set up timeout
|
timeout: setTimeout(() => {
|
||||||
const timeout = setTimeout(() => {
|
|
||||||
this.pendingActions.delete(actionId);
|
this.pendingActions.delete(actionId);
|
||||||
reject(new Error(`Action timeout: ${action.actionId}`));
|
pending.reject(new Error(`Action timeout: ${action.actionId}`));
|
||||||
}, 30000); // 30 second timeout
|
}, 30000),
|
||||||
|
startTime,
|
||||||
|
};
|
||||||
|
|
||||||
// Store pending action
|
this.pendingActions.set(actionId, pending);
|
||||||
this.pendingActions.set(actionId, {
|
|
||||||
resolve,
|
|
||||||
reject,
|
|
||||||
timeout,
|
|
||||||
startTime,
|
|
||||||
});
|
|
||||||
|
|
||||||
try {
|
// Wrap the pending resolve/reject in a way that works with async method
|
||||||
// Log the action we're about to execute
|
return new Promise<RobotActionResult>((resolve, reject) => {
|
||||||
console.log(`[RobotComm] Executing robot action: ${action.actionId}`);
|
pending.resolve = resolve;
|
||||||
console.log(`[RobotComm] Topic: ${action.implementation.topic}`);
|
pending.reject = reject;
|
||||||
console.log(`[RobotComm] Parameters:`, action.parameters);
|
|
||||||
|
|
||||||
// Execute action based on type and platform
|
// Execute action
|
||||||
this.executeRobotActionInternal(action, actionId);
|
this.executeRobotActionInternal(action, actionId, startTime)
|
||||||
} catch (error) {
|
.then((result) => {
|
||||||
clearTimeout(timeout);
|
clearTimeout(pending.timeout);
|
||||||
this.pendingActions.delete(actionId);
|
this.pendingActions.delete(actionId);
|
||||||
reject(error);
|
resolve(result);
|
||||||
}
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
clearTimeout(pending.timeout);
|
||||||
|
this.pendingActions.delete(actionId);
|
||||||
|
reject(error);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -228,10 +258,11 @@ export class RobotCommunicationService extends EventEmitter {
|
|||||||
|
|
||||||
// Private methods
|
// Private methods
|
||||||
|
|
||||||
private executeRobotActionInternal(
|
private async executeRobotActionInternal(
|
||||||
action: RobotAction,
|
action: RobotAction,
|
||||||
actionId: string,
|
actionId: string,
|
||||||
): void {
|
startTime: number,
|
||||||
|
): Promise<RobotActionResult> {
|
||||||
const { implementation, parameters, actionId: actionType } = action;
|
const { implementation, parameters, actionId: actionType } = action;
|
||||||
|
|
||||||
// Use SSH for play_animation actions (check both namespaced and non-namespaced)
|
// Use SSH for play_animation actions (check both namespaced and non-namespaced)
|
||||||
@@ -240,18 +271,12 @@ export class RobotCommunicationService extends EventEmitter {
|
|||||||
: actionType;
|
: actionType;
|
||||||
|
|
||||||
if (baseActionId?.startsWith("play_animation_")) {
|
if (baseActionId?.startsWith("play_animation_")) {
|
||||||
this.executeAnimationViaSSH(baseActionId).then(() => {
|
await this.executeAnimationViaSSH(baseActionId);
|
||||||
this.completeAction(actionId, {
|
return {
|
||||||
success: true,
|
success: true,
|
||||||
duration:
|
duration: Date.now() - startTime,
|
||||||
Date.now() -
|
data: { method: "ssh", action: baseActionId },
|
||||||
(this.pendingActions.get(actionId)?.startTime || Date.now()),
|
};
|
||||||
data: { method: "ssh", action: baseActionId },
|
|
||||||
});
|
|
||||||
}).catch((error) => {
|
|
||||||
this.pendingActions.get(actionId)?.reject(error);
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check for SSH command type
|
// Check for SSH command type
|
||||||
@@ -259,18 +284,12 @@ export class RobotCommunicationService extends EventEmitter {
|
|||||||
|| implementation.ros2?.payloadMapping?.sshCommand;
|
|| implementation.ros2?.payloadMapping?.sshCommand;
|
||||||
|
|
||||||
if (sshCommand) {
|
if (sshCommand) {
|
||||||
this.executeSSHCommand(sshCommand).then(() => {
|
await this.executeSSHCommand(sshCommand);
|
||||||
this.completeAction(actionId, {
|
return {
|
||||||
success: true,
|
success: true,
|
||||||
duration:
|
duration: Date.now() - startTime,
|
||||||
Date.now() -
|
data: { method: "ssh", command: sshCommand },
|
||||||
(this.pendingActions.get(actionId)?.startTime || Date.now()),
|
};
|
||||||
data: { method: "ssh", command: sshCommand },
|
|
||||||
});
|
|
||||||
}).catch((error) => {
|
|
||||||
this.pendingActions.get(actionId)?.reject(error);
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Apply transform if specified
|
// Apply transform if specified
|
||||||
@@ -297,19 +316,19 @@ export class RobotCommunicationService extends EventEmitter {
|
|||||||
|
|
||||||
// For actions that complete immediately (like movement commands),
|
// For actions that complete immediately (like movement commands),
|
||||||
// we simulate completion after a short delay
|
// we simulate completion after a short delay
|
||||||
setTimeout(() => {
|
return new Promise((resolve) => {
|
||||||
this.completeAction(actionId, {
|
setTimeout(() => {
|
||||||
success: true,
|
resolve({
|
||||||
duration:
|
success: true,
|
||||||
Date.now() -
|
duration: Date.now() - startTime,
|
||||||
(this.pendingActions.get(actionId)?.startTime || Date.now()),
|
data: {
|
||||||
data: {
|
topic: implementation.topic,
|
||||||
topic: implementation.topic,
|
messageType: implementation.messageType,
|
||||||
messageType: implementation.messageType,
|
message,
|
||||||
message,
|
},
|
||||||
},
|
});
|
||||||
});
|
}, 100);
|
||||||
}, 100);
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private async executeSSHCommand(command: string): Promise<void> {
|
private async executeSSHCommand(command: string): Promise<void> {
|
||||||
|
|||||||
Reference in New Issue
Block a user