fix frame timestamps to use a comparable epoch
steady_clock's epoch is unspecified and typically counts from process start or boot, so the published timestamp_ns could not be compared against another node's timestamps, wall clock or a recording — and it recorded when the node processed the frame rather than when the camera captured it. Publish two keys on every output instead: device_timestamp_ns from sl::Camera::getTimestamp(TIME_REFERENCE::IMAGE), and host_timestamp_ns from system_clock. Both are Unix-epoch nanoseconds, set as dora timestamp parameters. The SDK clock source is pinned to SYSTEM_CLOCK at construction, since it is process-wide and decides the epoch of the device value. Both are kept because the wall clock can step when NTP synchronises after boot on a Jetson, while the device timestamp is what two nodes reading the same frame can agree on. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Y7g2cBJ5e3r15ZbJ9WZn8c
This commit is contained in:
+33
-17
@@ -38,6 +38,32 @@ rust::Vec<int64_t> make_vector_int(std::initializer_list<int64_t> values) {
|
||||
return out;
|
||||
}
|
||||
|
||||
void set_intrinsics(Metadata& metadata, const zed::Calibration& calib) {
|
||||
metadata.set_float("fx", calib.fx);
|
||||
metadata.set_float("fy", calib.fy);
|
||||
metadata.set_float("cx", calib.cx);
|
||||
metadata.set_float("cy", calib.cy);
|
||||
metadata.set_list_float("distortion", make_distortion(calib.distortion));
|
||||
}
|
||||
|
||||
// Both clocks are needed. The device timestamp is the instant the frame was
|
||||
// captured and is the only value two nodes reading the same frame can agree on.
|
||||
// The host timestamp is what the rest of the dataflow and the session recorder
|
||||
// share, and on a Jetson it can step when NTP synchronises after boot — which is
|
||||
// exactly why the device timestamp is recorded alongside it rather than instead
|
||||
// of it.
|
||||
void set_frame_stamps(Metadata& metadata, int64_t frame_id, int64_t device_ns, int64_t host_ns) {
|
||||
metadata.set_int("frame_id", frame_id);
|
||||
metadata.set_timestamp("device_timestamp_ns", device_ns);
|
||||
metadata.set_timestamp("host_timestamp_ns", host_ns);
|
||||
}
|
||||
|
||||
int64_t host_timestamp_ns() {
|
||||
return std::chrono::duration_cast<std::chrono::nanoseconds>(
|
||||
std::chrono::system_clock::now().time_since_epoch())
|
||||
.count();
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
int main() {
|
||||
@@ -80,11 +106,8 @@ int main() {
|
||||
int height = image_mat.getHeight();
|
||||
|
||||
int64_t current_frame_id = frame_id++;
|
||||
int64_t timestamp_ns = static_cast<int64_t>(
|
||||
std::chrono::duration_cast<std::chrono::nanoseconds>(
|
||||
std::chrono::steady_clock::now().time_since_epoch()
|
||||
).count()
|
||||
);
|
||||
int64_t device_ns = camera.device_timestamp_ns();
|
||||
int64_t host_ns = host_timestamp_ns();
|
||||
|
||||
// --- image_bgr ---
|
||||
cv::Mat image_rgba(height, width, CV_8UC4, image_mat.getPtr<sl::uchar1>());
|
||||
@@ -100,13 +123,8 @@ int main() {
|
||||
image_metadata->set_string("encoding", "bgr8");
|
||||
image_metadata->set_string("layout", "HWC");
|
||||
image_metadata->set_list_int("shape", make_shape(height, width, 3));
|
||||
image_metadata->set_float("fx", calib.fx);
|
||||
image_metadata->set_float("fy", calib.fy);
|
||||
image_metadata->set_float("cx", calib.cx);
|
||||
image_metadata->set_float("cy", calib.cy);
|
||||
image_metadata->set_list_float("distortion", make_distortion(calib.distortion));
|
||||
image_metadata->set_int("frame_id", current_frame_id);
|
||||
image_metadata->set_int("timestamp_ns", timestamp_ns);
|
||||
set_intrinsics(*image_metadata, calib);
|
||||
set_frame_stamps(*image_metadata, current_frame_id, device_ns, host_ns);
|
||||
|
||||
auto image_result = send_output_with_metadata(
|
||||
dora_node.send_output, "image_bgr", image_slice, std::move(image_metadata));
|
||||
@@ -125,11 +143,8 @@ int main() {
|
||||
pc_metadata->set_string("dtype", "float32");
|
||||
pc_metadata->set_string("channels", "XYZRGBA");
|
||||
pc_metadata->set_string("units", "mm");
|
||||
pc_metadata->set_float("fx", calib.fx);
|
||||
pc_metadata->set_float("fy", calib.fy);
|
||||
pc_metadata->set_float("cx", calib.cx);
|
||||
pc_metadata->set_float("cy", calib.cy);
|
||||
pc_metadata->set_list_float("distortion", make_distortion(calib.distortion));
|
||||
set_intrinsics(*pc_metadata, calib);
|
||||
set_frame_stamps(*pc_metadata, current_frame_id, device_ns, host_ns);
|
||||
|
||||
if (pc_mode == PcMode::HALF) {
|
||||
int hw = pc_width / 2, hh = pc_height / 2;
|
||||
@@ -171,6 +186,7 @@ int main() {
|
||||
cam_metadata->set_string("layout", "C");
|
||||
cam_metadata->set_list_int("shape", make_vector_int({4}));
|
||||
cam_metadata->set_list_float("distortion", make_distortion(calib.distortion));
|
||||
set_frame_stamps(*cam_metadata, current_frame_id, device_ns, host_ns);
|
||||
|
||||
auto cam_result = send_output_with_metadata(
|
||||
dora_node.send_output, "camera_info", cam_slice, std::move(cam_metadata));
|
||||
|
||||
@@ -71,6 +71,11 @@ Config Config::from_env() {
|
||||
}
|
||||
|
||||
Camera::Camera(const Config& config) : config_(config) {
|
||||
// Process-wide, and must be set before any camera is opened. Without it the
|
||||
// epoch of the timestamps published alongside every frame depends on the SDK
|
||||
// default rather than on anything this node states.
|
||||
sl::setTimestampClock(sl::TIMESTAMP_CLOCK::SYSTEM_CLOCK);
|
||||
|
||||
init_params_.camera_resolution = parse_resolution(config_.resolution);
|
||||
init_params_.camera_fps = config_.fps;
|
||||
init_params_.depth_mode = parse_depth_mode(config_.depth_mode);
|
||||
@@ -135,6 +140,11 @@ Calibration Camera::calibration() const {
|
||||
return result;
|
||||
}
|
||||
|
||||
int64_t Camera::device_timestamp_ns() {
|
||||
return static_cast<int64_t>(
|
||||
zed_.getTimestamp(sl::TIME_REFERENCE::IMAGE).getNanoseconds());
|
||||
}
|
||||
|
||||
sl::Mat& Camera::image() {
|
||||
return image_mat_;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <sl/Camera.hpp>
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
@@ -35,6 +36,7 @@ public:
|
||||
void warmup();
|
||||
bool grab();
|
||||
Calibration calibration() const;
|
||||
int64_t device_timestamp_ns();
|
||||
sl::Mat& image();
|
||||
sl::Mat& point_cloud();
|
||||
sl::Camera& handle();
|
||||
|
||||
Reference in New Issue
Block a user