Skip to content
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

Global Camera Time #3909

Merged
merged 21 commits into from
May 16, 2019
Merged

Global Camera Time #3909

merged 21 commits into from
May 16, 2019

Conversation

doronhi
Copy link
Contributor

@doronhi doronhi commented May 5, 2019

For synchronization of several cameras on the same machine a common timestamp for all streams is needed.
This PR periodically compares the device time and the computer time to calculate a linear equation describing the connection between them. Then it applies the function to every frame in every stream.
As an additional by-product, it handles the 32 bytes issue of time stamp being reset every hour or so.
The function set the timestamp domain to "RS2_TIMESTAMP_DOMAIN_GLOBAL_TIME" as defined in rs_frame.h
If the metadata is not available the global timestamp is not invoked - timestamp domain remains RS2_TIMESTAMP_DOMAIN_SYSTEM_TIME.
The PR requires the implementation of a get_device_time() function to work - currently implemented for D400 series and L500 camera only.
Tracked on: RS-3975

dorodnic and others added 13 commits May 5, 2019 14:51
in realsense_metadata_win10.ps1 fixed D435i pid from 0B18 to 0B3A
add timestamp domain: RS2_TIMESTAMP_DOMAIN_HARDWARE_SYSTEM
add function to device: get_device_time()
ds5-device use global_timestamp_reader above ds5_timestamp_reader_from_metadata
rs-data-collect - check file writability before start collecting.
Add std check to avoid adding big time gaps.
…in global_timestamp_reader.

l500 uses global_timestamp_reader.
l500_timestamp_reader_from_metadata - fix time resolution.
…_DOMAIN_GLOBAL_time

re-implement get_device_time()
…ing filter, calculate linear equation between firmware time and system time.
remove loop handling from l500_timestamp_reader_from_metadata::get_frame_timestamp. Handled in global_timestamp_reader.
fix TIMESTAMP_USEC_TO_MSEC declaration.
@dorodnic dorodnic changed the base branch from master to development May 5, 2019 18:58
@dorodnic dorodnic changed the title Hwsystime Global Camera Time May 5, 2019
Copy link
Contributor

@bfulkers-i bfulkers-i left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The points I'd like to see clarified are:

  • What is the expected accuracy?
  • How is the latency of the device response / USB taken into account?
  • What happens when timestamps wrap?

To see how T265 deals with this same issue, look at https://github.com/IntelRealSense/librealsense/blob/master/third-party/libtm/libtm/src/Device.cpp#L230. The basic idea is to regularly query the device for its current time and measure both the response and the round trip time of the request to account for latency. See https://en.wikipedia.org/wiki/Network_Time_Protocol#Clock_synchronization_algorithm for a relevant figure.

LOG_DEBUG("time_diff_keeper::update_diff_time - in");
std::lock_guard<std::recursive_mutex> lock(_mtx);
LOG_DEBUG("time_diff_keeper::update_diff_time - lock");
double system_time = static_cast<double>(duration_cast<nanoseconds>(system_clock::now().time_since_epoch()).count()) * TIMESTAMP_USEC_TO_MSEC * TIMESTAMP_USEC_TO_MSEC;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be a std::chrono conversion <double, std::chrono::milliseconds>

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

by casting nanoseconds to milliseconds I get better accuracy. Or so it seems.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My mistake, what you likely want is duration<double, std::milli>, notice the difference between this and std::chrono::milliseconds which is duration</*signed integer type of at least 45 bits*/, std::milli>. In the latter case you get integer milliseconds, which is why you feel you are getting better accuracy by not using that.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks. Both for the note regarding the round-trip delay and for the system time reading method.
I updated accordingly.

bool time_diff_keeper::update_diff_time()
{
using namespace std::chrono;
const static double diffThresh = 500;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unused?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you, indeed unused.

{
// A time loop happend:
LOG_DEBUG("time_diff_keeper::call reset()");
_coefs.reset();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is the expected behavior when the timestamps wrap?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When timestamp wraps, the time samples for calculating the equation for firmware time to system time are erased. Coefficients a=1, b=0 are used for the next 100 milliseconds, until some samples accumulate again. The assumption is that in that time, the firmware time and system time will not diverge.

@@ -99,6 +99,14 @@ rs2_timestamp_domain rs2_get_frame_timestamp_domain(const rs2_frame* frameset, r
*/
rs2_time_t rs2_get_frame_timestamp(const rs2_frame* frame, rs2_error** error);

/**
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Split and resubmit as a separate PR

txtTimeStamp.Text = String.Format("{0,-20:0.00}", depthFrame.Timestamp) + "(" + depthFrame.TimestampDomain.ToString() + ")";
Dispatcher.Invoke(new Action(() =>
{
String color_dev_sn = new Sensor.CameraInfos(depthFrame.Sensor)[CameraInfo.SerialNumber];
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rename the var: colordepth_dev_sn

@dorodnic dorodnic mentioned this pull request May 8, 2019
Copy link
Collaborator

@ev-mp ev-mp left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looking good

@ev-mp ev-mp merged commit 1fd3144 into IntelRealSense:development May 16, 2019
@freemanlo
Copy link
Contributor

Do we have more detailed info in the official documentation?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants