From 5c7bbcd58f605952d24a906f4ae3a53dd169f4e8 Mon Sep 17 00:00:00 2001
From: Amal Nanavati
Date: Wed, 28 Aug 2024 10:25:35 -0700
Subject: [PATCH 1/2] Allow users to skip acquisition on error
---
feedingwebapp/src/Pages/Constants.js | 6 --
feedingwebapp/src/Pages/Home/Home.jsx | 5 ++
.../src/Pages/Home/MealStates/RobotMotion.jsx | 82 +++++++++++++++----
3 files changed, 71 insertions(+), 22 deletions(-)
diff --git a/feedingwebapp/src/Pages/Constants.js b/feedingwebapp/src/Pages/Constants.js
index cc7aae97..0bf1cd4f 100644
--- a/feedingwebapp/src/Pages/Constants.js
+++ b/feedingwebapp/src/Pages/Constants.js
@@ -43,12 +43,6 @@ export const SERVO_CARTESIAN_TOPIC_MSG = 'geometry_msgs/msg/TwistStamped'
export const SERVO_JOINT_TOPIC = '/web_app/servo_node/delta_joint_cmds'
export const SERVO_JOINT_TOPIC_MSG = 'control_msgs/msg/JointJog'
-// States from which, if they fail, it is NOT okay for the user to retry the
-// same action.
-let NON_RETRYABLE_STATES = new Set()
-NON_RETRYABLE_STATES.add(MEAL_STATE.R_BiteAcquisition)
-export { NON_RETRYABLE_STATES }
-
/**
* For states that call ROS actions, this dictionary contains
* the action name and the message type
diff --git a/feedingwebapp/src/Pages/Home/Home.jsx b/feedingwebapp/src/Pages/Home/Home.jsx
index 835e1a72..d9922125 100644
--- a/feedingwebapp/src/Pages/Home/Home.jsx
+++ b/feedingwebapp/src/Pages/Home/Home.jsx
@@ -118,6 +118,8 @@ function Home(props) {
let currentMealState = MEAL_STATE.R_BiteAcquisition
let nextMealState = MEAL_STATE.U_BiteAcquisitionCheck
let backMealState = MEAL_STATE.R_MovingAbovePlate
+ let errorMealState = MEAL_STATE.R_MovingToRestingPosition
+ let errorMealStateDescription = 'Proceed'
return (
)
}
diff --git a/feedingwebapp/src/Pages/Home/MealStates/RobotMotion.jsx b/feedingwebapp/src/Pages/Home/MealStates/RobotMotion.jsx
index b99958a9..8135d530 100644
--- a/feedingwebapp/src/Pages/Home/MealStates/RobotMotion.jsx
+++ b/feedingwebapp/src/Pages/Home/MealStates/RobotMotion.jsx
@@ -22,7 +22,6 @@ import { useGlobalState } from '../../GlobalState'
import {
CLEAR_OCTOMAP_SERVICE_NAME,
CLEAR_OCTOMAP_SERVICE_TYPE,
- NON_RETRYABLE_STATES,
ROS_ACTIONS_NAMES,
MOTION_STATUS_SUCCESS,
ROS_ACTION_STATUS_CANCEL_GOAL,
@@ -124,15 +123,28 @@ const RobotMotion = (props) => {
[setActionStatus]
)
+ /**
+ * Callback function to change the meal state.
+ */
+ const changeMealState = useCallback(
+ (nextMealState, msg = null) => {
+ if (msg) {
+ console.log(msg)
+ }
+ setPaused(false)
+ let setMealState = props.setMealState
+ setMealState(nextMealState)
+ },
+ [setPaused, props.setMealState]
+ )
+
/**
* Callback function for when the robot has finished moving to its staging
* location.
*/
const robotMotionDone = useCallback(() => {
- console.log('robotMotionDone')
- let setMealState = props.setMealState
- setMealState(props.nextMealState)
- }, [props.nextMealState, props.setMealState])
+ changeMealState(props.nextMealState, 'robotMotionDone')
+ }, [changeMealState, props.nextMealState])
/**
* Callback function for when the action sends a response. It updates the
@@ -264,10 +276,8 @@ const RobotMotion = (props) => {
}, [clearOctomapService, resumeCallback])
const backCallback = useCallback(() => {
- setPaused(false)
- let setMealState = props.setMealState
- setMealState(props.backMealState)
- }, [setPaused, props.backMealState, props.setMealState])
+ changeMealState(props.backMealState, 'backCallback')
+ }, [changeMealState, props.backMealState])
/**
* Get the action status text and progress bar or blank view to render.
@@ -310,6 +320,22 @@ const RobotMotion = (props) => {
) : (
<>>
)}
+ {props.errorMealState ? (
+
+ ) : (
+ <>>
+ )}
{
>
)
},
- [dimension, props.waitingText, motionTextFontSize, waitingTextFontSize, retryCallback]
+ [
+ dimension,
+ props.waitingText,
+ props.errorMealState,
+ props.errorMealStateDescription,
+ motionTextFontSize,
+ waitingTextFontSize,
+ retryCallback,
+ changeMealState
+ ]
)
/**
@@ -342,7 +377,6 @@ const RobotMotion = (props) => {
let showTime = false
let time = 0
let progress = null
- let retry = false
switch (actionStatus.actionStatus) {
case ROS_ACTION_STATUS_EXECUTE:
if (actionStatus.feedback) {
@@ -377,9 +411,19 @@ const RobotMotion = (props) => {
* users on how to troubleshoot/fix it.
*/
text = 'Robot encountered an error'
- retry = NON_RETRYABLE_STATES.has(props.mealState) ? false : true
return (
- <>{actionStatusTextAndVisual(flexSizeOuter, flexSizeTextInner, flexSizeVisualInner, text, showTime, time, progress, retry)}>
+ <>
+ {actionStatusTextAndVisual(
+ flexSizeOuter,
+ flexSizeTextInner,
+ flexSizeVisualInner,
+ text,
+ showTime,
+ time,
+ progress,
+ props.allowRetry
+ )}
+ >
)
case ROS_ACTION_STATUS_CANCELED:
return <>{actionStatusTextAndVisual(flexSizeOuter, flexSizeTextInner, flexSizeVisualInner, text, showTime, time, progress)}>
@@ -397,7 +441,7 @@ const RobotMotion = (props) => {
}
}
},
- [paused, dimension, actionStatusTextAndVisual, props.mealState]
+ [paused, dimension, actionStatusTextAndVisual, props.allowRetry]
)
// Render the component
@@ -421,7 +465,7 @@ const RobotMotion = (props) => {
pauseCallback={pauseCallback}
backCallback={props.backMealState ? backCallback : null}
backMealState={props.backMealState}
- resumeCallback={NON_RETRYABLE_STATES.has(props.mealState) ? null : resumeCallback}
+ resumeCallback={props.allowRetry ? resumeCallback : null}
paused={paused}
/>
>
@@ -454,10 +498,16 @@ RobotMotion.propTypes = {
// the action client, then calling it again, etc.)
actionInput: PropTypes.object.isRequired,
// The static text to display while the robot is executing the action
- waitingText: PropTypes.string.isRequired
+ waitingText: PropTypes.string.isRequired,
+ // Whether to show the retry/resume option if the action fails
+ allowRetry: PropTypes.bool,
+ // If error, show the user the option to transition to this meal state
+ errorMealState: PropTypes.string,
+ errorMealStateDescription: PropTypes.string
}
RobotMotion.defaultProps = {
+ allowRetry: true,
debug: false
}
From eef597aaf88e01e31b1fdf0b894ec459c2006443 Mon Sep 17 00:00:00 2001
From: Amal Nanavati
Date: Wed, 28 Aug 2024 11:03:47 -0700
Subject: [PATCH 2/2] Fixes from testing
---
feedingwebapp/src/Pages/Home/Home.jsx | 3 +-
.../src/Pages/Home/MealStates/RobotMotion.jsx | 86 +++++++++----------
2 files changed, 44 insertions(+), 45 deletions(-)
diff --git a/feedingwebapp/src/Pages/Home/Home.jsx b/feedingwebapp/src/Pages/Home/Home.jsx
index d9922125..86424819 100644
--- a/feedingwebapp/src/Pages/Home/Home.jsx
+++ b/feedingwebapp/src/Pages/Home/Home.jsx
@@ -118,8 +118,9 @@ function Home(props) {
let currentMealState = MEAL_STATE.R_BiteAcquisition
let nextMealState = MEAL_STATE.U_BiteAcquisitionCheck
let backMealState = MEAL_STATE.R_MovingAbovePlate
+ // TODO: Add an icon for this errorMealState!
let errorMealState = MEAL_STATE.R_MovingToRestingPosition
- let errorMealStateDescription = 'Proceed'
+ let errorMealStateDescription = 'Skip Acquisition'
return (
{
* @param {showTime} - indicates if elapsed time needs to be shown
* @param {time} - calculated elapsed time, 0 if time not available
* @param {progress} - progress proportion; if null progress bar not shown
- * @param {retry} - indicates if retry needed for error
+ * @param {error} - indicates if there was an error
*
* @returns {JSX.Element} the action status text, progress bar or blank view
*/
const actionStatusTextAndVisual = useCallback(
- (flexSizeOuter, flexSizeTextInner, flexSizeVisualInner, text, showTime, time, progress, retry = false) => {
+ (flexSizeOuter, flexSizeTextInner, flexSizeVisualInner, text, showTime, time, progress, error = false) => {
return (
<>
@@ -304,35 +304,41 @@ const RobotMotion = (props) => {
{text}
{showTime ? Elapsed: {time} sec
: <>>}
- {retry ? (
-
- ) : (
- <>>
- )}
- {props.errorMealState ? (
-
+ {error ? (
+ <>
+ {props.allowRetry ? (
+
+ ) : (
+ <>>
+ )}
+ {props.errorMealState ? (
+
+ ) : (
+ <>>
+ )}
+ >
) : (
<>>
)}
@@ -355,6 +361,7 @@ const RobotMotion = (props) => {
[
dimension,
props.waitingText,
+ props.allowRetry,
props.errorMealState,
props.errorMealStateDescription,
motionTextFontSize,
@@ -377,6 +384,7 @@ const RobotMotion = (props) => {
let showTime = false
let time = 0
let progress = null
+ let error = false
switch (actionStatus.actionStatus) {
case ROS_ACTION_STATUS_EXECUTE:
if (actionStatus.feedback) {
@@ -411,19 +419,9 @@ const RobotMotion = (props) => {
* users on how to troubleshoot/fix it.
*/
text = 'Robot encountered an error'
+ error = true
return (
- <>
- {actionStatusTextAndVisual(
- flexSizeOuter,
- flexSizeTextInner,
- flexSizeVisualInner,
- text,
- showTime,
- time,
- progress,
- props.allowRetry
- )}
- >
+ <>{actionStatusTextAndVisual(flexSizeOuter, flexSizeTextInner, flexSizeVisualInner, text, showTime, time, progress, error)}>
)
case ROS_ACTION_STATUS_CANCELED:
return <>{actionStatusTextAndVisual(flexSizeOuter, flexSizeTextInner, flexSizeVisualInner, text, showTime, time, progress)}>
@@ -441,7 +439,7 @@ const RobotMotion = (props) => {
}
}
},
- [paused, dimension, actionStatusTextAndVisual, props.allowRetry]
+ [paused, dimension, actionStatusTextAndVisual]
)
// Render the component