Skip to content

Commit ec73b0e

Browse files
authored
Temporary fix for video latency (#111)
* Revert default sim image to match with depth * Lower publication rate to prevent lag on VideoFeed * Aesthetic changes on DetectingFood * Change updateHz in app to 3Hz
1 parent b40a684 commit ec73b0e

File tree

4 files changed

+46
-32
lines changed

4 files changed

+46
-32
lines changed

feeding_web_app_ros2_test/launch/feeding_web_app_dummy_nodes_launch.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
<remap from="~/camera_info" to="/camera/color/camera_info"/>
2424
<remap from="~/aligned_depth/camera_info" to="/camera/aligned_depth_to_color/camera_info"/>
2525
<param name="fps" value="30"/>
26-
<param name="rgb_path" value="$(find-pkg-share feeding_web_app_ros2_test)/../data/2022_11_01_ada_picks_up_carrots_camera_compressed_ft_tf.mp4"/>
26+
<param name="rgb_path" value="$(find-pkg-share feeding_web_app_ros2_test)/../data/above_plate_1_rgb.jpg"/>
2727
<param name="depth_path" value="$(find-pkg-share feeding_web_app_ros2_test)/../data/above_plate_1_depth.png"/>
2828
</node>
2929
</group>

feedingwebapp/src/Pages/Constants.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,10 +48,10 @@ NON_MOVING_STATES.add(MEAL_STATE.U_PostMeal)
4848
export { NON_MOVING_STATES }
4949

5050
// The names of the ROS topic(s)
51-
export const CAMERA_FEED_TOPIC = '/local/camera/color/image_raw/compressed'
51+
export const CAMERA_FEED_TOPIC = '/local/camera/color/image_raw/compressed/low_hz'
5252
export const FACE_DETECTION_TOPIC = '/face_detection'
5353
export const FACE_DETECTION_TOPIC_MSG = 'ada_feeding_msgs/FaceDetection'
54-
export const FACE_DETECTION_IMG_TOPIC = '/face_detection_img/compressed'
54+
export const FACE_DETECTION_IMG_TOPIC = '/face_detection_img/compressed/low_hz'
5555

5656
// States from which, if they fail, it is NOT okay for the user to retry the
5757
// same action.

feedingwebapp/src/Pages/Home/MealStates/DetectingFace.jsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,9 +43,9 @@ const DetectingFace = () => {
4343
// Font size for text
4444
let textFontSize = 3
4545
let buttonWidth = 30
46-
let buttonHeight = 20
46+
let buttonHeight = 18
4747
let iconWidth = 28
48-
let iconHeight = 18
48+
let iconHeight = 16
4949
let sizeSuffix = isPortrait ? 'vh' : 'vw'
5050
// The min and max distance from the camera to the face for the face to be
5151
// conidered valid. NOTE: This must match the values in the MoveToMouth tree.

feedingwebapp/src/Pages/Home/VideoFeed.jsx

Lines changed: 41 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -85,30 +85,39 @@ const VideoFeed = (props) => {
8585
* re-connecting upon re-renders.
8686
*/
8787
const ros = useRef(useROS().ros)
88-
// Store the latest image timestamp in a ref to avoid re-generating cameraCallback
89-
const latestImageTimestamp = useRef(null)
88+
// Store the latest image message in a ref to avoid re-generating cameraCallback
89+
const latestImageMessage = useRef(null)
9090

9191
/**
9292
* Subscribe to the image topic.
9393
*/
9494
const cameraCallback = useCallback(
9595
(message) => {
96-
// console.log('Got camera message', message)
97-
if (!latestImageTimestamp.current || props.updateRateHz <= 0) {
98-
setLatestRenderedImg(message)
99-
} else {
100-
let currTime = message.header.stamp.sec + message.header.stamp.nanosec * 1e-9
101-
if (currTime - latestImageTimestamp.current >= 1.0 / props.updateRateHz) {
102-
setLatestRenderedImg(message)
103-
latestImageTimestamp.current = currTime
104-
}
105-
}
96+
latestImageMessage.current = message
10697
},
107-
[latestImageTimestamp, setLatestRenderedImg, props.updateRateHz]
98+
[latestImageMessage]
10899
)
100+
101+
/**
102+
* Create a timer to re-render the latest image every props.updateRateHz
103+
*/
104+
const [updateHzCurrentDate, setUpdateHzCurrentDate] = useState(new Date())
105+
useEffect(() => {
106+
setTimeout(() => {
107+
setUpdateHzCurrentDate(new Date())
108+
setLatestRenderedImg(latestImageMessage.current)
109+
}, 1000 / props.updateRateHz)
110+
}, [updateHzCurrentDate, setUpdateHzCurrentDate, props.updateRateHz, setLatestRenderedImg, latestImageMessage])
111+
/**
112+
* Create a timer to re-render the latest image every props.updateRateHz
113+
*/
114+
const [resubscribeRateCurrentDate, setResubscribeRateCurrentDate] = useState(new Date())
109115
useEffect(() => {
110116
console.log('subscribing to img topic')
111117
let topic = subscribeToROSTopic(ros.current, props.topic, 'sensor_msgs/CompressedImage', cameraCallback)
118+
setTimeout(() => {
119+
setResubscribeRateCurrentDate(new Date())
120+
}, 1000 / props.resubscribeRateHz)
112121
const cleanup = () => {
113122
console.log('unsubscribing from img topic')
114123
unsubscribeFromROSTopic(topic, cameraCallback)
@@ -123,7 +132,7 @@ const VideoFeed = (props) => {
123132
window.removeEventListener('beforeunload', cleanup)
124133
cleanup()
125134
}
126-
}, [cameraCallback, props.topic])
135+
}, [cameraCallback, props.topic, props.resubscribeRateHz, resubscribeRateCurrentDate, setResubscribeRateCurrentDate])
127136

128137
// Callback to resize the image based on the parent width and height
129138
const resizeImage = useCallback(() => {
@@ -192,18 +201,20 @@ const VideoFeed = (props) => {
192201

193202
// Render the component
194203
return (
195-
<img
196-
src={`data:image/jpeg;base64,${latestRenderedImg ? latestRenderedImg.data : ''}`}
197-
alt='Live video feed from the robot'
198-
style={{
199-
width: imgWidth,
200-
height: imgHeight,
201-
display: 'block',
202-
alignItems: 'center',
203-
justifyContent: 'center'
204-
}}
205-
onClick={props.pointClicked ? imageClicked : null}
206-
/>
204+
<>
205+
<img
206+
src={`data:image/jpeg;base64,${latestRenderedImg ? latestRenderedImg.data : ''}`}
207+
alt='Live video feed from the robot'
208+
style={{
209+
width: imgWidth,
210+
height: imgHeight,
211+
display: 'block',
212+
alignItems: 'center',
213+
justifyContent: 'center'
214+
}}
215+
onClick={props.pointClicked ? imageClicked : null}
216+
/>
217+
</>
207218
)
208219
}
209220
VideoFeed.propTypes = {
@@ -218,6 +229,8 @@ VideoFeed.propTypes = {
218229
topic: PropTypes.string.isRequired,
219230
// The rate at which to update the video feed, in Hz
220231
updateRateHz: PropTypes.number.isRequired,
232+
// The rate at which to resubscribe to the image topic
233+
resubscribeRateHz: PropTypes.number.isRequired,
221234
/**
222235
* An optional callback function for when the user clicks on the video feed.
223236
* This function should take in two parameters, `x` and `y`, which are the
@@ -228,7 +241,8 @@ VideoFeed.propTypes = {
228241
}
229242
VideoFeed.defaultProps = {
230243
topic: CAMERA_FEED_TOPIC,
231-
updateRateHz: 10
244+
updateRateHz: 3,
245+
resubscribeRateHz: 0.1
232246
}
233247

234248
export default VideoFeed

0 commit comments

Comments
 (0)