mirror of
https://github.com/soconnor0919/hristudio.git
synced 2026-03-23 19:27:51 -04:00
Fix branching logic and robot action timing
- Remove onCompleted() call after branch selection to prevent count increment - Add proper duration estimation for speech actions (word count + emotion overhead) - Add say_with_emotion and wave_goodbye to built-in actions - Add identifier field to admin.ts plugin creation
This commit is contained in:
@@ -564,6 +564,7 @@ async function seedNAO6Plugin() {
|
|||||||
|
|
||||||
const pluginData: InsertPlugin = {
|
const pluginData: InsertPlugin = {
|
||||||
robotId: robotId,
|
robotId: robotId,
|
||||||
|
identifier: "nao6-ros2",
|
||||||
name: "NAO6 Robot (Enhanced ROS2 Integration)",
|
name: "NAO6 Robot (Enhanced ROS2 Integration)",
|
||||||
version: "2.0.0",
|
version: "2.0.0",
|
||||||
description:
|
description:
|
||||||
|
|||||||
@@ -536,7 +536,8 @@ export function WizardActionItem({
|
|||||||
onClick={(e) => {
|
onClick={(e) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
onExecute(action.id, { value, label, nextStepId });
|
onExecute(action.id, { value, label, nextStepId });
|
||||||
onCompleted();
|
// Don't call onCompleted() here - the branching logic in handleWizardResponse
|
||||||
|
// will handle the jump and reset completedActionsCount
|
||||||
}}
|
}}
|
||||||
disabled={readOnly || isExecuting}
|
disabled={readOnly || isExecuting}
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -438,8 +438,25 @@ export class WizardRosService extends EventEmitter {
|
|||||||
|
|
||||||
this.publish(config.topic, config.messageType, msg);
|
this.publish(config.topic, config.messageType, msg);
|
||||||
|
|
||||||
// Wait for action completion (simple delay for now)
|
// Wait for action completion based on topic type
|
||||||
await new Promise((resolve) => setTimeout(resolve, 100));
|
if (config.topic === "/speech") {
|
||||||
|
// Estimate speech duration based on text content
|
||||||
|
const text =
|
||||||
|
typeof msg === "object" && msg !== null && "data" in msg
|
||||||
|
? String((msg as any).data || "")
|
||||||
|
: JSON.stringify(msg);
|
||||||
|
const wordCount = text.split(/\s+/).filter(Boolean).length;
|
||||||
|
// Emotion markup adds overhead: ~200ms per word base + emotion animation time
|
||||||
|
const emotionOverhead = 1500; // Animation prep time
|
||||||
|
const duration = emotionOverhead + Math.max(1000, wordCount * 300);
|
||||||
|
console.log(
|
||||||
|
`[WizardROS] Speech action estimated duration: ${duration}ms (${wordCount} words)`,
|
||||||
|
);
|
||||||
|
await new Promise((resolve) => setTimeout(resolve, duration));
|
||||||
|
} else {
|
||||||
|
// Short delay for non-speech actions
|
||||||
|
await new Promise((resolve) => setTimeout(resolve, 500));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -452,13 +469,25 @@ export class WizardRosService extends EventEmitter {
|
|||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
switch (actionId) {
|
switch (actionId) {
|
||||||
case "say_text":
|
case "say_text":
|
||||||
|
case "say_with_emotion":
|
||||||
const text = String(parameters.text || "Hello");
|
const text = String(parameters.text || "Hello");
|
||||||
this.publish("/speech", "std_msgs/String", { data: text });
|
this.publish("/speech", "std_msgs/String", { data: text });
|
||||||
const wordCount = text.split(/\s+/).length;
|
const wordCount = text.split(/\s+/).filter(Boolean).length;
|
||||||
const duration = Math.max(800, wordCount * 250 + 500);
|
const emotion = String(parameters.emotion || "neutral");
|
||||||
|
const emotionOverhead = 1500;
|
||||||
|
const duration = emotionOverhead + Math.max(1000, wordCount * 300);
|
||||||
|
console.log(
|
||||||
|
`[WizardROS] Speech action (${actionId}) estimated: ${duration}ms`,
|
||||||
|
);
|
||||||
await new Promise((resolve) => setTimeout(resolve, duration));
|
await new Promise((resolve) => setTimeout(resolve, duration));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case "wave_goodbye":
|
||||||
|
const waveText = String(parameters.text || "Goodbye");
|
||||||
|
this.publish("/speech", "std_msgs/String", { data: waveText });
|
||||||
|
await new Promise((resolve) => setTimeout(resolve, 3000));
|
||||||
|
break;
|
||||||
|
|
||||||
case "walk_forward":
|
case "walk_forward":
|
||||||
this.publish("/cmd_vel", "geometry_msgs/Twist", {
|
this.publish("/cmd_vel", "geometry_msgs/Twist", {
|
||||||
linear: { x: Number(parameters.speed) || 0.1, y: 0, z: 0 },
|
linear: { x: Number(parameters.speed) || 0.1, y: 0, z: 0 },
|
||||||
|
|||||||
@@ -927,11 +927,17 @@ export const adminRouter = createTRPCRouter({
|
|||||||
|
|
||||||
if (existingPlugin.length === 0) {
|
if (existingPlugin.length === 0) {
|
||||||
// Create new plugin
|
// Create new plugin
|
||||||
|
const pluginName = pluginData.name ?? "unknown";
|
||||||
|
const slugIdentifier = pluginName
|
||||||
|
.toLowerCase()
|
||||||
|
.replace(/[^a-z0-9]+/g, "-")
|
||||||
|
.replace(/^-|-$/g, "");
|
||||||
const newPlugin = await db
|
const newPlugin = await db
|
||||||
.insert(plugins)
|
.insert(plugins)
|
||||||
.values({
|
.values({
|
||||||
|
identifier: slugIdentifier,
|
||||||
robotId,
|
robotId,
|
||||||
name: pluginData.name ?? "",
|
name: pluginName,
|
||||||
version: pluginData.version ?? "",
|
version: pluginData.version ?? "",
|
||||||
description: pluginData.description,
|
description: pluginData.description,
|
||||||
author:
|
author:
|
||||||
|
|||||||
Reference in New Issue
Block a user