diff --git a/feedingwebapp/src/Pages/GlobalState.jsx b/feedingwebapp/src/Pages/GlobalState.jsx
index 8398b344..3958a126 100644
--- a/feedingwebapp/src/Pages/GlobalState.jsx
+++ b/feedingwebapp/src/Pages/GlobalState.jsx
@@ -82,7 +82,8 @@ export { NON_MOVING_STATES }
export const SETTINGS_STATE = {
MAIN: 'MAIN',
BITE_TRANSFER: 'BITE_TRANSFER',
- ABOVE_PLATE: 'ABOVE_PLATE'
+ ABOVE_PLATE: 'ABOVE_PLATE',
+ RESTING_CONFIGURATION: 'RESTING_CONFIGURATION'
}
// The name of the default parameter namespace
diff --git a/feedingwebapp/src/Pages/Header/TeleopSubcomponent.jsx b/feedingwebapp/src/Pages/Header/TeleopSubcomponent.jsx
index 02c83eee..132f9ef9 100644
--- a/feedingwebapp/src/Pages/Header/TeleopSubcomponent.jsx
+++ b/feedingwebapp/src/Pages/Header/TeleopSubcomponent.jsx
@@ -152,14 +152,14 @@ const TeleopSubcomponent = (props) => {
* When the component is unmounted, stop servo.
*/
useEffect(() => {
- let stopServoSuccessCallback = props.stopServoSuccessCallback
+ let unmountCallback = props.unmountCallback
return () => {
console.log('Unmounting teleop subcomponent.')
destroyActionClient(startCartesianControllerAction)
destroyActionClient(startJointControllerAction)
- stopServoSuccessCallback.current()
+ unmountCallback.current()
}
- }, [startCartesianControllerAction, startJointControllerAction, props.stopServoSuccessCallback])
+ }, [startCartesianControllerAction, startJointControllerAction, props.unmountCallback])
/**
* Callback function to publish constant cartesian cartesian velocity commands.
@@ -650,12 +650,12 @@ const TeleopSubcomponent = (props) => {
}
TeleopSubcomponent.propTypes = {
// A reference to a function to be called if StopServo is succesfully run.
- stopServoSuccessCallback: PropTypes.object,
+ unmountCallback: PropTypes.object,
// A function to be called when one of the teleop buttons are released
teleopButtonOnReleaseCallback: PropTypes.func
}
TeleopSubcomponent.defaultProps = {
- stopServoSuccessCallback: { current: () => {} },
+ unmountCallback: { current: () => {} },
teleopButtonOnReleaseCallback: () => {}
}
export default TeleopSubcomponent
diff --git a/feedingwebapp/src/Pages/Settings/AbovePlate.jsx b/feedingwebapp/src/Pages/Settings/CustomizeConfiguration.jsx
similarity index 74%
rename from feedingwebapp/src/Pages/Settings/AbovePlate.jsx
rename to feedingwebapp/src/Pages/Settings/CustomizeConfiguration.jsx
index be405172..514e2567 100644
--- a/feedingwebapp/src/Pages/Settings/AbovePlate.jsx
+++ b/feedingwebapp/src/Pages/Settings/CustomizeConfiguration.jsx
@@ -8,7 +8,6 @@ import { View } from 'react-native'
// Local imports
import { useROS, createROSService, createROSServiceRequest } from '../../ros/ros_helpers'
import {
- ABOVE_PLATE_PARAM_JOINTS,
CAMERA_FEED_TOPIC,
getRobotMotionText,
GET_JOINT_STATE_SERVICE_NAME,
@@ -23,10 +22,16 @@ import SettingsPageParent from './SettingsPageParent'
import VideoFeed from '../Home/VideoFeed'
/**
- * The AbovePlate component allows users to configure the "above plate" configuration
- * the robot moves to before bite selection.
+ * The CustomizeConfiguration component allows users to configure the one of the
+ * fixed configurations the robot uses. In its current form, the node can take in
+ * multiple parameters, but will set them all to the same joint state positions.
*/
-const AbovePlate = (props) => {
+const CustomizeConfiguration = (props) => {
+ // Check the props
+ if (Object.values(MEAL_STATE).indexOf(props.startingMealState) === -1) {
+ throw new Error('Invalid starting meal state ' + props.startingMealState)
+ }
+
// Get relevant global state variables
const setSettingsState = useGlobalState((state) => state.setSettingsState)
const globalMealState = useGlobalState((state) => state.mealState)
@@ -35,18 +40,17 @@ const AbovePlate = (props) => {
// Create relevant local state variables
// Configure the parameters for SettingsPageParent
- const paramNames = useMemo(() => [ABOVE_PLATE_PARAM_JOINTS], [])
- const [currentAbovePlateParam, setCurrentAbovePlateParam] = useState([null])
+ const [currentConfigurationParams, setCurrentConfigurationParams] = useState(props.paramNames.map(() => null))
const [localCurrAndNextMealState, setLocalCurrAndNextMealState] = useState(
globalMealState === MEAL_STATE.U_BiteDone || biteTransferPageAtFace
- ? [MEAL_STATE.R_MovingFromMouth, MEAL_STATE.R_MovingAbovePlate]
- : [MEAL_STATE.R_MovingAbovePlate, null]
+ ? [MEAL_STATE.R_MovingFromMouth, props.startingMealState]
+ : [props.startingMealState, null]
)
const actionInput = useMemo(() => ({}), [])
const doneButtonIsClicked = useRef(false)
const [zoomLevel, setZoomLevel] = useState(1.0)
const [mountTeleopSubcomponent, setMountTeleopSubcomponent] = useState(false)
- const stopServoSuccessCallback = useRef(() => {})
+ const unmountTeleopSubcomponentCallback = useRef(() => {})
// Flag to check if the current orientation is portrait
const isPortrait = useMediaQuery({ query: '(orientation: portrait)' })
@@ -62,8 +66,8 @@ const AbovePlate = (props) => {
(newLocalCurrMealState, newLocalNextMealState = null) => {
console.log('setLocalCurrMealStateWrapper evaluated')
let oldLocalCurrMealState = localCurrAndNextMealState[0]
- // Only mount the teleop subcomponent if the robot finished moving above the plate
- if (newLocalCurrMealState === null && oldLocalCurrMealState === MEAL_STATE.R_MovingAbovePlate) {
+ // Only mount the teleop subcomponent if the robot finished the prereq motion for this page
+ if (newLocalCurrMealState === null && oldLocalCurrMealState === props.startingMealState) {
setMountTeleopSubcomponent(true)
}
// Start in a moving state, not a paused state
@@ -77,18 +81,24 @@ const AbovePlate = (props) => {
setLocalCurrAndNextMealState([newLocalCurrMealState, newLocalNextMealState])
}
},
- [localCurrAndNextMealState, setLocalCurrAndNextMealState, setMountTeleopSubcomponent, doneButtonIsClicked, setPaused, setSettingsState]
+ [
+ doneButtonIsClicked,
+ localCurrAndNextMealState,
+ props.startingMealState,
+ setLocalCurrAndNextMealState,
+ setMountTeleopSubcomponent,
+ setPaused,
+ setSettingsState
+ ]
)
// Get the function that sets the local curr meal state and next meal state variables.
// Note this does not execute it. It is used to pass the function to other components.
const getSetLocalCurrMealStateWrapper = useCallback(
(newLocalCurrMealState, newLocalNextMealState = null) => {
- console.log('getSetLocalCurrMealStateWrapper evaluated')
let retval = () => {
- console.log('getSetLocalCurrMealStateWrapper retval evaluated')
setLocalCurrMealStateWrapper(newLocalCurrMealState, newLocalNextMealState)
- stopServoSuccessCallback.current = () => {}
+ unmountTeleopSubcomponentCallback.current = () => {}
}
// If the teleop subcomponent was mounted, unmount it and let the stopServo
// success callback handle the rest. However, sometimes the success message
@@ -101,7 +111,7 @@ const AbovePlate = (props) => {
}
return retval
},
- [mountTeleopSubcomponent, setLocalCurrMealStateWrapper, setMountTeleopSubcomponent, stopServoSuccessCallback]
+ [mountTeleopSubcomponent, setLocalCurrMealStateWrapper, setMountTeleopSubcomponent, unmountTeleopSubcomponentCallback]
)
// Store the props for the RobotMotion call.
@@ -149,17 +159,17 @@ const AbovePlate = (props) => {
})
service.callService(request, (response) => {
console.log('Got joint state response', response)
- setCurrentAbovePlateParam([response.joint_state.position])
+ setCurrentConfigurationParams(props.paramNames.map(() => response.joint_state.position))
})
- }, [getJointStateService, setCurrentAbovePlateParam])
+ }, [getJointStateService, props.paramNames, setCurrentConfigurationParams])
// Callback to move the robot to another configuration
const moveToButtonClicked = useCallback(
(nextMealState) => {
doneButtonIsClicked.current = false
- stopServoSuccessCallback.current = getSetLocalCurrMealStateWrapper(nextMealState)
+ unmountTeleopSubcomponentCallback.current = getSetLocalCurrMealStateWrapper(nextMealState)
},
- [getSetLocalCurrMealStateWrapper, doneButtonIsClicked, stopServoSuccessCallback]
+ [getSetLocalCurrMealStateWrapper, doneButtonIsClicked, unmountTeleopSubcomponentCallback]
)
// Callback to return to the main settings page
@@ -191,11 +201,11 @@ const AbovePlate = (props) => {
localCurrMealState = MEAL_STATE.R_MovingAbovePlate
break
}
- stopServoSuccessCallback.current = getSetLocalCurrMealStateWrapper(localCurrMealState, localNextMealState)
- }, [getSetLocalCurrMealStateWrapper, globalMealState, doneButtonIsClicked, stopServoSuccessCallback])
+ unmountTeleopSubcomponentCallback.current = getSetLocalCurrMealStateWrapper(localCurrMealState, localNextMealState)
+ }, [getSetLocalCurrMealStateWrapper, globalMealState, doneButtonIsClicked, unmountTeleopSubcomponentCallback])
// Callback to render the main contents of the page
- const renderAbovePlateSettings = useCallback(() => {
+ const renderSettings = useCallback(() => {
return (
{
<>
>
) : (
- To tune the “Above Plate” configuration, first “Move Above Plate.”
+ To tune the “{props.configurationName}” configuration, first “{props.buttonName}.”
)}
@@ -238,38 +248,24 @@ const AbovePlate = (props) => {
height: '100%'
}}
>
-
-
-
-
-
-
+ {props.otherButtonConfigs.map(({ name, mealState }) => (
+
+
+
+ ))}
@@ -295,10 +291,14 @@ const AbovePlate = (props) => {
textFontSize,
sizeSuffix,
zoomLevel,
+ props.buttonName,
+ props.configurationName,
+ props.otherButtonConfigs,
+ props.startingMealState,
props.webrtcURL,
mountTeleopSubcomponent,
moveToButtonClicked,
- stopServoSuccessCallback,
+ unmountTeleopSubcomponentCallback,
storeJointStatesAsLocalParam
])
@@ -311,6 +311,7 @@ const AbovePlate = (props) => {
// Render the modal body, for calling robot code from within this settings page
const renderModalBody = useCallback(() => {
+ console.log('renderModalBody', localCurrAndNextMealState, robotMotionProps)
let localCurrMealState = localCurrAndNextMealState[0]
switch (localCurrMealState) {
case MEAL_STATE.R_MovingToStagingConfiguration:
@@ -338,23 +339,38 @@ const AbovePlate = (props) => {
return (
setLocalCurrMealStateWrapper(null)}
modalChildren={renderModalBody()}
- paramNames={paramNames}
- localParamValues={currentAbovePlateParam}
- setLocalParamValues={setCurrentAbovePlateParam}
- resetToPresetSuccessCallback={() => moveToButtonClicked(MEAL_STATE.R_MovingAbovePlate)}
+ paramNames={props.paramNames}
+ localParamValues={currentConfigurationParams}
+ setLocalParamValues={setCurrentConfigurationParams}
+ resetToPresetSuccessCallback={() => moveToButtonClicked(props.startingMealState)}
>
- {renderAbovePlateSettings()}
+ {renderSettings()}
)
}
-AbovePlate.propTypes = {
+CustomizeConfiguration.propTypes = {
+ // The meal state that must be executed before this page is rendered
+ startingMealState: PropTypes.string.isRequired,
+ // The names of the parameter this component should tune.
+ paramNames: PropTypes.arrayOf(PropTypes.string).isRequired,
+ // The name of the configuration this component tunes.
+ configurationName: PropTypes.string.isRequired,
+ // The name of the button that should be clicked to tune the configuration.
+ buttonName: PropTypes.string.isRequired,
+ // Other button configs
+ otherButtonConfigs: PropTypes.arrayOf(
+ PropTypes.shape({
+ name: PropTypes.string.isRequired,
+ mealState: PropTypes.string.isRequired
+ })
+ ).isRequired,
// The URL of the webrtc signalling server
webrtcURL: PropTypes.string.isRequired
}
-export default AbovePlate
+export default CustomizeConfiguration
diff --git a/feedingwebapp/src/Pages/Settings/Main.jsx b/feedingwebapp/src/Pages/Settings/Main.jsx
index b0bd2bde..f0f696a6 100644
--- a/feedingwebapp/src/Pages/Settings/Main.jsx
+++ b/feedingwebapp/src/Pages/Settings/Main.jsx
@@ -156,6 +156,7 @@ const Main = () => {
// Get icon image for move to mouth
let moveToMouthConfigurationImage = MOVING_STATE_ICON_DICT[MEAL_STATE.R_MovingToMouth]
let moveAbovePlateConfigurationImage = MOVING_STATE_ICON_DICT[MEAL_STATE.R_MovingAbovePlate]
+ let moveToRestingConfigurationImage = MOVING_STATE_ICON_DICT[MEAL_STATE.R_MovingToRestingPosition]
// Configure the different options in the settings menu
let settingsConfig = [
@@ -168,6 +169,11 @@ const Main = () => {
title: 'Above Plate',
icon: moveAbovePlateConfigurationImage,
onClick: () => onClickSettingsPage(SETTINGS_STATE.ABOVE_PLATE)
+ },
+ {
+ title: 'Resting Position',
+ icon: moveToRestingConfigurationImage,
+ onClick: () => onClickSettingsPage(SETTINGS_STATE.RESTING_CONFIGURATION)
}
]
diff --git a/feedingwebapp/src/Pages/Settings/Settings.jsx b/feedingwebapp/src/Pages/Settings/Settings.jsx
index cc84b68c..840467cf 100644
--- a/feedingwebapp/src/Pages/Settings/Settings.jsx
+++ b/feedingwebapp/src/Pages/Settings/Settings.jsx
@@ -4,10 +4,11 @@ import PropTypes from 'prop-types'
import { View } from 'react-native'
// Local imports
-import { useGlobalState, SETTINGS_STATE } from '../GlobalState'
+import { useGlobalState, SETTINGS_STATE, MEAL_STATE } from '../GlobalState'
import Main from './Main'
-import AbovePlate from './AbovePlate'
+import CustomizeConfiguration from './CustomizeConfiguration'
import BiteTransfer from './BiteTransfer'
+import { ABOVE_PLATE_PARAM_JOINTS, RESTING_PARAM_JOINTS_1, RESTING_PARAM_JOINTS_2 } from '../Constants'
/**
* The Settings components displays the appropriate settings page based on the
@@ -25,7 +26,45 @@ const Settings = (props) => {
case SETTINGS_STATE.BITE_TRANSFER:
return
case SETTINGS_STATE.ABOVE_PLATE:
- return
+ return (
+
+ )
+ case SETTINGS_STATE.RESTING_CONFIGURATION:
+ return (
+
+ )
default:
console.log('Invalid settings state', settingsState)
return