Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow users to skip acquisition on error #144

Merged
merged 2 commits into from
Aug 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 0 additions & 6 deletions feedingwebapp/src/Pages/Constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
6 changes: 6 additions & 0 deletions feedingwebapp/src/Pages/Home/Home.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +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 = 'Skip Acquisition'
return (
<RobotMotion
debug={props.debug}
Expand All @@ -127,6 +130,9 @@ function Home(props) {
backMealState={backMealState}
actionInput={biteAcquisitionActionInput}
waitingText={getRobotMotionText(currentMealState)}
allowRetry={false} // Don't allow retrying bite acquisition
errorMealState={errorMealState}
errorMealStateDescription={errorMealStateDescription}
/>
)
}
Expand Down
110 changes: 79 additions & 31 deletions feedingwebapp/src/Pages/Home/MealStates/RobotMotion.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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.
Expand All @@ -279,12 +289,12 @@ const RobotMotion = (props) => {
* @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 (
<>
<View style={{ flex: flexSizeOuter, flexDirection: dimension, alignItems: 'center', justifyContent: 'center', width: '100%' }}>
Expand All @@ -294,19 +304,41 @@ const RobotMotion = (props) => {
</p>
<p style={{ fontSize: motionTextFontSize }}>{text}</p>
{showTime ? <p style={{ fontSize: motionTextFontSize }}>&nbsp;&nbsp;Elapsed: {time} sec</p> : <></>}
{retry ? (
<Button
variant='warning'
className='mx-2 btn-huge'
size='lg'
onClick={retryCallback}
style={{
width: '90%',
height: '20%'
}}
>
<h5 style={{ textAlign: 'center', fontSize: motionTextFontSize }}>Retry</h5>
</Button>
{error ? (
<>
{props.allowRetry ? (
<Button
variant='warning'
className='mx-2 btn-huge'
size='lg'
onClick={retryCallback}
style={{
width: '90%',
height: '20%'
}}
>
<h5 style={{ textAlign: 'center', fontSize: motionTextFontSize }}>Retry</h5>
</Button>
) : (
<></>
)}
{props.errorMealState ? (
<Button
variant='warning'
className='mx-2 btn-huge'
size='lg'
onClick={() => changeMealState(props.errorMealState, 'errorMealState')}
style={{
width: '90%',
height: '20%'
}}
>
<h5 style={{ textAlign: 'center', fontSize: motionTextFontSize }}>{props.errorMealStateDescription}</h5>
</Button>
) : (
<></>
)}
</>
) : (
<></>
)}
Expand All @@ -326,7 +358,17 @@ const RobotMotion = (props) => {
</>
)
},
[dimension, props.waitingText, motionTextFontSize, waitingTextFontSize, retryCallback]
[
dimension,
props.waitingText,
props.allowRetry,
props.errorMealState,
props.errorMealStateDescription,
motionTextFontSize,
waitingTextFontSize,
retryCallback,
changeMealState
]
)

/**
Expand All @@ -342,7 +384,7 @@ const RobotMotion = (props) => {
let showTime = false
let time = 0
let progress = null
let retry = false
let error = false
switch (actionStatus.actionStatus) {
case ROS_ACTION_STATUS_EXECUTE:
if (actionStatus.feedback) {
Expand Down Expand Up @@ -377,9 +419,9 @@ const RobotMotion = (props) => {
* users on how to troubleshoot/fix it.
*/
text = 'Robot encountered an error'
retry = NON_RETRYABLE_STATES.has(props.mealState) ? false : true
error = true
return (
<>{actionStatusTextAndVisual(flexSizeOuter, flexSizeTextInner, flexSizeVisualInner, text, showTime, time, progress, retry)}</>
<>{actionStatusTextAndVisual(flexSizeOuter, flexSizeTextInner, flexSizeVisualInner, text, showTime, time, progress, error)}</>
)
case ROS_ACTION_STATUS_CANCELED:
return <>{actionStatusTextAndVisual(flexSizeOuter, flexSizeTextInner, flexSizeVisualInner, text, showTime, time, progress)}</>
Expand All @@ -397,7 +439,7 @@ const RobotMotion = (props) => {
}
}
},
[paused, dimension, actionStatusTextAndVisual, props.mealState]
[paused, dimension, actionStatusTextAndVisual]
)

// Render the component
Expand All @@ -421,7 +463,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}
/>
</>
Expand Down Expand Up @@ -454,10 +496,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
}

Expand Down
Loading