CSCore failing to set manual USB camera exposure

For the past day or two, any attempts to set the manual exposure for a USB camera using cscore has resulted in the error CS: ERROR: ioctl VIDIOC_S_EXT_CTRLS failed at UsbCameraProperty.cpp:67: Invalid argument (UsbUtil.cpp:156) and the exposure not getting updated. By default the camera is stuck in “auto exposure” mode, and ends up streaming at 7.5 fps, sometimes 15 if it is in the correct lighting conditions (it should be at 30).
Context:

  • Using wpilibpi w/ wpilib v2023.4.1 on a raspberry pi 4
  • Camera: Lifecam hd3000
  • This is a recent development; changing the exposure was working flawlessly before this error started occurring

What I have tried (nothing has worked):

  • Change the default exposure in the web dashboard for the camera
  • Change resolution and fps in the web dashboard for the camera
  • Plug the camera into a different USB port
  • Try the default ‘multiCameraServer’ program instead of our vision application

I have not tried reimaging yet, but can if absolutely necessary. Also, I briefly remember running a sudo apt update to install some debugging tools sometime before the errors started occurring, but did not run into the error for at least a day afterward simply because I didn’t retest the code during that time. I have been trying to figure out how to view the update history but have gotten nowhere. Could it be that the camera driver or some other dependency was updated and is now incompatible with cscore? If this was the case, I’m assuming a reimage would be necessary.

Here are some sample outputs:
(our program)


(default streaming)

Here is the line that sets the exposure:

cs::SetCameraExposureManual(ctx.camera_h, _global.nt.exposure.Get(), &status);

Here is the full program source: 2023-Charged-Up/chargedup.cpp at dev-samr-super-vision · FRC3407/2023-Charged-Up · GitHub

Thanks in advance for any help!

Does it work to set the exposure settings interactively on the stream server web page? E.g. set exposure to manual mode, and then move the manual mode slider?

The exact V4L2 property names for camera exposure seem to have changed over recent Linux kernel versions, and the SetExposureManual() function assumes certain names, so it’s relatively fragile right now. v4l2-ctl -D 0 --list-ctrls (or something similar to that) should list all the camera property names. You can use these names with GetProperty() to set specific properties like you can on the web page.

What USB camera is this?

Setting the exposure manually on the stream web page also failed and produced the same output, except for half of the time when setting the raw exposure to 0 would work.

It is a Microsoft Lifecam HD3000 - here is the control mode list from the command you gave:

User Controls

                     brightness 0x00980900 (int)    : min=30 max=255 step=1 default=133 value=142
                       contrast 0x00980901 (int)    : min=0 max=10 step=1 default=5 value=4
                     saturation 0x00980902 (int)    : min=0 max=200 step=1 default=83 value=82
        white_balance_automatic 0x0098090c (bool)   : default=1 value=1
           power_line_frequency 0x00980918 (menu)   : min=0 max=2 default=2 value=2
      white_balance_temperature 0x0098091a (int)    : min=2800 max=10000 step=1 default=4500 value=4000 flags=inactive
                      sharpness 0x0098091b (int)    : min=0 max=50 step=1 default=25 value=23
         backlight_compensation 0x0098091c (int)    : min=0 max=10 step=1 default=0 value=0

Camera Controls

                  auto_exposure 0x009a0901 (menu)   : min=0 max=3 default=1 value=1
         exposure_time_absolute 0x009a0902 (int)    : min=5 max=20000 step=1 default=156 value=604
                   pan_absolute 0x009a0908 (int)    : min=-201600 max=201600 step=3600 default=0 value=-18000
                  tilt_absolute 0x009a0909 (int)    : min=-201600 max=201600 step=3600 default=0 value=-72000
                  zoom_absolute 0x009a090d (int)    : min=0 max=10 step=1 default=0 value=0

I wouldn’t know if any of them have changed, but I can try implementing the direct property modification and see if that works. As a side note, I always wondered how the stream gui had so many options while the api didn’t mention hardly any of them - I guess now I know.

Yep, those names are not what the code assumes for those properties. The code assumes exposure_auto and exposure_absolute (instead of auto_exposure and exposure_time_absolute). Linux changed the names at some point relatively recently. Note for setting exposure_time_absolute you’ll want to implement this scaling function to go from the 0-100 range to the exact values required by the LifeCam (or just use one of the exact values, since you’re setting a fixed value anyway): allwpilib/UsbCameraImpl.cpp at main · wpilibsuite/allwpilib · GitHub
(the weird LifeCam exposure range is why setting the exposure through the web gui doesn’t work… and why we provide a dedicated function for it)

1 Like

Ok I swapped in these lines

cs::SetProperty(cs::GetSourceProperty(ctx.camera_h, "auto_exposure", &status), 1, &status);
cs::SetProperty(cs::GetSourceProperty(ctx.camera_h, "exposure_time_absolute", &status), _global.nt.exposure.Get(), &status);

but it is still stuck in auto exposure mode unless the value being set is 0 (then it sets to a very low exposure). No error outputs except for at initialization where I presume other parameters that also had their id names changed are failing.

I tried manually sending values from the lookup table (5, 20, 156, etc.), but nothing happened. This is the same behavior I was seeing when setting from the web gui.

You need to set auto_exposure to 0 to get manual exposure control via exposure_time_absolute. Setting it to 1 is enabling auto exposure, disabling manual exposure control. You can confirm the menu values with v4l2-ctl, but I’m near-certain setting it to 0 is what you need to do.
1 is correct.

In the source code (UsbCameraImpl.cpp:1493), it is being set to 1 before manual setting, and I tried setting it to 0 and it spit out the same “invalid property” error.

…I was about to ask how to confirm the menu values but I figured it out:

User Controls

                     brightness 0x00980900 (int)    : min=30 max=255 step=1 default=133 value=142
                       contrast 0x00980901 (int)    : min=0 max=10 step=1 default=5 value=4
                     saturation 0x00980902 (int)    : min=0 max=200 step=1 default=83 value=82
        white_balance_automatic 0x0098090c (bool)   : default=1 value=1
           power_line_frequency 0x00980918 (menu)   : min=0 max=2 default=2 value=2
                                0: Disabled
                                1: 50 Hz
                                2: 60 Hz
      white_balance_temperature 0x0098091a (int)    : min=2800 max=10000 step=1 default=4500 value=4000 flags=inactive
                      sharpness 0x0098091b (int)    : min=0 max=50 step=1 default=25 value=23
         backlight_compensation 0x0098091c (int)    : min=0 max=10 step=1 default=0 value=0

Camera Controls

                  auto_exposure 0x009a0901 (menu)   : min=0 max=3 default=1 value=1
                                1: Manual Mode
                                3: Aperture Priority Mode
         exposure_time_absolute 0x009a0902 (int)    : min=5 max=20000 step=1 default=156 value=5
                   pan_absolute 0x009a0908 (int)    : min=-201600 max=201600 step=3600 default=0 value=-18000
                  tilt_absolute 0x009a0909 (int)    : min=-201600 max=201600 step=3600 default=0 value=-72000
                  zoom_absolute 0x009a090d (int)    : min=0 max=10 step=1 default=0 value=0

It seems that 1 should be the correct value?

Yep, you’re right! It should be 1.

If that’s not working… the issue might well be the camera.

:grimacing:
Oh well I guess I can always reinstall if I feel the need