-
Notifications
You must be signed in to change notification settings - Fork 4.8k
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
set_devices_changed_callback seems to trigger inconstantly after hardware_reset #9287
Comments
Hi @stfuchs The hardware_reset() scripts on this GitHub support forum are typically suited for single-camera projects. A RealSense user called Westa contributed a C++ multiple-camera hardware reset script that makes use of callbacks to iterate through all attached cameras. Westa stated that "it explains how the realsense context works - and how to iterate over all the current devices. It also shows a mechanism for resetting a found Intel device - and a mechanism to wait for the hardware to finishing resetting before continuing". I have posted the full C++ script below. Would it be possible to adapt this script for your callback-equipped project to test whether it makes a positive difference, please? Thanks!
|
Hi Marty, thanks for getting back to me so quickly. Unfortunately I can't access your link to the Intel Community. It keeps asking me to register even though I already did and even confirmed my email address. The example you posted is almost the same as mine, except that it actually only resets the first camera it finds and stops there: if (gotDev == 0 && (devName == "Intel RealSense D415" || devName == "Intel RealSense D435"))
{
devFirmware = dev.get_info(RS2_CAMERA_INFO_FIRMWARE_VERSION);
// assume there is only one intel camera for now
// save the device for future use
rs2Dev = dev;
gotDev = 1;
} It even says it in the comment. |
The link just goes to a comment with the same script, so don't worry. The reason for pasting the script here was that links to that different forum do not always work. My personal interpretation of the script is that it is not saying that it only detects one camera, but is establishing that there is at least one camera connected. It sets gotdev to '1' to acknowledge this. If gotdev = 0 then the message "No Intel Realsense devices detected" is printed. |
Maybe I'm missing something but the way I understand this part: for (auto&& dev : rs2Ctx.query_devices()) // Query the list of connected RealSense devices
{
std::string devName = "";
std::string devSerialNumber = "";
std::string devFirmware = "";
std::string devProdId = "";
devProdId = dev.get_info(RS2_CAMERA_INFO_PRODUCT_ID);
devSerialNumber = dev.get_info(RS2_CAMERA_INFO_SERIAL_NUMBER);
devName = dev.get_info(RS2_CAMERA_INFO_NAME);
if (gotDev == 0 && (devName == "Intel RealSense D415" || devName == "Intel RealSense D435"))
{
devFirmware = dev.get_info(RS2_CAMERA_INFO_FIRMWARE_VERSION);
// assume there is only one intel camera for now
// save the device for future use
rs2Dev = dev;
gotDev = 1;
}
std::cout << "System Dev: " << devName << " Ser: " << devSerialNumber << " Firmware: " << devFirmware << " ProdID " << devProdId << std::endl;
} It uses the context to iterate over all available devices. Then if Then the device loop is done it moves to the next part: ////////////////////////////////////////////////////////////////
// if we have found a realsense sensor - force initialise it if required
if (gotDev == 1)
{
// reset the hardware device found during initial iteration thru context
rs2Dev.hardware_reset();
// wait for hardware to reset reset
resetCompleteIntelRealsense = 0;
int rs2WaitForReset = 1;
// pause until device is reset - not elegant but will do for testing
while (resetCompleteIntelRealsense == 0 && rs2WaitForReset < 9999999999)
{
rs2WaitForReset++;
}
} where it resets the previously sorted device if it was found. The last while loop blocks execution until either the callback from |
To be fair, the original formatting doesn't really help, so here is it with fixed indentation: // define a realsense context
std::cout << "Initialising realsense context" << std::endl;
rs2::context rs2Ctx;
rs2::device rs2Dev;
resettingIntelRealsense = 0;
resetCompleteIntelRealsense = 0;
int gotDev = 0;
// Define a callback mechanism - to detect when the sensor has been reset
rs2Ctx.set_devices_changed_callback(
[&](rs2::event_information& info)
{
// loop thru all new devices - that is one that has been reset effectively
for (auto&& dev : info.get_new_devices())
{
std::string devName = "";
std::string devSerialNumber = "";
std::string devFirmware = "";
std::string devProdId = "";
devProdId = dev.get_info(RS2_CAMERA_INFO_PRODUCT_ID);
devSerialNumber = dev.get_info(RS2_CAMERA_INFO_SERIAL_NUMBER);
devName = dev.get_info(RS2_CAMERA_INFO_NAME);
if (devName == "Intel RealSense D415")
{
devFirmware = dev.get_info(RS2_CAMERA_INFO_FIRMWARE_VERSION);
}
if (devName == "Intel RealSense D435")
{
devFirmware = dev.get_info(RS2_CAMERA_INFO_FIRMWARE_VERSION);
}
std::cout << "RESET Dev: " << devName << " Ser: " << devSerialNumber << " Firmware: " << devFirmware << " ProdID " << devProdId << std::endl;
resetCompleteIntelRealsense = 1;
}
});
// interate thru the intel device context looking for intel sensors
// note that other devices like webcams can appear here too depending on their device type
for (auto&& dev : rs2Ctx.query_devices()) // Query the list of connected RealSense devices
{
std::string devName = "";
std::string devSerialNumber = "";
std::string devFirmware = "";
std::string devProdId = "";
devProdId = dev.get_info(RS2_CAMERA_INFO_PRODUCT_ID);
devSerialNumber = dev.get_info(RS2_CAMERA_INFO_SERIAL_NUMBER);
devName = dev.get_info(RS2_CAMERA_INFO_NAME);
if (gotDev == 0 && (devName == "Intel RealSense D415" || devName == "Intel RealSense D435"))
{
devFirmware = dev.get_info(RS2_CAMERA_INFO_FIRMWARE_VERSION);
// assume there is only one intel camera for now
// save the device for future use
rs2Dev = dev;
gotDev = 1;
}
std::cout << "System Dev: " << devName << " Ser: " << devSerialNumber << " Firmware: " << devFirmware << " ProdID " << devProdId << std::endl;
}
////////////////////////////////////////////////////////////////
// if we have found a realsense sensor - force initialise it if required
if (gotDev == 1)
{
// reset the hardware device found during initial iteration thru context
rs2Dev.hardware_reset();
// wait for hardware to reset reset
resetCompleteIntelRealsense = 0;
int rs2WaitForReset = 1;
// pause until device is reset - not elegant but will do for testing
while (resetCompleteIntelRealsense == 0 && rs2WaitForReset < 9999999999)
{
rs2WaitForReset++;
}
}
if (gotDev == 0)
{
std::cout << "No Intel Realsense devices detected" << std::endl;
} |
I'm reminded of a C++ case where a RealSense user tried to use callback to access multiple cameras to capture an image from every camera simultaneously but could only access one camera at a time, looping through the cameras. The solution they arrived at was to instead create multiple threads. Note that if you try the above script, it is looking for D415 cameras and so you should edit the script to look for D435, as that is the model that you have. |
@MartyG-RealSense thanks for the links. I looked through all the comments but I don't think my problem has to do with threading. In fact I don't even think it has to do with my multi cam setup. I disconnect all other cameras and change the test to this: int main(int argc, char** argv)
{
rs2::context ctx;
bool reconnected = false;
ctx.set_devices_changed_callback(
[&reconnected](rs2::event_information& info) {
std::cout << "Device change triggered!" << std::endl;
for (auto&& dev_new : info.get_new_devices())
{
std::string new_id = dev_new.get_info(RS2_CAMERA_INFO_SERIAL_NUMBER);
std::cout << "Device connected: " << new_id << std::endl;
reconnected = true;
}
});
rs2::device_list device_list = ctx.query_devices();
std::cout << "Devices found: " << device_list.size() << std::endl;
rs2::device device = device_list.front();
std::cout << "Before hardware_reset" << std::endl;
device.hardware_reset();
std::cout << "After hardware_reset" << std::endl;
auto wait_until = std::chrono::system_clock::now() + std::chrono::seconds(30);
while (std::chrono::system_clock::now() < wait_until)
{
std::this_thread::sleep_for(std::chrono::milliseconds(100));
if (reconnected)
{
std::cout << "Reset complete" << std::endl;
break;
}
}
if (!reconnected)
{
std::cout << "Reached timeout instead of callback" << std::endl;
}
} Only on the first time I run it the callback was triggered. Here is the output of the script running it 5 times in a row:
|
I started looking into the source code a bit. My understanding so far is that the responsible function, that calls my callback, actively polls for changed devices and does that only every 5 seconds or so: https://github.com/IntelRealSense/librealsense/blob/master/src/types.h#L1595-L1612 Based on the dmesg output it seems as if the reset completes within 3 seconds on my machine. So I guess the disconnect just slips through the polling interval most of the time. Is that accurate? Oddly enough I tried calling rs2::device device = device_list.front();
std::cout << "Before hardware_reset" << std::endl;
device.hardware_reset();
std::cout << "After hardware_reset" << std::endl;
auto wait_until = std::chrono::system_clock::now() + std::chrono::seconds(30);
while (std::chrono::system_clock::now() < wait_until)
{
std::cout << "Devices connected: " << ctx.query_devices().size() << std::endl;
if (reconnected)
{
std::cout << "Reset complete" << std::endl;
break;
}
std::this_thread::sleep_for(std::chrono::milliseconds(5));
} but the device list did not change at all. |
That is indeed my understanding that devices are checked for changes every 5 seconds, as per the advice in #6921 (comment) about editing the time period in files.h to reduce this timer. Some advice on improving hardware reset is also given in the comment linked to below and the comments below it. |
Hi @stfuchs Do you have an update about this case that you can provide, please? Thanks! |
I simply came to the conclusion that |
Thanks very much @stfuchs for your feedback. I do not have advice to offer on that subject. As you developed a solution for your particular project, I will close the case. Thanks again! |
Issue Description
I have a similar issue as #6921 with the main difference that I'm on linux instead of win10.
I am trying to add
hardware_reset
to the start of my program and wanted to use theset_devices_changed_callback
to receive feedback when a camera is available again. My test setup consists of 3x D435 cameras connected via usb hub. The issue that I'm seeing is that the registered callback gets called only occasionally if I try to reset all 3 cameras.Here is an example to reproduce this:
This is the output when I run it (first number in [] is the timestamp, second is the serial number):
And here are the dmesg logs for that time:
I'm built librealsense 2.47 from source with the following flags:
UDEV and kernel patch are installed via debian packages:
From the example output above you can see that the callback gets triggered only once. For that camera the kernel log also shows an actual disconnect event. Note that it's not always the same camera. Sometimes one of other cameras triggers the callback, sometimes none of them trigger at all, and very few times more than one camera triggered the callback.
So my questions are:
device_list
provided byrs2::context::query_devices()
become invalid once I callrs2::device::hardware_reset()
?hardware_reset
successful even if no callback was triggered and noUSB disconnect
kernel event happened? So is falling back on a timeout reasonable?The text was updated successfully, but these errors were encountered: