From 44f53217d46ab6247b752dde6c3a1f6ed3715ecb Mon Sep 17 00:00:00 2001 From: mg <2492465538@qq.com> Date: Mon, 19 Oct 2026 18:49:12 +0800 Subject: [PATCH] add mvs_driver srv files --- rm_msgs/CMakeLists.txt | 7 ++++ .../srv/mvs_driver/ExposureStatusSwitch.srv | 34 +++++++++++++++++++ rm_msgs/srv/mvs_driver/GetFrameRate.srv | 34 +++++++++++++++++++ 3 files changed, 75 insertions(+) create mode 100644 rm_msgs/srv/mvs_driver/ExposureStatusSwitch.srv create mode 100644 rm_msgs/srv/mvs_driver/GetFrameRate.srv diff --git a/rm_msgs/CMakeLists.txt b/rm_msgs/CMakeLists.txt index c263f315..005c704f 100755 --- a/rm_msgs/CMakeLists.txt +++ b/rm_msgs/CMakeLists.txt @@ -64,6 +64,13 @@ add_service_files( ShooterSpeed.srv ) +add_service_files( + DIRECTORY srv/mvs_driver + FILES + GetFrameRate.srv + ExposureStatusSwitch.srv +) + add_message_files( DIRECTORY msg/detection FILES diff --git a/rm_msgs/srv/mvs_driver/ExposureStatusSwitch.srv b/rm_msgs/srv/mvs_driver/ExposureStatusSwitch.srv new file mode 100644 index 00000000..8b0a6728 --- /dev/null +++ b/rm_msgs/srv/mvs_driver/ExposureStatusSwitch.srv @@ -0,0 +1,34 @@ +# Manual-exposure preset switch of one instance (see docs_ai/usage.md 5.10). +# +# Why a service and not dynamic_reconfigure: the windmill case has to switch the exposure of a +# running camera in one call, without every caller having to know the target value, and the switch +# has to survive a reconnect. The presets themselves stay in the yaml block of the instance +# (exposure_value / exposure_windmill_value), so a field site stays configurable per camera. +# All this service writes is ExposureTime - one field of ExposureParams per preset. ExposureAuto and +# the auto range stay as configured, so under exposure_auto=true the written value has no effect and +# the read-back in the response is what counts. +# +# Request: exactly one field, the preset to activate. +# NORMAL (0) = ExposureTime = exposure_value of the yaml block +# WINDMILL (1) = ExposureTime = exposure_windmill_value +# Extending the table is one yaml key plus one 'case' in MvsDriverNode::OnExposureStatusSwitch() plus +# one constant here: the field stays a single int32, so existing callers keep working. +# +# Contrary to get_frame_rate the request HAS a field, so 'rosservice call' needs it (the terminal +# client is what demands it - docs_ai/usage.md 5.1.1): +# rosservice call //exposure_status_switch "target: 1" +# +# The write runs on the device lock (CameraDevice::WithHandle()) and the response carries the value +# the camera really holds afterwards: the camera clamps out-of-range requests instead of failing +# them, so 'requested_us' alone would not tell what is in effect. Without an open camera the call +# still answers (success=false) instead of throwing or hanging, which is how a caller tells "preset +# applied" from "there is no camera". + +int32 target # preset to activate: NORMAL (0) or WINDMILL (1) +int32 NORMAL = 0 # ExposureTime = exposure_value of the yaml block +int32 WINDMILL = 1 # ExposureTime = exposure_windmill_value +--- +bool success # false = no camera handle (not open / not grabbing) or the write failed +string message # human readable status: preset name plus what the camera holds now +float64 requested_us # exposure (us) this call asked for (-1 = unknown target, nothing written) +float64 exposure_us # ExposureTime read back from the camera (-1 = no camera / unreadable) diff --git a/rm_msgs/srv/mvs_driver/GetFrameRate.srv b/rm_msgs/srv/mvs_driver/GetFrameRate.srv new file mode 100644 index 00000000..f4be48dd --- /dev/null +++ b/rm_msgs/srv/mvs_driver/GetFrameRate.srv @@ -0,0 +1,34 @@ +# Live frame-rate read-out of one instance (see docs_ai/usage.md 5.1). +# +# Why a service and not 'rostopic hz': hz averages over the whole subscription, so it needs seconds +# to converge and keeps reporting the old value for a while after a change, and it makes the caller +# deserialize every frame. This service reads counters the driver already keeps, so one call answers: +# fps = raw frames in the newest <= 0.3 s window (follows a change within ~0.2 s) +# fps_1s = raw frames of the last finished 1 Hz interval (the number in the 1 Hz log) +# fps_compressed_1s = compressed frames published in that same interval +# Calling it while nothing streams is a valid answer too (success=false / growing frame_age): that is +# how a stalled camera is told apart from a stalled subscriber. +# +# Request: empty. This service takes no arguments, so 'rosservice call //get_frame_rate' +# works as it is written: there is no 'count' to pass and nothing a client could leave unset. +# Besides answering, every call prints exactly one line with the same numbers to the node log / +# rosout, so one call leaves one line behind and ten calls leave ten ("one call = one line", see +# docs_ai/usage.md 5.1.1). That line names its instance in the text ('hk_camera: frame rate report ...'), +# which is what tells two instances of the same manager apart in a shared log (rosconsole only knows +# the manager process - docs_ai/known_issues.md D4). The call itself stays non-blocking: it reads only +# counters the driver already keeps and never touches the camera device (the one lock it can take is +# a microsecond-sized read of the compressed queue length). The line adds no thread, no timer tick and +# no lock either - it is printed from this very callback, from exactly the values answered below. + +--- +bool success # false = no frame at all since startup (camera not opened / not grabbing) +string message # human readable status, e.g. "no frame for 2.4s (stream stalled?)" +float64 fps # raw frames/s over the newest 'window' seconds +float64 window # length of that window in seconds (0 = time for one sample only) +float64 fps_1s # raw frames/s of the last finished 1 Hz interval +float64 fps_compressed_1s # image_raw/compressed frames/s of that same interval +float64 frame_age # seconds since the newest frame (-1 = no frame since startup) +uint64 frames # raw frames received since startup +uint32 queue # frames waiting for the JPEG worker right now +uint32 dropped_1s # compressed frames given up (queue full) in the last finished interval +uint32 skipped_1s # frames not compressed because of compress_fps, same interval