mirror of
https://github.com/orbbec/OrbbecSDK_ROS2.git
synced 2026-10-07 21:37:46 +08:00
Merge branch 'merge/sdk_2.8.6' into v2-main
This commit is contained in:
@@ -0,0 +1,536 @@
|
||||
#include "orbbec_camera/frame_timestamp_csv_logger.h"
|
||||
|
||||
#include <chrono>
|
||||
#include <filesystem>
|
||||
#include <iomanip>
|
||||
#include <sstream>
|
||||
#include <utility>
|
||||
|
||||
namespace orbbec_camera {
|
||||
namespace {
|
||||
|
||||
constexpr size_t kCompletedQueueSoftLimit = 1000;
|
||||
constexpr size_t kFlushBatchSize = 100;
|
||||
constexpr auto kFlushInterval = std::chrono::seconds(1);
|
||||
|
||||
} // namespace
|
||||
|
||||
FrameTimestampCsvLogger::FrameTimestampCsvLogger(bool enabled, const std::string &csv_file_path,
|
||||
rclcpp::Logger logger)
|
||||
: logger_(std::move(logger)), enabled_(enabled), csv_file_path_(csv_file_path) {
|
||||
if (!enabled_) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
auto path = std::filesystem::path(csv_file_path_);
|
||||
if (path.has_parent_path() && !std::filesystem::exists(path.parent_path())) {
|
||||
std::filesystem::create_directories(path.parent_path());
|
||||
}
|
||||
} catch (const std::exception &e) {
|
||||
RCLCPP_ERROR_STREAM(logger_, "Failed to prepare frame timestamp CSV path " << csv_file_path_
|
||||
<< ": " << e.what());
|
||||
enabled_ = false;
|
||||
writer_failed_ = true;
|
||||
return;
|
||||
}
|
||||
|
||||
openCsvIfNeeded();
|
||||
if (!enabled_) {
|
||||
return;
|
||||
}
|
||||
|
||||
writer_thread_ = std::thread([this]() { writerThreadMain(); });
|
||||
}
|
||||
|
||||
FrameTimestampCsvLogger::~FrameTimestampCsvLogger() noexcept { shutdown(); }
|
||||
|
||||
void FrameTimestampCsvLogger::recordFrameSet(const std::shared_ptr<ob::Frame> &color_frame,
|
||||
const std::shared_ptr<ob::Frame> &depth_frame,
|
||||
int64_t arrival_system_us, int64_t arrival_steady_us,
|
||||
bool track_color, bool track_depth,
|
||||
bool color_image_publish_expected,
|
||||
bool depth_image_publish_expected) {
|
||||
if (!enabled_ || writer_failed_) {
|
||||
return;
|
||||
}
|
||||
recordFrameSetInternal(color_frame, depth_frame, arrival_system_us, arrival_steady_us,
|
||||
track_color, track_depth, color_image_publish_expected,
|
||||
depth_image_publish_expected);
|
||||
}
|
||||
|
||||
void FrameTimestampCsvLogger::recordStandaloneFrameArrival(OBStreamType stream_type,
|
||||
const std::shared_ptr<ob::Frame> &frame,
|
||||
int64_t arrival_system_us,
|
||||
int64_t arrival_steady_us,
|
||||
bool image_publish_expected) {
|
||||
if (!enabled_ || writer_failed_ || !frame || !isTrackedStream(stream_type)) {
|
||||
return;
|
||||
}
|
||||
recordStandaloneFrameArrivalInternal(stream_type, frame, arrival_system_us, arrival_steady_us,
|
||||
image_publish_expected);
|
||||
}
|
||||
|
||||
void FrameTimestampCsvLogger::recordPreImagePublish(OBStreamType stream_type,
|
||||
const std::shared_ptr<ob::Frame> &frame,
|
||||
int64_t publish_system_us,
|
||||
int64_t publish_steady_us) {
|
||||
if (!enabled_ || writer_failed_ || !frame || !isTrackedStream(stream_type)) {
|
||||
return;
|
||||
}
|
||||
recordPreImagePublishInternal(stream_type, frame, publish_system_us, publish_steady_us);
|
||||
}
|
||||
|
||||
void FrameTimestampCsvLogger::shutdown() {
|
||||
if (!enabled_) {
|
||||
return;
|
||||
}
|
||||
|
||||
{
|
||||
std::lock_guard<std::mutex> state_lock(state_mutex_);
|
||||
if (shutdown_requested_) {
|
||||
return;
|
||||
}
|
||||
shutdown_requested_ = true;
|
||||
|
||||
std::vector<PendingRow> rows_to_flush;
|
||||
flushPendingRowsLocked(rows_to_flush);
|
||||
for (const auto &row : rows_to_flush) {
|
||||
enqueueCompletedRow(row);
|
||||
}
|
||||
}
|
||||
|
||||
completed_rows_cv_.notify_all();
|
||||
if (writer_thread_.joinable()) {
|
||||
writer_thread_.join();
|
||||
}
|
||||
|
||||
if (csv_stream_.is_open()) {
|
||||
csv_stream_.flush();
|
||||
csv_stream_.close();
|
||||
}
|
||||
}
|
||||
|
||||
FrameTimestampCsvLogger::TrackedStream FrameTimestampCsvLogger::toTrackedStream(
|
||||
OBStreamType stream_type) const {
|
||||
if (stream_type == OB_STREAM_COLOR) {
|
||||
return TrackedStream::COLOR;
|
||||
}
|
||||
return TrackedStream::DEPTH;
|
||||
}
|
||||
|
||||
bool FrameTimestampCsvLogger::isTrackedStream(OBStreamType stream_type) const {
|
||||
return stream_type == OB_STREAM_COLOR || stream_type == OB_STREAM_DEPTH;
|
||||
}
|
||||
|
||||
void FrameTimestampCsvLogger::recordFrameSetInternal(
|
||||
const std::shared_ptr<ob::Frame> &color_frame, const std::shared_ptr<ob::Frame> &depth_frame,
|
||||
int64_t arrival_system_us, int64_t arrival_steady_us, bool track_color, bool track_depth,
|
||||
bool color_image_publish_expected, bool depth_image_publish_expected) {
|
||||
if (!track_color && !track_depth) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::vector<PendingRow> ready_rows;
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(state_mutex_);
|
||||
if (shutdown_requested_) {
|
||||
return;
|
||||
}
|
||||
|
||||
PendingRow row;
|
||||
row.row_id = next_row_id_++;
|
||||
|
||||
if (track_color && color_frame) {
|
||||
populateArrivalData(row.color, TrackedStream::COLOR, color_frame, arrival_system_us,
|
||||
arrival_steady_us, color_image_publish_expected);
|
||||
color_frame_index_to_row_id_[row.color.frame_index] = row.row_id;
|
||||
if (!color_image_publish_expected) {
|
||||
finalizeStreamWithoutPublish(row.color);
|
||||
}
|
||||
} else {
|
||||
row.color.final = true;
|
||||
}
|
||||
|
||||
if (track_depth && depth_frame) {
|
||||
populateArrivalData(row.depth, TrackedStream::DEPTH, depth_frame, arrival_system_us,
|
||||
arrival_steady_us, depth_image_publish_expected);
|
||||
depth_frame_index_to_row_id_[row.depth.frame_index] = row.row_id;
|
||||
if (!depth_image_publish_expected) {
|
||||
finalizeStreamWithoutPublish(row.depth);
|
||||
}
|
||||
} else {
|
||||
row.depth.final = true;
|
||||
}
|
||||
|
||||
pending_rows_.emplace(row.row_id, row);
|
||||
if (isRowReady(row)) {
|
||||
auto it = pending_rows_.find(row.row_id);
|
||||
if (it != pending_rows_.end()) {
|
||||
ready_rows.push_back(it->second);
|
||||
eraseFrameIndexMappingLocked(it->second);
|
||||
pending_rows_.erase(it);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (const auto &ready_row : ready_rows) {
|
||||
enqueueCompletedRow(ready_row);
|
||||
}
|
||||
}
|
||||
|
||||
void FrameTimestampCsvLogger::recordStandaloneFrameArrivalInternal(
|
||||
OBStreamType stream_type, const std::shared_ptr<ob::Frame> &frame, int64_t arrival_system_us,
|
||||
int64_t arrival_steady_us, bool image_publish_expected) {
|
||||
std::optional<PendingRow> ready_row;
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(state_mutex_);
|
||||
if (shutdown_requested_) {
|
||||
return;
|
||||
}
|
||||
|
||||
PendingRow row;
|
||||
row.row_id = next_row_id_++;
|
||||
|
||||
const auto tracked_stream = toTrackedStream(stream_type);
|
||||
auto &state = tracked_stream == TrackedStream::COLOR ? row.color : row.depth;
|
||||
auto &other_state = tracked_stream == TrackedStream::COLOR ? row.depth : row.color;
|
||||
|
||||
populateArrivalData(state, tracked_stream, frame, arrival_system_us, arrival_steady_us,
|
||||
image_publish_expected);
|
||||
other_state.final = true;
|
||||
|
||||
if (tracked_stream == TrackedStream::COLOR) {
|
||||
color_frame_index_to_row_id_[state.frame_index] = row.row_id;
|
||||
} else {
|
||||
depth_frame_index_to_row_id_[state.frame_index] = row.row_id;
|
||||
}
|
||||
|
||||
if (!image_publish_expected) {
|
||||
finalizeStreamWithoutPublish(state);
|
||||
}
|
||||
|
||||
pending_rows_.emplace(row.row_id, row);
|
||||
if (isRowReady(row)) {
|
||||
auto it = pending_rows_.find(row.row_id);
|
||||
if (it != pending_rows_.end()) {
|
||||
ready_row = it->second;
|
||||
eraseFrameIndexMappingLocked(*ready_row);
|
||||
pending_rows_.erase(it);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (ready_row.has_value()) {
|
||||
enqueueCompletedRow(*ready_row);
|
||||
}
|
||||
}
|
||||
|
||||
void FrameTimestampCsvLogger::recordPreImagePublishInternal(OBStreamType stream_type,
|
||||
const std::shared_ptr<ob::Frame> &frame,
|
||||
int64_t publish_system_us,
|
||||
int64_t publish_steady_us) {
|
||||
std::optional<PendingRow> ready_row;
|
||||
const auto frame_index = frame->getIndex();
|
||||
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(state_mutex_);
|
||||
if (shutdown_requested_) {
|
||||
return;
|
||||
}
|
||||
|
||||
const auto tracked_stream = toTrackedStream(stream_type);
|
||||
auto &row_map = tracked_stream == TrackedStream::COLOR ? color_frame_index_to_row_id_
|
||||
: depth_frame_index_to_row_id_;
|
||||
auto row_id_it = row_map.find(frame_index);
|
||||
if (row_id_it == row_map.end()) {
|
||||
RCLCPP_WARN_STREAM(logger_,
|
||||
"Frame timestamp CSV logger missed row mapping for stream "
|
||||
<< (tracked_stream == TrackedStream::COLOR ? "color" : "depth")
|
||||
<< " frame index " << frame_index);
|
||||
return;
|
||||
}
|
||||
const auto row_id = row_id_it->second;
|
||||
|
||||
auto pending_it = pending_rows_.find(row_id);
|
||||
if (pending_it == pending_rows_.end()) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto &state = tracked_stream == TrackedStream::COLOR ? pending_it->second.color
|
||||
: pending_it->second.depth;
|
||||
populatePublishData(state, tracked_stream, publish_system_us, publish_steady_us);
|
||||
state.final = true;
|
||||
|
||||
if (isRowReady(pending_it->second)) {
|
||||
ready_row = pending_it->second;
|
||||
eraseFrameIndexMappingLocked(*ready_row);
|
||||
pending_rows_.erase(pending_it);
|
||||
}
|
||||
}
|
||||
|
||||
if (ready_row.has_value()) {
|
||||
enqueueCompletedRow(*ready_row);
|
||||
}
|
||||
}
|
||||
|
||||
void FrameTimestampCsvLogger::populateArrivalData(StreamState &state, TrackedStream stream,
|
||||
const std::shared_ptr<ob::Frame> &frame,
|
||||
int64_t arrival_system_us,
|
||||
int64_t arrival_steady_us,
|
||||
bool publish_expected) {
|
||||
auto &previous = stream == TrackedStream::COLOR ? color_previous_ : depth_previous_;
|
||||
|
||||
state.has_frame = true;
|
||||
state.publish_expected = publish_expected;
|
||||
state.frame_index = frame->getIndex();
|
||||
if (frame->hasMetadata(OB_FRAME_METADATA_TYPE_FRAME_NUMBER)) {
|
||||
state.metadata_frame_number =
|
||||
static_cast<int64_t>(frame->getMetadataValue(OB_FRAME_METADATA_TYPE_FRAME_NUMBER));
|
||||
} else {
|
||||
state.metadata_frame_number.reset();
|
||||
}
|
||||
if (frame->hasMetadata(OB_FRAME_METADATA_TYPE_SENSOR_TIMESTAMP)) {
|
||||
state.sensor_ts_us =
|
||||
static_cast<int64_t>(frame->getMetadataValue(OB_FRAME_METADATA_TYPE_SENSOR_TIMESTAMP));
|
||||
} else {
|
||||
state.sensor_ts_us.reset();
|
||||
}
|
||||
state.device_ts_us = static_cast<int64_t>(frame->getTimeStampUs());
|
||||
state.global_ts_us = static_cast<int64_t>(frame->getGlobalTimeStampUs());
|
||||
state.sdk_system_ts_us = static_cast<int64_t>(frame->getSystemTimeStampUs());
|
||||
state.arrival_system_us = arrival_system_us;
|
||||
state.arrival_steady_us = arrival_steady_us;
|
||||
state.device_ts_delta_us = updateDelta(previous.device_ts_us, state.device_ts_us);
|
||||
if (state.sensor_ts_us.has_value()) {
|
||||
state.sensor_ts_delta_us = updateDelta(previous.sensor_ts_us, state.sensor_ts_us.value());
|
||||
} else {
|
||||
state.sensor_ts_delta_us.reset();
|
||||
previous.sensor_ts_us.reset();
|
||||
}
|
||||
state.global_ts_delta_us = updateDelta(previous.global_ts_us, state.global_ts_us);
|
||||
state.sdk_system_ts_delta_us = updateDelta(previous.sdk_system_ts_us, state.sdk_system_ts_us);
|
||||
state.arrival_system_delta_us = updateDelta(previous.arrival_system_us, state.arrival_system_us);
|
||||
state.arrival_steady_delta_us = updateDelta(previous.arrival_steady_us, state.arrival_steady_us);
|
||||
state.sdk_delay_from_global_us = state.arrival_system_us - state.global_ts_us;
|
||||
state.sdk_delay_from_system_us = state.arrival_system_us - state.sdk_system_ts_us;
|
||||
}
|
||||
|
||||
void FrameTimestampCsvLogger::populatePublishData(StreamState &state, TrackedStream stream,
|
||||
int64_t publish_system_us,
|
||||
int64_t publish_steady_us) {
|
||||
auto &previous = stream == TrackedStream::COLOR ? color_previous_ : depth_previous_;
|
||||
|
||||
state.publish_system_us = publish_system_us;
|
||||
state.publish_steady_us = publish_steady_us;
|
||||
state.publish_system_delta_us =
|
||||
updateDelta(previous.publish_system_us, state.publish_system_us.value());
|
||||
state.publish_steady_delta_us =
|
||||
updateDelta(previous.publish_steady_us, state.publish_steady_us.value());
|
||||
state.arrival_to_publish_system_us = state.publish_system_us.value() - state.arrival_system_us;
|
||||
state.arrival_to_publish_steady_us = state.publish_steady_us.value() - state.arrival_steady_us;
|
||||
}
|
||||
|
||||
std::optional<int64_t> FrameTimestampCsvLogger::updateDelta(std::optional<int64_t> &previous,
|
||||
int64_t current) {
|
||||
std::optional<int64_t> delta;
|
||||
if (previous.has_value()) {
|
||||
delta = current - previous.value();
|
||||
}
|
||||
previous = current;
|
||||
return delta;
|
||||
}
|
||||
|
||||
void FrameTimestampCsvLogger::finalizeStreamWithoutPublish(StreamState &state) {
|
||||
state.final = true;
|
||||
}
|
||||
|
||||
bool FrameTimestampCsvLogger::isRowReady(const PendingRow &row) const {
|
||||
return row.color.final && row.depth.final;
|
||||
}
|
||||
|
||||
void FrameTimestampCsvLogger::enqueueCompletedRow(const PendingRow &row) {
|
||||
std::lock_guard<std::mutex> queue_lock(completed_rows_mutex_);
|
||||
completed_rows_.push_back(row);
|
||||
if (completed_rows_.size() > kCompletedQueueSoftLimit) {
|
||||
if (!queue_warning_active_) {
|
||||
RCLCPP_WARN_STREAM(logger_, "Frame timestamp CSV queue size exceeded "
|
||||
<< kCompletedQueueSoftLimit << " rows");
|
||||
queue_warning_active_ = true;
|
||||
}
|
||||
} else {
|
||||
queue_warning_active_ = false;
|
||||
}
|
||||
completed_rows_cv_.notify_one();
|
||||
}
|
||||
|
||||
void FrameTimestampCsvLogger::flushPendingRowsLocked(std::vector<PendingRow> &rows) {
|
||||
rows.reserve(rows.size() + pending_rows_.size());
|
||||
for (auto &item : pending_rows_) {
|
||||
auto row = item.second;
|
||||
row.color.final = true;
|
||||
row.depth.final = true;
|
||||
rows.push_back(std::move(row));
|
||||
}
|
||||
pending_rows_.clear();
|
||||
color_frame_index_to_row_id_.clear();
|
||||
depth_frame_index_to_row_id_.clear();
|
||||
}
|
||||
|
||||
void FrameTimestampCsvLogger::eraseFrameIndexMappingLocked(const PendingRow &row) {
|
||||
if (row.color.has_frame) {
|
||||
color_frame_index_to_row_id_.erase(row.color.frame_index);
|
||||
}
|
||||
if (row.depth.has_frame) {
|
||||
depth_frame_index_to_row_id_.erase(row.depth.frame_index);
|
||||
}
|
||||
}
|
||||
|
||||
std::string FrameTimestampCsvLogger::serializeRow(const PendingRow &row) const {
|
||||
std::ostringstream ss;
|
||||
ss << serializeStreamColumns(row.color) << "," << serializeStreamColumns(row.depth);
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
std::string FrameTimestampCsvLogger::serializeStreamColumns(const StreamState &state) const {
|
||||
std::vector<std::string> fields(22, "");
|
||||
if (state.has_frame) {
|
||||
fields[0] = std::to_string(state.frame_index);
|
||||
fields[1] = formatOptionalIntColumn(state.metadata_frame_number);
|
||||
if (state.sensor_ts_us.has_value()) {
|
||||
fields[2] = formatSecondsColumn(state.sensor_ts_us.value());
|
||||
}
|
||||
fields[3] = formatOptionalIntColumn(state.sensor_ts_delta_us);
|
||||
fields[4] = formatSecondsColumn(state.device_ts_us);
|
||||
fields[5] = formatOptionalIntColumn(state.device_ts_delta_us);
|
||||
fields[6] = formatSecondsColumn(state.global_ts_us);
|
||||
fields[7] = formatOptionalIntColumn(state.global_ts_delta_us);
|
||||
fields[8] = formatSecondsColumn(state.sdk_system_ts_us);
|
||||
fields[9] = formatOptionalIntColumn(state.sdk_system_ts_delta_us);
|
||||
fields[10] = formatSecondsColumn(state.arrival_system_us);
|
||||
fields[11] = formatOptionalIntColumn(state.arrival_system_delta_us);
|
||||
fields[12] = formatSecondsColumn(state.arrival_steady_us);
|
||||
fields[13] = formatOptionalIntColumn(state.arrival_steady_delta_us);
|
||||
if (state.publish_system_us.has_value()) {
|
||||
fields[14] = formatSecondsColumn(state.publish_system_us.value());
|
||||
}
|
||||
fields[15] = formatOptionalIntColumn(state.publish_system_delta_us);
|
||||
if (state.publish_steady_us.has_value()) {
|
||||
fields[16] = formatSecondsColumn(state.publish_steady_us.value());
|
||||
}
|
||||
fields[17] = formatOptionalIntColumn(state.publish_steady_delta_us);
|
||||
fields[18] = formatOptionalIntColumn(state.arrival_to_publish_system_us);
|
||||
fields[19] = formatOptionalIntColumn(state.arrival_to_publish_steady_us);
|
||||
fields[20] = formatOptionalIntColumn(state.sdk_delay_from_global_us);
|
||||
fields[21] = formatOptionalIntColumn(state.sdk_delay_from_system_us);
|
||||
}
|
||||
|
||||
std::ostringstream ss;
|
||||
for (size_t i = 0; i < fields.size(); ++i) {
|
||||
if (i != 0) {
|
||||
ss << ",";
|
||||
}
|
||||
ss << fields[i];
|
||||
}
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
std::string FrameTimestampCsvLogger::formatSecondsColumn(int64_t time_us) {
|
||||
std::ostringstream ss;
|
||||
ss << std::fixed << std::setprecision(6) << (static_cast<long double>(time_us) / 1000000.0L);
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
std::string FrameTimestampCsvLogger::formatOptionalIntColumn(const std::optional<int64_t> &value) {
|
||||
if (!value.has_value()) {
|
||||
return "";
|
||||
}
|
||||
return std::to_string(*value);
|
||||
}
|
||||
|
||||
std::string FrameTimestampCsvLogger::csvHeader() {
|
||||
std::ostringstream ss;
|
||||
for (const auto *prefix : {"color", "depth"}) {
|
||||
ss << prefix << "_sdk_frame_index,";
|
||||
ss << prefix << "_hardware_frame_number,";
|
||||
ss << prefix << "_sensor_ts_sec,";
|
||||
ss << prefix << "_sensor_ts_delta_us,";
|
||||
ss << prefix << "_device_ts_sec,";
|
||||
ss << prefix << "_device_ts_delta_us,";
|
||||
ss << prefix << "_global_ts_sec,";
|
||||
ss << prefix << "_global_ts_delta_us,";
|
||||
ss << prefix << "_system_ts_sec,";
|
||||
ss << prefix << "_system_ts_delta_us,";
|
||||
ss << prefix << "_arrival_system_sec,";
|
||||
ss << prefix << "_arrival_system_delta_us,";
|
||||
ss << prefix << "_arrival_steady_sec,";
|
||||
ss << prefix << "_arrival_steady_delta_us,";
|
||||
ss << prefix << "_publish_system_sec,";
|
||||
ss << prefix << "_publish_system_delta_us,";
|
||||
ss << prefix << "_publish_steady_sec,";
|
||||
ss << prefix << "_publish_steady_delta_us,";
|
||||
ss << prefix << "_arrival_to_publish_system_us,";
|
||||
ss << prefix << "_arrival_to_publish_steady_us,";
|
||||
ss << prefix << "_sdk_delay_from_global_us,";
|
||||
ss << prefix << "_sdk_delay_from_system_us";
|
||||
if (std::string(prefix) == "color") {
|
||||
ss << ",";
|
||||
}
|
||||
}
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
void FrameTimestampCsvLogger::writerThreadMain() {
|
||||
if (!enabled_ || writer_failed_) {
|
||||
return;
|
||||
}
|
||||
|
||||
size_t rows_since_flush = 0;
|
||||
auto last_flush = std::chrono::steady_clock::now();
|
||||
|
||||
while (true) {
|
||||
std::deque<PendingRow> rows_to_write;
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(completed_rows_mutex_);
|
||||
completed_rows_cv_.wait_for(lock, kFlushInterval, [this]() {
|
||||
return shutdown_requested_ || !completed_rows_.empty();
|
||||
});
|
||||
rows_to_write.swap(completed_rows_);
|
||||
}
|
||||
|
||||
for (const auto &row : rows_to_write) {
|
||||
if (csv_stream_.is_open()) {
|
||||
csv_stream_ << serializeRow(row) << "\n";
|
||||
rows_since_flush++;
|
||||
}
|
||||
}
|
||||
|
||||
const auto now = std::chrono::steady_clock::now();
|
||||
if (csv_stream_.is_open() && (rows_since_flush >= kFlushBatchSize ||
|
||||
now - last_flush >= kFlushInterval || shutdown_requested_)) {
|
||||
csv_stream_.flush();
|
||||
rows_since_flush = 0;
|
||||
last_flush = now;
|
||||
}
|
||||
|
||||
std::lock_guard<std::mutex> lock(completed_rows_mutex_);
|
||||
if (shutdown_requested_ && completed_rows_.empty()) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void FrameTimestampCsvLogger::openCsvIfNeeded() {
|
||||
csv_stream_.open(csv_file_path_, std::ios::out | std::ios::trunc);
|
||||
if (!csv_stream_.is_open()) {
|
||||
RCLCPP_ERROR_STREAM(logger_, "Failed to open frame timestamp CSV file: " << csv_file_path_);
|
||||
enabled_ = false;
|
||||
writer_failed_ = true;
|
||||
return;
|
||||
}
|
||||
csv_stream_ << csvHeader() << "\n";
|
||||
csv_stream_.flush();
|
||||
RCLCPP_INFO_STREAM(logger_, "Frame timestamp CSV logger enabled: " << csv_file_path_);
|
||||
}
|
||||
|
||||
} // namespace orbbec_camera
|
||||
+1264
-625
File diff suppressed because it is too large
Load Diff
@@ -22,6 +22,7 @@
|
||||
#include <ament_index_cpp/get_package_share_directory.hpp>
|
||||
#include <ament_index_cpp/get_package_prefix.hpp>
|
||||
#include <rclcpp_components/register_node_macro.hpp>
|
||||
#include <rcutils/logging.h>
|
||||
#include <csignal>
|
||||
#include <sys/mman.h>
|
||||
#include <unistd.h>
|
||||
@@ -34,6 +35,12 @@
|
||||
|
||||
std::string g_camera_name = "orbbec_camera"; // Assuming this is declared elsewhere
|
||||
std::string g_time_domain = "global"; // Assuming this is declared elsewhere
|
||||
namespace {
|
||||
std::string getLogDirectoryForCamera(const std::string &camera_name) {
|
||||
std::string home_dir = std::getenv("HOME") ? std::getenv("HOME") : "";
|
||||
return (std::filesystem::path(home_dir) / ".ros" / "Log" / camera_name).string();
|
||||
}
|
||||
} // namespace
|
||||
|
||||
void signalHandler(int sig) {
|
||||
// Prevent recursive signal handling
|
||||
@@ -59,7 +66,7 @@ void signalHandler(int sig) {
|
||||
}
|
||||
in_signal_handler.store(false);
|
||||
} else {
|
||||
std::string log_dir = "Log/";
|
||||
std::filesystem::path log_dir = getLogDirectoryForCamera(g_camera_name);
|
||||
|
||||
// get current time
|
||||
std::time_t now = std::time(nullptr);
|
||||
@@ -71,13 +78,13 @@ void signalHandler(int sig) {
|
||||
|
||||
// generate log file name
|
||||
std::string log_file_name = g_camera_name + "_crash_stack_trace_" + time_stream.str() + ".log";
|
||||
std::string log_file_path = log_dir + log_file_name;
|
||||
std::filesystem::path log_file_path = log_dir / log_file_name;
|
||||
|
||||
if (!std::filesystem::exists(log_dir)) {
|
||||
std::filesystem::create_directories(log_dir);
|
||||
}
|
||||
|
||||
std::cout << "Log crash stack trace to " << log_file_path << std::endl;
|
||||
std::cout << "Log crash stack trace to " << log_file_path.string() << std::endl;
|
||||
std::ofstream log_file(log_file_path, std::ios::app);
|
||||
|
||||
if (log_file.is_open()) {
|
||||
@@ -96,6 +103,24 @@ void signalHandler(int sig) {
|
||||
|
||||
namespace orbbec_camera {
|
||||
backward::SignalHandling OBCameraNodeDriver::sh;
|
||||
|
||||
namespace {
|
||||
int rosLogSeverityFromString(const std::string_view &log_level) {
|
||||
if (log_level == "debug") {
|
||||
return RCUTILS_LOG_SEVERITY_DEBUG;
|
||||
} else if (log_level == "info") {
|
||||
return RCUTILS_LOG_SEVERITY_INFO;
|
||||
} else if (log_level == "warn") {
|
||||
return RCUTILS_LOG_SEVERITY_WARN;
|
||||
} else if (log_level == "error") {
|
||||
return RCUTILS_LOG_SEVERITY_ERROR;
|
||||
} else if (log_level == "fatal") {
|
||||
return RCUTILS_LOG_SEVERITY_FATAL;
|
||||
}
|
||||
return RCUTILS_LOG_SEVERITY_UNSET;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
OBCameraNodeDriver::OBCameraNodeDriver(const rclcpp::NodeOptions &node_options)
|
||||
: Node("orbbec_camera_node", "/", node_options),
|
||||
node_options_(node_options),
|
||||
@@ -205,19 +230,26 @@ void OBCameraNodeDriver::init() {
|
||||
g_camera_name = declare_parameter<std::string>("camera_name", g_camera_name);
|
||||
auto log_level_str = declare_parameter<std::string>("log_level", "none");
|
||||
auto log_level = obLogSeverityFromString(log_level_str);
|
||||
auto ros_log_level = rosLogSeverityFromString(log_level_str);
|
||||
auto log_file_name = declare_parameter<std::string>("log_file_name", "");
|
||||
std::string pwd_dir = std::getenv("PWD") ? std::getenv("PWD") : std::getenv("HOME");
|
||||
std::string log_path = pwd_dir + "/Log/" + g_camera_name;
|
||||
std::string log_path = getLogDirectoryForCamera(g_camera_name);
|
||||
// Set logger to console
|
||||
ob::Context::setLoggerToConsole(log_level);
|
||||
ob::Context::setLoggerToFile(log_level, log_path.c_str());
|
||||
if (ros_log_level != RCUTILS_LOG_SEVERITY_UNSET) {
|
||||
auto ret = rcutils_logging_set_logger_level(this->get_logger().get_name(), ros_log_level);
|
||||
if (ret != RCUTILS_RET_OK) {
|
||||
RCLCPP_WARN_STREAM(logger_, "Failed to set ROS log level to " << log_level_str);
|
||||
}
|
||||
}
|
||||
// Set custom log file name if specified
|
||||
if (!log_file_name.empty()) {
|
||||
try {
|
||||
ob::Context::setLoggerFileName(log_file_name);
|
||||
RCLCPP_INFO_STREAM(logger_, "SDK log file name set to: " << log_file_name);
|
||||
} catch (const ob::Error &e) {
|
||||
RCLCPP_WARN_STREAM(logger_, "Failed to set SDK log file name: " << e.getMessage());
|
||||
RCLCPP_WARN_STREAM(logger_, "Failed to set SDK log file name: "
|
||||
<< orbbec_camera::formatObErrorWithStatus(e));
|
||||
}
|
||||
}
|
||||
// Force IP
|
||||
@@ -283,13 +315,14 @@ void OBCameraNodeDriver::init() {
|
||||
<< device_access_mode_ << ")");
|
||||
if (uvc_backend_ == "libuvc") {
|
||||
ctx_->setUvcBackendType(OB_UVC_BACKEND_TYPE_LIBUVC);
|
||||
RCLCPP_INFO_STREAM(logger_, "setUvcBackendType:" << uvc_backend_);
|
||||
RCLCPP_INFO_STREAM(logger_, "Set UVC backend to " << uvc_backend_);
|
||||
} else if (uvc_backend_ == "v4l2") {
|
||||
ctx_->setUvcBackendType(OB_UVC_BACKEND_TYPE_V4L2);
|
||||
RCLCPP_INFO_STREAM(logger_, "setUvcBackendType:" << uvc_backend_);
|
||||
RCLCPP_INFO_STREAM(logger_, "Set UVC backend to " << uvc_backend_);
|
||||
} else {
|
||||
ctx_->setUvcBackendType(OB_UVC_BACKEND_TYPE_LIBUVC);
|
||||
RCLCPP_INFO_STREAM(logger_, "setUvcBackendType:" << uvc_backend_);
|
||||
RCLCPP_WARN_STREAM(logger_,
|
||||
"Unsupported uvc_backend '" << uvc_backend_ << "', using default libuvc");
|
||||
}
|
||||
ctx_->enableNetDeviceEnumeration(enumerate_net_device_);
|
||||
device_changed_callback_id_ = ctx_->registerDeviceChangedCallback(
|
||||
@@ -319,17 +352,16 @@ void OBCameraNodeDriver::init() {
|
||||
void OBCameraNodeDriver::onDeviceConnected(const std::shared_ptr<ob::DeviceList> &device_list) {
|
||||
CHECK_NOTNULL(device_list);
|
||||
{
|
||||
RCLCPP_INFO_STREAM(logger_, "onDeviceConnected called");
|
||||
RCLCPP_INFO_STREAM(logger_, "Device connected callback triggered");
|
||||
std::unique_lock<decltype(reset_device_mutex_)> reset_lock(reset_device_mutex_);
|
||||
if (reset_device_flag_) {
|
||||
RCLCPP_INFO_STREAM(logger_, "onDeviceConnected : device reset in progress, waiting...");
|
||||
RCLCPP_INFO_STREAM(logger_, "Device reset in progress, waiting before connecting");
|
||||
reset_device_cond_.wait(
|
||||
reset_lock, [this]() { return !reset_device_flag_ || !is_alive_ || !rclcpp::ok(); });
|
||||
if (!is_alive_) {
|
||||
return;
|
||||
}
|
||||
RCLCPP_INFO_STREAM(logger_,
|
||||
"onDeviceConnected : device reset completed, continuing connection");
|
||||
RCLCPP_INFO_STREAM(logger_, "Device reset completed, continuing connection");
|
||||
}
|
||||
}
|
||||
if (device_list->getCount() == 0) {
|
||||
@@ -377,11 +409,9 @@ void OBCameraNodeDriver::onDeviceDisconnected(const std::shared_ptr<ob::DeviceLi
|
||||
RCLCPP_INFO_STREAM(logger_, "device with " << uid << " disconnected");
|
||||
if (uid == device_unique_id_ || serial_number_ == serial_number) {
|
||||
RCLCPP_INFO_STREAM(logger_,
|
||||
"device with " << uid << " disconnected, notify reset device thread 1.");
|
||||
"device with " << uid << " disconnected, notify reset device thread");
|
||||
reset_device_flag_ = true;
|
||||
reset_device_cond_.notify_all();
|
||||
RCLCPP_INFO_STREAM(logger_,
|
||||
"device with " << uid << " disconnected, notify reset device thread 2.");
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -497,7 +527,7 @@ void OBCameraNodeDriver::resetDevice() {
|
||||
}
|
||||
}
|
||||
|
||||
RCLCPP_INFO_STREAM(logger_, "resetDevice : Reset device uid: " << device_unique_id_);
|
||||
RCLCPP_INFO_STREAM(logger_, "Resetting device UID: " << device_unique_id_);
|
||||
std::lock_guard<decltype(device_lock_)> device_lock(device_lock_);
|
||||
{
|
||||
// Mark device as disconnected immediately to prevent other threads from accessing it
|
||||
@@ -516,7 +546,7 @@ void OBCameraNodeDriver::resetDevice() {
|
||||
|
||||
if (device_) {
|
||||
try {
|
||||
RCLCPP_INFO_STREAM(logger_, "Resetting device_");
|
||||
RCLCPP_INFO_STREAM(logger_, "Resetting device handle");
|
||||
// Force free any idle memory before device reset
|
||||
if (ctx_) {
|
||||
try {
|
||||
@@ -526,9 +556,10 @@ void OBCameraNodeDriver::resetDevice() {
|
||||
}
|
||||
}
|
||||
device_.reset();
|
||||
RCLCPP_INFO_STREAM(logger_, "device_ reset completed");
|
||||
RCLCPP_INFO_STREAM(logger_, "Device handle reset complete");
|
||||
} catch (const ob::Error &e) {
|
||||
RCLCPP_WARN_STREAM(logger_, "OB Exception during device reset: " << e.getMessage());
|
||||
RCLCPP_WARN_STREAM(logger_, "OB Exception during device reset: "
|
||||
<< orbbec_camera::formatObErrorWithStatus(e));
|
||||
} catch (const std::exception &e) {
|
||||
RCLCPP_WARN_STREAM(logger_, "Standard exception during device reset: " << e.what());
|
||||
} catch (...) {
|
||||
@@ -538,9 +569,9 @@ void OBCameraNodeDriver::resetDevice() {
|
||||
|
||||
if (device_info_) {
|
||||
try {
|
||||
RCLCPP_INFO_STREAM(logger_, "Resetting device_info_");
|
||||
RCLCPP_INFO_STREAM(logger_, "Resetting device info");
|
||||
device_info_.reset();
|
||||
RCLCPP_INFO_STREAM(logger_, "device_info_ reset completed");
|
||||
RCLCPP_INFO_STREAM(logger_, "Device info reset complete");
|
||||
} catch (...) {
|
||||
RCLCPP_WARN_STREAM(logger_, "Exception during device_info reset");
|
||||
}
|
||||
@@ -553,7 +584,7 @@ void OBCameraNodeDriver::resetDevice() {
|
||||
}
|
||||
reset_device_cond_.notify_all();
|
||||
malloc_trim(0);
|
||||
RCLCPP_INFO_STREAM(logger_, "Reset device uid: " << device_unique_id_ << " done");
|
||||
RCLCPP_INFO_STREAM(logger_, "Device reset complete");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -586,7 +617,7 @@ void OBCameraNodeDriver::deviceStatusTimer() {
|
||||
ob_camera_node_->getColorStatus(status_msg);
|
||||
ob_camera_node_->getDepthStatus(status_msg);
|
||||
} catch (const ob::Error &e) {
|
||||
std::string error_msg = e.getMessage() ? e.getMessage() : "Unknown OB error";
|
||||
std::string error_msg = orbbec_camera::formatObErrorWithStatus(e);
|
||||
if (error_msg.find("Device is deactivated") != std::string::npos ||
|
||||
error_msg.find("disconnected") != std::string::npos ||
|
||||
error_msg.find("Send control transfer failed") != std::string::npos) {
|
||||
@@ -615,7 +646,7 @@ void OBCameraNodeDriver::deviceStatusTimer() {
|
||||
status_msg.connection_type = device_info_->getConnectionType();
|
||||
}
|
||||
} catch (const ob::Error &e) {
|
||||
std::string error_msg = e.getMessage() ? e.getMessage() : "Unknown OB error";
|
||||
std::string error_msg = orbbec_camera::formatObErrorWithStatus(e);
|
||||
if (error_msg.find("Device is deactivated") != std::string::npos ||
|
||||
error_msg.find("disconnected") != std::string::npos ||
|
||||
error_msg.find("Send control transfer failed") != std::string::npos) {
|
||||
@@ -642,7 +673,7 @@ void OBCameraNodeDriver::deviceStatusTimer() {
|
||||
status_msg.calibration_from_factory = calibration_from_factory;
|
||||
}
|
||||
} catch (const ob::Error &e) {
|
||||
std::string error_msg = e.getMessage() ? e.getMessage() : "Unknown OB error";
|
||||
std::string error_msg = orbbec_camera::formatObErrorWithStatus(e);
|
||||
if (error_msg.find("Device is deactivated") != std::string::npos ||
|
||||
error_msg.find("disconnected") != std::string::npos ||
|
||||
error_msg.find("Send control transfer failed") != std::string::npos) {
|
||||
@@ -681,7 +712,7 @@ void OBCameraNodeDriver::deviceStatusTimer() {
|
||||
status_msg.customer_calibration_ready = false;
|
||||
}
|
||||
} catch (const ob::Error &e) {
|
||||
std::string error_msg = e.getMessage() ? e.getMessage() : "Unknown OB error";
|
||||
std::string error_msg = orbbec_camera::formatObErrorWithStatus(e);
|
||||
if (error_msg.find("Device is deactivated") != std::string::npos ||
|
||||
error_msg.find("disconnected") != std::string::npos ||
|
||||
error_msg.find("Send control transfer failed") != std::string::npos) {
|
||||
@@ -811,11 +842,9 @@ std::shared_ptr<ob::Device> OBCameraNodeDriver::selectDeviceBySerialNumber(
|
||||
std::transform(serial_number.begin(), serial_number.end(), std::back_inserter(lower_sn),
|
||||
[](auto ch) { return isalpha(ch) ? tolower(ch) : static_cast<int>(ch); });
|
||||
for (size_t i = 0; i < list->getCount(); i++) {
|
||||
RCLCPP_INFO_STREAM_THROTTLE(logger_, *get_clock(), 5000,
|
||||
"Before lock: Select device serial number: " << serial_number);
|
||||
RCLCPP_DEBUG_STREAM_THROTTLE(logger_, *get_clock(), 5000,
|
||||
"Selecting device by serial number: " << serial_number);
|
||||
std::lock_guard<decltype(device_lock_)> lock(device_lock_);
|
||||
RCLCPP_INFO_STREAM_THROTTLE(logger_, *get_clock(), 5000,
|
||||
"After lock: Select device serial number: " << serial_number);
|
||||
try {
|
||||
auto pid = list->getPid(i);
|
||||
if (isOpenNIDevice(pid)) {
|
||||
@@ -825,21 +854,23 @@ std::shared_ptr<ob::Device> OBCameraNodeDriver::selectDeviceBySerialNumber(
|
||||
if (device_info->getSerialNumber() == serial_number) {
|
||||
RCLCPP_INFO_STREAM_THROTTLE(
|
||||
logger_, *get_clock(), 5000,
|
||||
"Device serial number " << device_info->getSerialNumber() << " matched");
|
||||
"Matched device serial number: " << device_info->getSerialNumber());
|
||||
return device;
|
||||
}
|
||||
} else {
|
||||
std::string sn = list->getSerialNumber(i);
|
||||
RCLCPP_INFO_STREAM_THROTTLE(logger_, *get_clock(), 5000, "Device serial number: " << sn);
|
||||
RCLCPP_DEBUG_STREAM_THROTTLE(logger_, *get_clock(), 5000,
|
||||
"Checking device serial number: " << sn);
|
||||
if (sn == serial_number) {
|
||||
RCLCPP_INFO_STREAM_THROTTLE(logger_, *get_clock(), 5000,
|
||||
"Device serial number " << sn << " matched");
|
||||
"Matched device serial number: " << sn);
|
||||
return list->getDevice(i, device_access_mode_);
|
||||
}
|
||||
}
|
||||
} catch (ob::Error &e) {
|
||||
RCLCPP_ERROR_STREAM_THROTTLE(logger_, *get_clock(), 5000,
|
||||
"Failed to get device info " << e.getMessage());
|
||||
RCLCPP_ERROR_STREAM_THROTTLE(
|
||||
logger_, *get_clock(), 5000,
|
||||
"Failed to get device info " << orbbec_camera::formatObErrorWithStatus(e));
|
||||
} catch (std::exception &e) {
|
||||
RCLCPP_ERROR_STREAM_THROTTLE(logger_, *get_clock(), 5000,
|
||||
"Failed to get device info " << e.what());
|
||||
@@ -849,15 +880,12 @@ std::shared_ptr<ob::Device> OBCameraNodeDriver::selectDeviceBySerialNumber(
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::shared_ptr<ob::Device> OBCameraNodeDriver::selectDeviceByUSBPort(
|
||||
const std::shared_ptr<ob::DeviceList> &list, const std::string &usb_port) {
|
||||
try {
|
||||
RCLCPP_INFO_STREAM_THROTTLE(logger_, *get_clock(), 5000,
|
||||
"Before lock: Select device usb port: " << usb_port);
|
||||
"Selecting device by USB port: " << usb_port);
|
||||
std::lock_guard<decltype(device_lock_)> lock(device_lock_);
|
||||
RCLCPP_INFO_STREAM_THROTTLE(logger_, *get_clock(), 5000,
|
||||
"After lock: Select device usb port: " << usb_port);
|
||||
auto device = list->getDeviceByUid(usb_port.c_str(), device_access_mode_);
|
||||
if (device) {
|
||||
RCLCPP_INFO_STREAM_THROTTLE(logger_, *get_clock(), 5000,
|
||||
@@ -871,8 +899,9 @@ std::shared_ptr<ob::Device> OBCameraNodeDriver::selectDeviceByUSBPort(
|
||||
}
|
||||
return device;
|
||||
} catch (ob::Error &e) {
|
||||
RCLCPP_ERROR_STREAM_THROTTLE(logger_, *get_clock(), 5000,
|
||||
"Failed to get device info " << e.getMessage());
|
||||
RCLCPP_ERROR_STREAM_THROTTLE(
|
||||
logger_, *get_clock(), 5000,
|
||||
"Failed to get device info " << orbbec_camera::formatObErrorWithStatus(e));
|
||||
} catch (std::exception &e) {
|
||||
RCLCPP_ERROR_STREAM_THROTTLE(logger_, *get_clock(), 5000,
|
||||
"Failed to get device info " << e.what());
|
||||
@@ -885,11 +914,9 @@ std::shared_ptr<ob::Device> OBCameraNodeDriver::selectDeviceByUSBPort(
|
||||
|
||||
std::shared_ptr<ob::Device> OBCameraNodeDriver::selectDeviceByNetIP(
|
||||
const std::shared_ptr<ob::DeviceList> &list, const std::string &net_ip) {
|
||||
RCLCPP_INFO_STREAM_THROTTLE(logger_, *get_clock(), 5000,
|
||||
"Before lock: Select device net ip: " << net_ip);
|
||||
RCLCPP_DEBUG_STREAM_THROTTLE(logger_, *get_clock(), 5000,
|
||||
"Selecting device by network IP: " << net_ip);
|
||||
std::lock_guard<decltype(device_lock_)> lock(device_lock_);
|
||||
RCLCPP_INFO_STREAM_THROTTLE(logger_, *get_clock(), 5000,
|
||||
"After lock: Select device net ip: " << net_ip);
|
||||
std::shared_ptr<ob::Device> device = nullptr;
|
||||
for (size_t i = 0; i < list->getCount(); i++) {
|
||||
try {
|
||||
@@ -899,16 +926,17 @@ std::shared_ptr<ob::Device> OBCameraNodeDriver::selectDeviceByNetIP(
|
||||
if (list->getIpAddress(i) == nullptr) {
|
||||
continue;
|
||||
}
|
||||
RCLCPP_INFO_STREAM_THROTTLE(logger_, *get_clock(), 5000,
|
||||
"FindDeviceByNetIP device net ip " << list->getIpAddress(i));
|
||||
RCLCPP_DEBUG_STREAM_THROTTLE(logger_, *get_clock(), 5000,
|
||||
"FindDeviceByNetIP device net ip " << list->getIpAddress(i));
|
||||
if (std::string(list->getIpAddress(i)) == net_ip) {
|
||||
RCLCPP_INFO_STREAM_THROTTLE(logger_, *get_clock(), 5000,
|
||||
"getDeviceByNetIP device net ip " << net_ip << " done");
|
||||
return list->getDevice(i, device_access_mode_);
|
||||
}
|
||||
} catch (ob::Error &e) {
|
||||
RCLCPP_ERROR_STREAM_THROTTLE(logger_, *get_clock(), 5000,
|
||||
"Failed to get device info " << e.getMessage());
|
||||
RCLCPP_ERROR_STREAM_THROTTLE(
|
||||
logger_, *get_clock(), 5000,
|
||||
"Failed to get device info " << orbbec_camera::formatObErrorWithStatus(e));
|
||||
continue;
|
||||
} catch (std::exception &e) {
|
||||
RCLCPP_ERROR_STREAM_THROTTLE(logger_, *get_clock(), 5000,
|
||||
@@ -937,7 +965,7 @@ void OBCameraNodeDriver::initializeDevice(const std::shared_ptr<ob::Device> &dev
|
||||
constexpr int max_retries = 3;
|
||||
bool initialized = false;
|
||||
device_info_ = device_->getDeviceInfo();
|
||||
RCLCPP_INFO_STREAM(logger_, "Try to connect device via " << device_info_->connectionType());
|
||||
RCLCPP_DEBUG_STREAM(logger_, "Try to connect device via " << device_info_->connectionType());
|
||||
|
||||
while (retry_count < max_retries && !initialized) {
|
||||
try {
|
||||
@@ -953,7 +981,7 @@ void OBCameraNodeDriver::initializeDevice(const std::shared_ptr<ob::Device> &dev
|
||||
} catch (const ob::Error &e) {
|
||||
RCLCPP_ERROR_STREAM(logger_, "Failed to initialize device (Attempt "
|
||||
<< retry_count + 1 << " of " << max_retries
|
||||
<< "): " << e.getMessage());
|
||||
<< "): " << orbbec_camera::formatObErrorWithStatus(e));
|
||||
} catch (const std::exception &e) {
|
||||
RCLCPP_ERROR_STREAM(logger_, "Failed to initialize device (Attempt " << retry_count + 1
|
||||
<< " of " << max_retries
|
||||
@@ -981,6 +1009,7 @@ void OBCameraNodeDriver::initializeDevice(const std::shared_ptr<ob::Device> &dev
|
||||
if (enable_sync_host_time_ && !isOpenNIDevice(device_info_->pid()) && device_type_ == "camera") {
|
||||
TRY_EXECUTE_BLOCK(device_->timerSyncWithHost());
|
||||
if (g_time_domain != "global") {
|
||||
device_->enableGlobalTimestamp(false);
|
||||
sync_host_time_timer_ = this->create_wall_timer(time_sync_period_, [this]() {
|
||||
// Multiple safety checks before attempting time sync
|
||||
if (!device_) {
|
||||
@@ -1027,9 +1056,10 @@ void OBCameraNodeDriver::initializeDevice(const std::shared_ptr<ob::Device> &dev
|
||||
return;
|
||||
}
|
||||
|
||||
RCLCPP_INFO_STREAM(logger_, "Sync device time with host");
|
||||
TRY_EXECUTE_BLOCK(device_->timerSyncWithHost());
|
||||
});
|
||||
RCLCPP_INFO_STREAM(logger_, "Enabled timer sync with host with period "
|
||||
<< time_sync_period_.count() << " ms");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1041,20 +1071,34 @@ void OBCameraNodeDriver::initializeDevice(const std::shared_ptr<ob::Device> &dev
|
||||
RCLCPP_INFO_STREAM(logger_, "ROS Wrapper version: " << OB_ROS_VERSION_STR);
|
||||
RCLCPP_INFO_STREAM(logger_, "SDK version: " << getObSDKVersion());
|
||||
RCLCPP_INFO_STREAM(logger_, "Hardware version: " << device_info_->getHardwareVersion());
|
||||
try {
|
||||
std::string isp_fw_version = device_->getExtensionInfo("IspFwVer");
|
||||
if (!isp_fw_version.empty()) {
|
||||
RCLCPP_INFO_STREAM(logger_, "ISP firmware version: " << isp_fw_version);
|
||||
}
|
||||
std::string isp_need_version = device_->getExtensionInfo("IspNeedVer");
|
||||
if (!isp_need_version.empty()) {
|
||||
RCLCPP_INFO_STREAM(logger_, "ISP needed version: " << isp_need_version);
|
||||
}
|
||||
} catch (ob::Error &e) {
|
||||
// Some devices don't support ISP firmware version query
|
||||
RCLCPP_DEBUG_STREAM(
|
||||
logger_, "Current device not support ISP firmware version query: " << e.getMessage());
|
||||
}
|
||||
RCLCPP_INFO_STREAM(logger_, "usb connect type: " << device_info_->getConnectionType());
|
||||
});
|
||||
RCLCPP_INFO_STREAM(logger_, "device unique id: " << device_unique_id_);
|
||||
RCLCPP_INFO_STREAM(logger_, "Current node pid: " << getpid());
|
||||
auto time_cost = std::chrono::duration_cast<std::chrono::milliseconds>(
|
||||
std::chrono::high_resolution_clock::now() - start_time_);
|
||||
RCLCPP_INFO_STREAM(logger_, "Start device cost " << time_cost.count() << " ms");
|
||||
RCLCPP_DEBUG_STREAM(logger_, "Start device cost: " << time_cost.count() << " ms");
|
||||
|
||||
if (!upgrade_firmware_.empty()) {
|
||||
// Check if this is a second update (reupdate scenario)
|
||||
bool is_second_update = is_reupdating_.load();
|
||||
|
||||
if (is_second_update) {
|
||||
RCLCPP_INFO(logger_, "Device reconnected, starting the second firmware update...");
|
||||
RCLCPP_INFO(logger_, "Device reconnected, starting the second firmware update");
|
||||
} else {
|
||||
RCLCPP_INFO(logger_, "Starting firmware update from file: %s", upgrade_firmware_.c_str());
|
||||
}
|
||||
@@ -1082,7 +1126,7 @@ void OBCameraNodeDriver::initializeDevice(const std::shared_ptr<ob::Device> &dev
|
||||
|
||||
if (need_reupdate_) {
|
||||
// Some devices require a second update after reboot
|
||||
RCLCPP_INFO(logger_, "The device will reboot and perform a second update automatically.");
|
||||
RCLCPP_INFO(logger_, "The device will reboot and perform a second update automatically");
|
||||
// Set flag to indicate we're waiting for device to reboot for second update
|
||||
is_reupdating_ = true;
|
||||
// Keep upgrade_firmware_ path and wait for device to reconnect
|
||||
@@ -1092,10 +1136,10 @@ void OBCameraNodeDriver::initializeDevice(const std::shared_ptr<ob::Device> &dev
|
||||
|
||||
if (firmware_update_success_) {
|
||||
if (is_second_update) {
|
||||
RCLCPP_INFO(logger_, "Second firmware update completed successfully!");
|
||||
RCLCPP_INFO(logger_, "Second firmware update completed successfully");
|
||||
is_reupdating_ = false;
|
||||
} else {
|
||||
RCLCPP_INFO(logger_, "Firmware update completed successfully!");
|
||||
RCLCPP_INFO(logger_, "Firmware update completed successfully");
|
||||
}
|
||||
return;
|
||||
}
|
||||
@@ -1108,7 +1152,7 @@ void OBCameraNodeDriver::initializeDevice(const std::shared_ptr<ob::Device> &dev
|
||||
ob_lidar_node_->startStreams();
|
||||
ob_lidar_node_->startIMU();
|
||||
} else {
|
||||
RCLCPP_INFO_STREAM(logger_, "ob_camera_node_ is nullptr");
|
||||
RCLCPP_WARN_STREAM(logger_, "Camera or LiDAR node is null after device initialization");
|
||||
}
|
||||
|
||||
} // namespace orbbec_camera
|
||||
@@ -1180,7 +1224,8 @@ bool OBCameraNodeDriver::applyForceIpConfig() {
|
||||
RCLCPP_ERROR(logger_, "[ForceIP] Failed to apply config (SDK returned false)");
|
||||
}
|
||||
} catch (const ob::Error &e) {
|
||||
RCLCPP_ERROR(logger_, "[ForceIP] ob::Error: %s", e.getMessage());
|
||||
RCLCPP_ERROR(logger_, "[ForceIP] ob::Error: %s",
|
||||
orbbec_camera::formatObErrorWithStatus(e).c_str());
|
||||
} catch (const std::exception &e) {
|
||||
RCLCPP_ERROR(logger_, "[ForceIP] std::exception: %s", e.what());
|
||||
} catch (...) {
|
||||
@@ -1267,7 +1312,7 @@ void OBCameraNodeDriver::startDevice(const std::shared_ptr<ob::DeviceList> &list
|
||||
// success get lock,break
|
||||
break;
|
||||
} else if (try_lock_result == EBUSY) {
|
||||
RCLCPP_INFO_STREAM(logger_, "Device lock is held by another process, waiting 100ms");
|
||||
RCLCPP_WARN_STREAM(logger_, "Device lock is held by another process, waiting 100ms");
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
||||
} else {
|
||||
RCLCPP_ERROR_STREAM(logger_, "Failed to lock orb_device_lock_");
|
||||
@@ -1293,12 +1338,12 @@ void OBCameraNodeDriver::startDevice(const std::shared_ptr<ob::DeviceList> &list
|
||||
}
|
||||
auto end_time = std::chrono::high_resolution_clock::now();
|
||||
auto time_cost = std::chrono::duration_cast<std::chrono::milliseconds>(end_time - start_time);
|
||||
RCLCPP_INFO_STREAM(logger_, "Select device cost " << time_cost.count() << " ms");
|
||||
RCLCPP_DEBUG_STREAM(logger_, "Select device cost " << time_cost.count() << " ms");
|
||||
start_time = std::chrono::high_resolution_clock::now();
|
||||
initializeDevice(device);
|
||||
end_time = std::chrono::high_resolution_clock::now();
|
||||
time_cost = std::chrono::duration_cast<std::chrono::milliseconds>(end_time - start_time);
|
||||
RCLCPP_INFO_STREAM(logger_, "Initialize device cost " << time_cost.count() << " ms");
|
||||
RCLCPP_INFO_STREAM(logger_, "Initialize device cost: " << time_cost.count() << " ms");
|
||||
|
||||
if (firmware_update_success_) {
|
||||
firmware_update_success_ = false;
|
||||
@@ -1312,15 +1357,16 @@ void OBCameraNodeDriver::startDevice(const std::shared_ptr<ob::DeviceList> &list
|
||||
}
|
||||
|
||||
auto pid = device->getDeviceInfo()->getPid();
|
||||
if (GEMINI_335LG_PID == pid) {
|
||||
if (GEMINI_335LG_PID == pid || GEMINI_338LG_PID == pid) {
|
||||
ob_camera_node_->startGmslTrigger();
|
||||
}
|
||||
if (pid == GEMINI_305_PID) {
|
||||
// Fixing 305 hot-swap not outputting power
|
||||
ob_camera_node_->startStreams();
|
||||
}
|
||||
// if (isGemini305SeriesPID(pid)) {
|
||||
// // Fixing 305 series hot-swap not outputting power
|
||||
// ob_camera_node_->startStreams();
|
||||
// }
|
||||
} catch (ob::Error &e) {
|
||||
RCLCPP_ERROR_STREAM(logger_, "Failed to initialize device " << e.getMessage());
|
||||
RCLCPP_ERROR_STREAM(
|
||||
logger_, "Failed to initialize device " << orbbec_camera::formatObErrorWithStatus(e));
|
||||
start_device_failed = true;
|
||||
} catch (std::exception &e) {
|
||||
RCLCPP_ERROR_STREAM(logger_, "Failed to initialize device " << e.what());
|
||||
@@ -1393,7 +1439,8 @@ void OBCameraNodeDriver::updatePresetFirmware(std::string path) {
|
||||
}
|
||||
}
|
||||
} catch (ob::Error &e) {
|
||||
RCLCPP_ERROR_STREAM(logger_, "Failed to update Preset Firmware " << e.getMessage());
|
||||
RCLCPP_ERROR_STREAM(logger_, "Failed to update Preset Firmware "
|
||||
<< orbbec_camera::formatObErrorWithStatus(e));
|
||||
} catch (std::exception &e) {
|
||||
RCLCPP_ERROR_STREAM(logger_, "Failed to update Preset Firmware " << e.what());
|
||||
} catch (...) {
|
||||
|
||||
@@ -64,27 +64,26 @@ void OBLidarNode::setAndGetNodeParameter(
|
||||
OBLidarNode::~OBLidarNode() noexcept { clean(); }
|
||||
|
||||
void OBLidarNode::rebootDevice() {
|
||||
RCLCPP_WARN_STREAM(logger_, "Reboot device");
|
||||
RCLCPP_INFO_STREAM(logger_, "Rebooting device");
|
||||
clean();
|
||||
if (device_) {
|
||||
device_->reboot();
|
||||
RCLCPP_WARN_STREAM(logger_, "Reboot device DONE");
|
||||
RCLCPP_DEBUG_STREAM(logger_, "Reboot device complete");
|
||||
}
|
||||
}
|
||||
|
||||
void OBLidarNode::clean() noexcept {
|
||||
std::lock_guard<decltype(device_lock_)> lock(device_lock_);
|
||||
RCLCPP_WARN_STREAM(logger_, "Do destroy ~OBLidarNode");
|
||||
RCLCPP_DEBUG_STREAM(logger_, "Destroying OBLidarNode");
|
||||
is_running_.store(false);
|
||||
RCLCPP_WARN_STREAM(logger_, "Stop tf thread");
|
||||
RCLCPP_DEBUG_STREAM(logger_, "Stop tf thread");
|
||||
if (tf_thread_ && tf_thread_->joinable()) {
|
||||
tf_thread_->join();
|
||||
}
|
||||
RCLCPP_WARN_STREAM(logger_, "Stop color frame thread");
|
||||
RCLCPP_WARN_STREAM(logger_, "stop streams");
|
||||
RCLCPP_DEBUG_STREAM(logger_, "Stop streams");
|
||||
stopStreams();
|
||||
stopIMU();
|
||||
RCLCPP_WARN_STREAM(logger_, "Destroy ~OBLidarNode DONE");
|
||||
RCLCPP_DEBUG_STREAM(logger_, "OBLidarNode cleanup complete");
|
||||
}
|
||||
|
||||
void OBLidarNode::setupTopics() {
|
||||
@@ -95,8 +94,9 @@ void OBLidarNode::setupTopics() {
|
||||
setupProfiles();
|
||||
setupPublishers();
|
||||
} catch (const ob::Error &e) {
|
||||
RCLCPP_ERROR_STREAM(logger_, "Failed to setup topics: " << e.getMessage());
|
||||
throw std::runtime_error(e.getMessage());
|
||||
RCLCPP_ERROR_STREAM(logger_,
|
||||
"Failed to setup topics: " << orbbec_camera::formatObErrorWithStatus(e));
|
||||
throw std::runtime_error(orbbec_camera::formatObErrorWithStatus(e));
|
||||
} catch (const std::exception &e) {
|
||||
RCLCPP_ERROR_STREAM(logger_, "Failed to setup topics: " << e.what());
|
||||
throw std::runtime_error(e.what());
|
||||
@@ -115,9 +115,9 @@ void OBLidarNode::getParameters() {
|
||||
param_name = stream_name_[stream_index] + "_rate";
|
||||
setAndGetNodeParameter(rate_int_[stream_index], param_name, 0);
|
||||
rate_[stream_index] = OBScanRateFromInt(rate_int_[stream_index]);
|
||||
RCLCPP_INFO_STREAM(logger_, "Input rate: " << magic_enum::enum_name(rate_[stream_index])
|
||||
<< " Input format:"
|
||||
<< magic_enum::enum_name(format_[stream_index]));
|
||||
RCLCPP_DEBUG_STREAM(logger_, "Input rate: " << magic_enum::enum_name(rate_[stream_index])
|
||||
<< " Input format:"
|
||||
<< magic_enum::enum_name(format_[stream_index]));
|
||||
param_name = stream_name_[stream_index] + "_frame_id";
|
||||
std::string default_frame_id = camera_name_ + "_" + stream_name_[stream_index] + "_frame";
|
||||
setAndGetNodeParameter(frame_id_[stream_index], param_name, default_frame_id);
|
||||
@@ -181,6 +181,8 @@ void OBLidarNode::getParameters() {
|
||||
}
|
||||
|
||||
void OBLidarNode::setupDevices() {
|
||||
RCLCPP_INFO_STREAM(logger_, "Current time domain: " << time_domain_);
|
||||
|
||||
auto sensor_list = device_->getSensorList();
|
||||
for (size_t i = 0; i < sensor_list->getCount(); i++) {
|
||||
auto sensor = sensor_list->getSensor(i);
|
||||
@@ -196,14 +198,13 @@ void OBLidarNode::setupDevices() {
|
||||
}
|
||||
for (const auto &[stream_index, enable] : enable_stream_) {
|
||||
if (enable && sensors_.find(stream_index) == sensors_.end()) {
|
||||
RCLCPP_INFO_STREAM(logger_,
|
||||
magic_enum::enum_name(stream_index.first)
|
||||
<< "sensor isn't supported by current device! -- Skipping...");
|
||||
RCLCPP_WARN_STREAM(logger_, magic_enum::enum_name(stream_index.first)
|
||||
<< " sensor not supported by current device, skipping");
|
||||
enable_stream_[stream_index] = false;
|
||||
}
|
||||
}
|
||||
if (device_->isPropertySupported(OB_PROP_HEARTBEAT_BOOL, OB_PERMISSION_READ_WRITE)) {
|
||||
RCLCPP_INFO_STREAM(logger_, "Setting heartbeat to " << (enable_heartbeat_ ? "ON" : "OFF"));
|
||||
RCLCPP_INFO_STREAM(logger_, "Current heartbeat: " << (enable_heartbeat_ ? "ON" : "OFF"));
|
||||
TRY_TO_SET_PROPERTY(setBoolProperty, OB_PROP_HEARTBEAT_BOOL, enable_heartbeat_);
|
||||
}
|
||||
if (!echo_mode_.empty() &&
|
||||
@@ -214,9 +215,9 @@ void OBLidarNode::setupDevices() {
|
||||
TRY_TO_SET_PROPERTY(setIntProperty, OB_PROP_LIDAR_SPECIFIC_MODE_INT, 1);
|
||||
}
|
||||
RCLCPP_INFO_STREAM(
|
||||
logger_, "Setting echo mode to "
|
||||
<< (device_->getIntProperty(OB_PROP_LIDAR_SPECIFIC_MODE_INT) ? "First Echo"
|
||||
: "Last Echo"));
|
||||
logger_, "Current echo mode: " << (device_->getIntProperty(OB_PROP_LIDAR_SPECIFIC_MODE_INT)
|
||||
? "First Echo"
|
||||
: "Last Echo"));
|
||||
}
|
||||
if (repetitive_scan_mode_ != -1 &&
|
||||
device_->isPropertySupported(OB_PROP_LIDAR_REPETITIVE_SCAN_MODE_INT,
|
||||
@@ -229,7 +230,7 @@ void OBLidarNode::setupDevices() {
|
||||
} else {
|
||||
TRY_TO_SET_PROPERTY(setIntProperty, OB_PROP_LIDAR_REPETITIVE_SCAN_MODE_INT,
|
||||
repetitive_scan_mode_);
|
||||
RCLCPP_INFO_STREAM(logger_, "Setting repetitive scan mode to " << device_->getIntProperty(
|
||||
RCLCPP_INFO_STREAM(logger_, "Current repetitive scan mode: " << device_->getIntProperty(
|
||||
OB_PROP_LIDAR_REPETITIVE_SCAN_MODE_INT));
|
||||
}
|
||||
}
|
||||
@@ -242,7 +243,7 @@ void OBLidarNode::setupDevices() {
|
||||
} else {
|
||||
TRY_TO_SET_PROPERTY(setIntProperty, OB_PROP_LIDAR_TAIL_FILTER_LEVEL_INT, filter_level_);
|
||||
TRY_TO_SET_PROPERTY(setIntProperty, OB_PROP_LIDAR_APPLY_CONFIGS_INT, 1);
|
||||
RCLCPP_INFO_STREAM(logger_, "Setting filter level to " << device_->getIntProperty(
|
||||
RCLCPP_INFO_STREAM(logger_, "Current filter level: " << device_->getIntProperty(
|
||||
OB_PROP_LIDAR_TAIL_FILTER_LEVEL_INT));
|
||||
}
|
||||
}
|
||||
@@ -255,7 +256,7 @@ void OBLidarNode::setupDevices() {
|
||||
range.min, range.max);
|
||||
} else {
|
||||
TRY_TO_SET_PROPERTY(setFloatProperty, OB_PROP_LIDAR_MEMS_FOV_SIZE_FLOAT, vertical_fov_);
|
||||
RCLCPP_INFO_STREAM(logger_, "Setting vertical fov to " << device_->getFloatProperty(
|
||||
RCLCPP_INFO_STREAM(logger_, "Current vertical fov: " << device_->getFloatProperty(
|
||||
OB_PROP_LIDAR_MEMS_FOV_SIZE_FLOAT));
|
||||
}
|
||||
}
|
||||
@@ -303,20 +304,20 @@ void OBLidarNode::setupProfiles() {
|
||||
<< "Format:" << format_[elem]);
|
||||
RCLCPP_INFO_STREAM(logger_, "Available profiles:");
|
||||
printSensorProfiles(sensor);
|
||||
RCLCPP_ERROR(logger_, "Because can not set this stream, so exit.");
|
||||
RCLCPP_ERROR(logger_, "Failed to configure the requested stream profile, exiting.");
|
||||
exit(-1);
|
||||
}
|
||||
if (!selected_profile) {
|
||||
RCLCPP_WARN_STREAM(logger_, "Given stream configuration is not supported by the device! "
|
||||
<< " Stream: " << magic_enum::enum_name(elem.first)
|
||||
<< ", Stream Index: " << elem.second
|
||||
<< ", Scan Rate: " << rate_[elem]);
|
||||
RCLCPP_WARN_STREAM(
|
||||
logger_, "Requested stream configuration is not supported by the device: "
|
||||
<< "stream=" << magic_enum::enum_name(elem.first)
|
||||
<< ", stream_index=" << elem.second << ", scan_rate=" << rate_[elem]);
|
||||
if (default_profile) {
|
||||
RCLCPP_WARN_STREAM(logger_, "Using default profile instead.");
|
||||
RCLCPP_WARN_STREAM(logger_, "default scan Rate "
|
||||
<< magic_enum::enum_name(default_profile->getScanRate())
|
||||
<< "default format:"
|
||||
<< magic_enum::enum_name(default_profile->getFormat()));
|
||||
RCLCPP_WARN_STREAM(logger_, "Using the default profile instead");
|
||||
RCLCPP_WARN_STREAM(
|
||||
logger_, "Default profile: scan_rate="
|
||||
<< magic_enum::enum_name(default_profile->getScanRate())
|
||||
<< ", format=" << magic_enum::enum_name(default_profile->getFormat()));
|
||||
selected_profile = default_profile;
|
||||
} else {
|
||||
RCLCPP_ERROR_STREAM(
|
||||
@@ -329,11 +330,11 @@ void OBLidarNode::setupProfiles() {
|
||||
stream_profile_[elem] = selected_profile;
|
||||
rate_[elem] = selected_profile->getScanRate();
|
||||
format_[elem] = selected_profile->getFormat();
|
||||
RCLCPP_INFO_STREAM(logger_, " stream "
|
||||
<< stream_name_[elem] << " is enabled - scan rate: "
|
||||
<< magic_enum::enum_name(selected_profile->getScanRate())
|
||||
<< " format:"
|
||||
<< magic_enum::enum_name(selected_profile->getFormat()));
|
||||
RCLCPP_DEBUG_STREAM(logger_, "stream "
|
||||
<< stream_name_[elem] << " is enabled - scan rate: "
|
||||
<< magic_enum::enum_name(selected_profile->getScanRate())
|
||||
<< " format:"
|
||||
<< magic_enum::enum_name(selected_profile->getFormat()));
|
||||
}
|
||||
}
|
||||
// IMU
|
||||
@@ -354,12 +355,12 @@ void OBLidarNode::setupProfiles() {
|
||||
auto profile = profile_list->getGyroStreamProfile(full_scale_range, sample_rate);
|
||||
stream_profile_[stream_index] = profile;
|
||||
}
|
||||
RCLCPP_INFO_STREAM(logger_, "stream " << stream_name_[stream_index] << " full scale range "
|
||||
RCLCPP_INFO_STREAM(logger_, "Stream " << stream_name_[stream_index] << " full scale range: "
|
||||
<< (stream_index == ACCEL ? accel_range_ : gyro_range_)
|
||||
<< " sample rate " << imu_rate_);
|
||||
<< ", sample rate: " << imu_rate_);
|
||||
} catch (const ob::Error &e) {
|
||||
RCLCPP_INFO_STREAM(logger_, "Failed to setup << " << stream_name_[stream_index]
|
||||
<< " profile: " << e.getMessage());
|
||||
RCLCPP_INFO_STREAM(logger_, "Failed to set up " << stream_name_[stream_index] << " profile: "
|
||||
<< orbbec_camera::formatObErrorWithStatus(e));
|
||||
enable_stream_[stream_index] = false;
|
||||
stream_profile_[stream_index] = nullptr;
|
||||
}
|
||||
@@ -434,7 +435,8 @@ void OBLidarNode::startStreams() {
|
||||
onNewFrameSetCallback(frame_set);
|
||||
});
|
||||
} catch (const ob::Error &e) {
|
||||
RCLCPP_ERROR_STREAM(logger_, "Failed to start pipeline: " << e.getMessage());
|
||||
RCLCPP_ERROR_STREAM(logger_,
|
||||
"Failed to start pipeline: " << orbbec_camera::formatObErrorWithStatus(e));
|
||||
setupPipelineConfig();
|
||||
pipeline_->start(pipeline_config_, [this](const std::shared_ptr<ob::FrameSet> &frame_set) {
|
||||
onNewFrameSetCallback(frame_set);
|
||||
@@ -499,13 +501,14 @@ void OBLidarNode::startIMU() {
|
||||
|
||||
void OBLidarNode::stopStreams() {
|
||||
if (!pipeline_started_ || !pipeline_) {
|
||||
RCLCPP_INFO_STREAM(logger_, "pipeline not started or not exist, skip stop pipeline");
|
||||
RCLCPP_DEBUG_STREAM(logger_, "Pipeline not started or not exist, skip stop pipeline");
|
||||
return;
|
||||
}
|
||||
try {
|
||||
pipeline_->stop();
|
||||
} catch (const ob::Error &e) {
|
||||
RCLCPP_ERROR_STREAM(logger_, "Failed to stop pipeline: " << e.getMessage());
|
||||
RCLCPP_ERROR_STREAM(logger_,
|
||||
"Failed to stop pipeline: " << orbbec_camera::formatObErrorWithStatus(e));
|
||||
} catch (...) {
|
||||
RCLCPP_ERROR_STREAM(logger_, "Failed to stop pipeline");
|
||||
}
|
||||
@@ -517,14 +520,16 @@ void OBLidarNode::stopIMU() {
|
||||
}
|
||||
|
||||
if (!imu_sync_output_start_ || !imuPipeline_) {
|
||||
RCLCPP_INFO_STREAM(logger_, "IMU pipeline not started or not exist, skip stop imu pipeline");
|
||||
RCLCPP_DEBUG_STREAM(logger_,
|
||||
"IMU pipeline not started or unavailable, skip stopping IMU pipeline");
|
||||
return;
|
||||
}
|
||||
try {
|
||||
imuPipeline_->stop();
|
||||
imu_sync_output_start_ = false;
|
||||
} catch (const ob::Error &e) {
|
||||
RCLCPP_ERROR_STREAM(logger_, "Failed to stop IMU pipeline: " << e.getMessage());
|
||||
RCLCPP_ERROR_STREAM(
|
||||
logger_, "Failed to stop IMU pipeline: " << orbbec_camera::formatObErrorWithStatus(e));
|
||||
} catch (...) {
|
||||
RCLCPP_ERROR_STREAM(logger_, "Failed to stop IMU pipeline");
|
||||
}
|
||||
@@ -537,15 +542,15 @@ void OBLidarNode::setupPipelineConfig() {
|
||||
pipeline_config_ = std::make_shared<ob::Config>();
|
||||
for (const auto &stream_index : LIDAR_STREAMS) {
|
||||
if (enable_stream_[stream_index]) {
|
||||
RCLCPP_INFO_STREAM(logger_, "Enable " << stream_name_[stream_index] << " stream");
|
||||
RCLCPP_DEBUG_STREAM(logger_, "Enable " << stream_name_[stream_index] << " stream");
|
||||
auto profile = stream_profile_[stream_index]->as<ob::LiDARStreamProfile>();
|
||||
|
||||
if (enable_stream_[stream_index]) {
|
||||
auto video_profile = profile;
|
||||
RCLCPP_INFO_STREAM(logger_,
|
||||
"lidar profile: " << magic_enum::enum_name(video_profile->getScanRate())
|
||||
<< " "
|
||||
<< magic_enum::enum_name(video_profile->getFormat()));
|
||||
RCLCPP_DEBUG_STREAM(logger_,
|
||||
"lidar profile: " << magic_enum::enum_name(video_profile->getScanRate())
|
||||
<< " "
|
||||
<< magic_enum::enum_name(video_profile->getFormat()));
|
||||
}
|
||||
|
||||
RCLCPP_INFO_STREAM(
|
||||
@@ -650,7 +655,8 @@ void OBLidarNode::onNewFrameSetCallback(std::shared_ptr<ob::FrameSet> frame_set)
|
||||
}
|
||||
}
|
||||
} catch (const ob::Error &e) {
|
||||
RCLCPP_ERROR_STREAM(logger_, "onNewFrameSetCallback error: " << e.getMessage());
|
||||
RCLCPP_ERROR_STREAM(
|
||||
logger_, "onNewFrameSetCallback error: " << orbbec_camera::formatObErrorWithStatus(e));
|
||||
} catch (const std::exception &e) {
|
||||
RCLCPP_ERROR_STREAM(logger_, "onNewFrameSetCallback error: " << e.what());
|
||||
} catch (...) {
|
||||
@@ -1244,12 +1250,13 @@ void OBLidarNode::calcAndPublishStaticTransform() {
|
||||
RCLCPP_DEBUG_STREAM(logger_, "ACCEL and GYRO extrinsics are identical");
|
||||
}
|
||||
} catch (const ob::Error &e) {
|
||||
RCLCPP_WARN_STREAM(logger_,
|
||||
"Could not get GYRO extrinsic for verification: " << e.getMessage());
|
||||
RCLCPP_WARN_STREAM(logger_, "Could not get GYRO extrinsic for verification: "
|
||||
<< orbbec_camera::formatObErrorWithStatus(e));
|
||||
}
|
||||
|
||||
} catch (const ob::Error &e) {
|
||||
RCLCPP_WARN_STREAM(logger_, "Failed to get ACCEL extrinsic, trying GYRO: " << e.getMessage());
|
||||
RCLCPP_WARN_STREAM(logger_, "Failed to get ACCEL extrinsic, trying GYRO: "
|
||||
<< orbbec_camera::formatObErrorWithStatus(e));
|
||||
try {
|
||||
ex = base_stream_profile->getExtrinsicTo(stream_profile_[GYRO]);
|
||||
RCLCPP_INFO_STREAM(logger_, "Using GYRO extrinsic for IMU");
|
||||
@@ -1272,11 +1279,12 @@ void OBLidarNode::calcAndPublishStaticTransform() {
|
||||
auto timestamp = node_->now();
|
||||
publishStaticTF(timestamp, trans, Q, frame_id_[base_stream_], accel_gyro_frame_id_);
|
||||
|
||||
RCLCPP_INFO_STREAM(logger_, "Publishing static transform from "
|
||||
<< frame_id_[base_stream_] << " to " << accel_gyro_frame_id_);
|
||||
RCLCPP_INFO_STREAM(logger_, "Translation " << trans[0] << ", " << trans[1] << ", " << trans[2]);
|
||||
RCLCPP_INFO_STREAM(logger_, "Rotation " << Q.getX() << ", " << Q.getY() << ", " << Q.getZ()
|
||||
<< ", " << Q.getW());
|
||||
RCLCPP_DEBUG_STREAM(logger_, "Publishing static transform from "
|
||||
<< frame_id_[base_stream_] << " to " << accel_gyro_frame_id_);
|
||||
RCLCPP_DEBUG_STREAM(logger_,
|
||||
"Translation " << trans[0] << ", " << trans[1] << ", " << trans[2]);
|
||||
RCLCPP_DEBUG_STREAM(logger_, "Rotation " << Q.getX() << ", " << Q.getY() << ", " << Q.getZ()
|
||||
<< ", " << Q.getW());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -22,6 +22,37 @@
|
||||
#include "orbbec_camera/utils.h"
|
||||
namespace orbbec_camera {
|
||||
|
||||
namespace {
|
||||
|
||||
bool isGemini330SeriesForDisparity(uint32_t pid) {
|
||||
return pid == GEMINI_335_PID || pid == GEMINI_336_PID || pid == GEMINI_330_PID ||
|
||||
pid == GEMINI_335L_PID || pid == GEMINI_336L_PID || pid == GEMINI_330L_PID ||
|
||||
pid == GEMINI_335LG_PID || pid == GEMINI_335LE_PID || pid == GEMINI_338_PID ||
|
||||
pid == GEMINI_338LG_PID || pid == GEMINI_338LE_PID || pid == GEMINI_338L_PID ||
|
||||
pid == GEMINI_331L_PID;
|
||||
}
|
||||
|
||||
bool isSupportedDisparityResolutionForPid(uint32_t pid, int width, int height) {
|
||||
if (pid == GEMINI_335LE_PID || pid == GEMINI_338LE_PID) {
|
||||
return (width == 1280 && height == 800) || (width == 640 && height == 400) ||
|
||||
(width == 424 && height == 266) || (width == 320 && height == 200);
|
||||
}
|
||||
|
||||
return (width == 1280 && height == 800) || (width == 1280 && height == 720) ||
|
||||
(width == 640 && height == 400) || (width == 424 && height == 266);
|
||||
}
|
||||
|
||||
std::string getDisparityResolutionHintByPid(uint32_t pid) {
|
||||
if (pid == GEMINI_335LE_PID || pid == GEMINI_338LE_PID) {
|
||||
return "Supported resolutions for the current device: 1280x800/640x400/424x266/320x200";
|
||||
}
|
||||
|
||||
return "Supported resolutions for the current device: "
|
||||
"1280x800/1280x720/640x400/424x266";
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
void OBCameraNode::setupCameraCtrlServices() {
|
||||
using std_srvs::srv::SetBool;
|
||||
for (auto stream_index : IMAGE_STREAMS) {
|
||||
@@ -253,15 +284,15 @@ void OBCameraNode::setupCameraCtrlServices() {
|
||||
getUserCalibParamsCallback(request, response);
|
||||
});
|
||||
}
|
||||
set_ae_mode_srv_ = node_->create_service<SetString>(
|
||||
"set_ae_mode", [this](const std::shared_ptr<SetString::Request> request,
|
||||
std::shared_ptr<SetString::Response> response) {
|
||||
setAEModeCallback(request, response);
|
||||
set_ae_reference_stream_srv_ = node_->create_service<SetString>(
|
||||
"set_ae_reference_stream", [this](const std::shared_ptr<SetString::Request> request,
|
||||
std::shared_ptr<SetString::Response> response) {
|
||||
setAEReferenceStreamCallback(request, response);
|
||||
});
|
||||
set_sports_mode_srv_ = node_->create_service<SetBool>(
|
||||
"set_sports_mode", [this](const std::shared_ptr<SetBool::Request> request,
|
||||
std::shared_ptr<SetBool::Response> response) {
|
||||
setSportsModeCallback(request, response);
|
||||
set_ae_strategy_srv_ = node_->create_service<SetString>(
|
||||
"set_ae_strategy", [this](const std::shared_ptr<SetString::Request> request,
|
||||
std::shared_ptr<SetString::Response> response) {
|
||||
setAEStrategyCallback(request, response);
|
||||
});
|
||||
set_streams_enable_srv_ = node_->create_service<SetBool>(
|
||||
"set_streams_enable", [this](const std::shared_ptr<SetBool::Request> request,
|
||||
@@ -283,6 +314,16 @@ void OBCameraNode::setupCameraCtrlServices() {
|
||||
std::shared_ptr<GetInt32::Response> response) {
|
||||
getPointCloudDecimationCallback(request, response);
|
||||
});
|
||||
set_disparity_range_mode_srv_ = node_->create_service<SetInt32>(
|
||||
"set_disparity_range_mode", [this](const std::shared_ptr<SetInt32::Request> request,
|
||||
std::shared_ptr<SetInt32::Response> response) {
|
||||
setDisparityRangeModeCallback(request, response);
|
||||
});
|
||||
set_disparity_search_offset_srv_ = node_->create_service<SetInt32>(
|
||||
"set_disparity_search_offset", [this](const std::shared_ptr<SetInt32::Request> request,
|
||||
std::shared_ptr<SetInt32::Response> response) {
|
||||
setDisparitySearchOffsetCallback(request, response);
|
||||
});
|
||||
}
|
||||
|
||||
void OBCameraNode::getPointCloudDecimationCallback(
|
||||
@@ -330,6 +371,139 @@ void OBCameraNode::setPointCloudDecimationCallback(
|
||||
}
|
||||
}
|
||||
|
||||
void OBCameraNode::setDisparityRangeModeCallback(const std::shared_ptr<SetInt32::Request>& request,
|
||||
std::shared_ptr<SetInt32::Response>& response) {
|
||||
if (!request) {
|
||||
response->success = false;
|
||||
response->message = "Invalid request";
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
if (!device_->isPropertySupported(OB_PROP_DISP_SEARCH_RANGE_MODE_INT, OB_PERMISSION_WRITE)) {
|
||||
response->success = false;
|
||||
response->message = "Current device does not support disparity range mode";
|
||||
return;
|
||||
}
|
||||
|
||||
const bool allow_set = isGemini435LePID(pid_) || enable_stream_[DEPTH];
|
||||
if (!allow_set) {
|
||||
response->success = false;
|
||||
response->message = "Disparity range mode can only be set when depth stream is enabled";
|
||||
return;
|
||||
}
|
||||
|
||||
if (isGemini330SeriesForDisparity(pid_) &&
|
||||
!isSupportedDisparityResolutionForPid(pid_, width_[DEPTH], height_[DEPTH])) {
|
||||
response->success = false;
|
||||
response->message = "Current depth resolution " + std::to_string(width_[DEPTH]) + "x" +
|
||||
std::to_string(height_[DEPTH]) + " is not supported. " +
|
||||
getDisparityResolutionHintByPid(pid_);
|
||||
return;
|
||||
}
|
||||
|
||||
auto range = device_->getIntPropertyRange(OB_PROP_DISP_SEARCH_RANGE_MODE_INT);
|
||||
const int requested_mode_value = request->data;
|
||||
int hw_mode_index = -1;
|
||||
if (requested_mode_value == 64) {
|
||||
hw_mode_index = 0;
|
||||
} else if (requested_mode_value == 128) {
|
||||
hw_mode_index = 1;
|
||||
} else if (requested_mode_value == 256) {
|
||||
hw_mode_index = 2;
|
||||
}
|
||||
|
||||
if (hw_mode_index < range.min || hw_mode_index > range.max) {
|
||||
response->success = false;
|
||||
std::string supported_mode;
|
||||
for (int i = range.min; i <= range.max; ++i) {
|
||||
supported_mode += (i == 0) ? "64"
|
||||
: (i == 1) ? "/128"
|
||||
: (i == 2) ? "/256"
|
||||
: "/" + std::to_string(i);
|
||||
}
|
||||
response->message = "Invalid disparity range mode. Allowed values:" + supported_mode;
|
||||
return;
|
||||
}
|
||||
|
||||
device_->setIntProperty(OB_PROP_DISP_SEARCH_RANGE_MODE_INT, hw_mode_index);
|
||||
auto current_mode_index = device_->getIntProperty(OB_PROP_DISP_SEARCH_RANGE_MODE_INT);
|
||||
auto current_mode_value = (current_mode_index == 0) ? 64
|
||||
: (current_mode_index == 1) ? 128
|
||||
: (current_mode_index == 2) ? 256
|
||||
: current_mode_index;
|
||||
response->success = true;
|
||||
response->message = "disparity_range_mode updated to " + std::to_string(current_mode_value);
|
||||
} catch (const ob::Error& e) {
|
||||
response->success = false;
|
||||
response->message = orbbec_camera::formatObErrorWithStatus(e);
|
||||
} catch (const std::exception& e) {
|
||||
response->success = false;
|
||||
response->message = e.what();
|
||||
} catch (...) {
|
||||
response->success = false;
|
||||
response->message = "unknown error";
|
||||
}
|
||||
}
|
||||
|
||||
void OBCameraNode::setDisparitySearchOffsetCallback(
|
||||
const std::shared_ptr<SetInt32::Request>& request,
|
||||
std::shared_ptr<SetInt32::Response>& response) {
|
||||
if (!request) {
|
||||
response->success = false;
|
||||
response->message = "Invalid request";
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
if (!device_->isPropertySupported(OB_PROP_DISP_SEARCH_OFFSET_INT, OB_PERMISSION_WRITE)) {
|
||||
response->success = false;
|
||||
response->message = "Current device does not support disparity search offset";
|
||||
return;
|
||||
}
|
||||
|
||||
const bool allow_set = isGemini435LePID(pid_) || enable_stream_[DEPTH];
|
||||
if (!allow_set) {
|
||||
response->success = false;
|
||||
response->message = "Disparity search offset can only be set when depth stream is enabled";
|
||||
return;
|
||||
}
|
||||
|
||||
if (isGemini330SeriesForDisparity(pid_) &&
|
||||
!isSupportedDisparityResolutionForPid(pid_, width_[DEPTH], height_[DEPTH])) {
|
||||
response->success = false;
|
||||
response->message = "Current depth resolution " + std::to_string(width_[DEPTH]) + "x" +
|
||||
std::to_string(height_[DEPTH]) + " is not supported. " +
|
||||
getDisparityResolutionHintByPid(pid_);
|
||||
return;
|
||||
}
|
||||
|
||||
auto range = device_->getIntPropertyRange(OB_PROP_DISP_SEARCH_OFFSET_INT);
|
||||
if (request->data < range.min || request->data > range.max) {
|
||||
response->success = false;
|
||||
response->message =
|
||||
"Invalid disparity search offset. Allowed values:" + std::to_string(range.min) + " to " +
|
||||
std::to_string(range.max);
|
||||
return;
|
||||
}
|
||||
|
||||
device_->setIntProperty(OB_PROP_DISP_SEARCH_OFFSET_INT, request->data);
|
||||
auto current_offset = device_->getIntProperty(OB_PROP_DISP_SEARCH_OFFSET_INT);
|
||||
RCLCPP_INFO_STREAM(logger_, "Set disparity_search_offset to " << current_offset);
|
||||
response->success = true;
|
||||
response->message = "disparity_search_offset updated to " + std::to_string(current_offset);
|
||||
} catch (const ob::Error& e) {
|
||||
response->success = false;
|
||||
response->message = orbbec_camera::formatObErrorWithStatus(e);
|
||||
} catch (const std::exception& e) {
|
||||
response->success = false;
|
||||
response->message = e.what();
|
||||
} catch (...) {
|
||||
response->success = false;
|
||||
response->message = "unknown error";
|
||||
}
|
||||
}
|
||||
|
||||
void OBCameraNode::setStreamsEnableCallback(
|
||||
const std::shared_ptr<std_srvs::srv::SetBool::Request> request,
|
||||
std::shared_ptr<std_srvs::srv::SetBool::Response> response) {
|
||||
@@ -345,7 +519,7 @@ void OBCameraNode::setStreamsEnableCallback(
|
||||
}
|
||||
} catch (const ob::Error& e) {
|
||||
response->success = false;
|
||||
response->message = e.getMessage();
|
||||
response->message = orbbec_camera::formatObErrorWithStatus(e);
|
||||
} catch (const std::exception& e) {
|
||||
response->success = false;
|
||||
response->message = e.what();
|
||||
@@ -394,7 +568,7 @@ void OBCameraNode::setExposureCallback(const std::shared_ptr<SetInt32::Request>&
|
||||
response->success = true;
|
||||
} catch (const ob::Error& e) {
|
||||
response->success = false;
|
||||
response->message = e.getMessage();
|
||||
response->message = orbbec_camera::formatObErrorWithStatus(e);
|
||||
} catch (const std::exception& e) {
|
||||
response->success = false;
|
||||
response->message = e.what();
|
||||
@@ -432,7 +606,7 @@ void OBCameraNode::getGainCallback(const std::shared_ptr<GetInt32::Request>& req
|
||||
response->success = true;
|
||||
} catch (ob::Error& e) {
|
||||
response->success = false;
|
||||
response->message = e.getMessage();
|
||||
response->message = orbbec_camera::formatObErrorWithStatus(e);
|
||||
} catch (const std::exception& e) {
|
||||
response->success = false;
|
||||
response->message = e.what();
|
||||
@@ -471,7 +645,7 @@ void OBCameraNode::setGainCallback(const std::shared_ptr<SetInt32 ::Request>& re
|
||||
auto range = device_->getIntPropertyRange(prop_id);
|
||||
if (request->data < range.min || request->data > range.max) {
|
||||
response->success = false;
|
||||
RCLCPP_INFO_STREAM(logger_, "set gain value out of range");
|
||||
RCLCPP_WARN_STREAM(logger_, "Gain value is out of range");
|
||||
response->message = "value out of range";
|
||||
return;
|
||||
}
|
||||
@@ -479,7 +653,7 @@ void OBCameraNode::setGainCallback(const std::shared_ptr<SetInt32 ::Request>& re
|
||||
response->success = true;
|
||||
} catch (const ob::Error& e) {
|
||||
response->success = false;
|
||||
response->message = e.getMessage();
|
||||
response->message = orbbec_camera::formatObErrorWithStatus(e);
|
||||
} catch (const std::exception& e) {
|
||||
response->success = false;
|
||||
response->message = e.what();
|
||||
@@ -493,16 +667,17 @@ void OBCameraNode::setAeRoiCallback(const std::shared_ptr<SetArrays ::Request>&
|
||||
std::shared_ptr<SetArrays::Response>& response,
|
||||
const stream_index_pair& stream_index) {
|
||||
auto stream = stream_index.first;
|
||||
if (device_->getDeviceInfo()->getPid() == GEMINI_305_PID &&
|
||||
(stream != OB_STREAM_COLOR && ae_mode_ == "colorbased")) {
|
||||
if (isGemini305SeriesPID(device_->getDeviceInfo()->getPid()) &&
|
||||
(stream != OB_STREAM_COLOR && ae_reference_stream_ == "color")) {
|
||||
response->success = false;
|
||||
response->message = "AE MODE is colorbased, other sensors setting is not supported";
|
||||
response->message = "AE Reference Stream is color, other sensors setting is not supported";
|
||||
return;
|
||||
}
|
||||
if (device_->getDeviceInfo()->getPid() == GEMINI_305_PID &&
|
||||
(stream != OB_STREAM_DEPTH && ae_mode_ == "depthbased")) {
|
||||
if (isGemini305SeriesPID(device_->getDeviceInfo()->getPid()) &&
|
||||
(stream != OB_STREAM_DEPTH && ae_reference_stream_ == "depth")) {
|
||||
response->success = false;
|
||||
response->message = "AE MODE is depthbased, other sensors sensor setting is not supported";
|
||||
response->message =
|
||||
"AE Reference Stream is depth, other sensors sensor setting is not supported";
|
||||
return;
|
||||
}
|
||||
auto config = OBRegionOfInterest();
|
||||
@@ -542,9 +717,9 @@ void OBCameraNode::setAeRoiCallback(const std::shared_ptr<SetArrays ::Request>&
|
||||
device_->getStructuredData(OB_STRUCT_DEPTH_AE_ROI, reinterpret_cast<uint8_t*>(&config),
|
||||
&data_size);
|
||||
RCLCPP_INFO_STREAM(
|
||||
logger_, "set depth AE ROI : "
|
||||
logger_, "Set depth AE ROI to "
|
||||
<< "[Left: " << config.x0_left << ", Right: " << config.x1_right
|
||||
<< ", Top: " << config.y0_top << ", Bottom: " << config.y1_bottom << " ]");
|
||||
<< ", Top: " << config.y0_top << ", Bottom: " << config.y1_bottom << "]");
|
||||
break;
|
||||
case OB_STREAM_COLOR:
|
||||
case OB_STREAM_COLOR_LEFT:
|
||||
@@ -578,9 +753,9 @@ void OBCameraNode::setAeRoiCallback(const std::shared_ptr<SetArrays ::Request>&
|
||||
device_->getStructuredData(OB_STRUCT_COLOR_AE_ROI, reinterpret_cast<uint8_t*>(&config),
|
||||
&data_size);
|
||||
RCLCPP_INFO_STREAM(
|
||||
logger_, "set color AE ROI : "
|
||||
logger_, "Set color AE ROI to "
|
||||
<< "[Left: " << config.x0_left << ", Right: " << config.x1_right
|
||||
<< ", Top: " << config.y0_top << ", Bottom: " << config.y1_bottom << " ]");
|
||||
<< ", Top: " << config.y0_top << ", Bottom: " << config.y1_bottom << "]");
|
||||
break;
|
||||
default:
|
||||
RCLCPP_ERROR(logger_, "%s NOT a video stream", __FUNCTION__);
|
||||
@@ -591,7 +766,7 @@ void OBCameraNode::setAeRoiCallback(const std::shared_ptr<SetArrays ::Request>&
|
||||
response->success = true;
|
||||
} catch (const ob::Error& e) {
|
||||
response->success = false;
|
||||
response->message = e.getMessage();
|
||||
response->message = orbbec_camera::formatObErrorWithStatus(e);
|
||||
} catch (const std::exception& e) {
|
||||
response->success = false;
|
||||
response->message = e.what();
|
||||
@@ -609,7 +784,7 @@ void OBCameraNode::getWhiteBalanceCallback(const std::shared_ptr<GetInt32::Reque
|
||||
response->success = true;
|
||||
} catch (const ob::Error& e) {
|
||||
response->success = false;
|
||||
response->message = e.getMessage();
|
||||
response->message = orbbec_camera::formatObErrorWithStatus(e);
|
||||
} catch (const std::exception& e) {
|
||||
response->success = false;
|
||||
response->message = e.what();
|
||||
@@ -625,13 +800,13 @@ void OBCameraNode::setWhiteBalanceCallback(const std::shared_ptr<SetInt32 ::Requ
|
||||
auto range = device_->getIntPropertyRange(OB_PROP_COLOR_WHITE_BALANCE_INT);
|
||||
if (request->data < range.min || request->data > range.max) {
|
||||
response->success = false;
|
||||
RCLCPP_INFO_STREAM(logger_, "set white balance value out of range");
|
||||
RCLCPP_WARN_STREAM(logger_, "White balance value is out of range");
|
||||
response->message = "value out of range";
|
||||
return;
|
||||
}
|
||||
bool auto_white_balance = device_->getBoolProperty(OB_PROP_COLOR_AUTO_WHITE_BALANCE_BOOL);
|
||||
if (auto_white_balance) {
|
||||
RCLCPP_WARN(logger_, "auto white balance is enabled, set white balance will be ignored");
|
||||
RCLCPP_WARN(logger_, "Auto white balance is enabled, set white balance will be ignored");
|
||||
response->success = false;
|
||||
response->message = "auto white balance is enabled";
|
||||
return;
|
||||
@@ -639,7 +814,7 @@ void OBCameraNode::setWhiteBalanceCallback(const std::shared_ptr<SetInt32 ::Requ
|
||||
device_->setIntProperty(OB_PROP_COLOR_WHITE_BALANCE_INT, request->data);
|
||||
response->success = true;
|
||||
} catch (const ob::Error& e) {
|
||||
response->message = e.getMessage();
|
||||
response->message = orbbec_camera::formatObErrorWithStatus(e);
|
||||
} catch (const std::exception& e) {
|
||||
response->message = e.what();
|
||||
response->success = false;
|
||||
@@ -657,7 +832,7 @@ void OBCameraNode::getAutoWhiteBalanceCallback(const std::shared_ptr<GetInt32::R
|
||||
response->success = true;
|
||||
} catch (const ob::Error& e) {
|
||||
response->success = false;
|
||||
response->message = e.getMessage();
|
||||
response->message = orbbec_camera::formatObErrorWithStatus(e);
|
||||
} catch (const std::exception& e) {
|
||||
response->message = e.what();
|
||||
} catch (...) {
|
||||
@@ -673,7 +848,7 @@ void OBCameraNode::setAutoWhiteBalanceCallback(const std::shared_ptr<SetBool::Re
|
||||
response->success = true;
|
||||
} catch (const ob::Error& e) {
|
||||
response->success = false;
|
||||
response->message = e.getMessage();
|
||||
response->message = orbbec_camera::formatObErrorWithStatus(e);
|
||||
} catch (const std::exception& e) {
|
||||
response->message = e.what();
|
||||
} catch (...) {
|
||||
@@ -712,7 +887,7 @@ void OBCameraNode::setAutoExposureCallback(
|
||||
auto range = device_->getIntPropertyRange(prop_id);
|
||||
if (request->data < range.min || request->data > range.max) {
|
||||
response->success = false;
|
||||
RCLCPP_INFO_STREAM(logger_, "set auto exposure value out of range");
|
||||
RCLCPP_WARN_STREAM(logger_, "Auto exposure value is out of range");
|
||||
response->message = "value out of range";
|
||||
return;
|
||||
}
|
||||
@@ -720,7 +895,7 @@ void OBCameraNode::setAutoExposureCallback(
|
||||
response->success = true;
|
||||
} catch (const ob::Error& e) {
|
||||
response->success = false;
|
||||
response->message = e.getMessage();
|
||||
response->message = orbbec_camera::formatObErrorWithStatus(e);
|
||||
} catch (const std::exception& e) {
|
||||
response->message = e.what();
|
||||
} catch (...) {
|
||||
@@ -738,7 +913,7 @@ void OBCameraNode::setFanWorkModeCallback(const std::shared_ptr<SetInt32::Reques
|
||||
response->success = true;
|
||||
} catch (const ob::Error& e) {
|
||||
response->success = false;
|
||||
response->message = e.getMessage();
|
||||
response->message = orbbec_camera::formatObErrorWithStatus(e);
|
||||
} catch (const std::exception& e) {
|
||||
response->success = false;
|
||||
response->message = e.what();
|
||||
@@ -760,7 +935,7 @@ void OBCameraNode::setFloorEnableCallback(
|
||||
response->success = true;
|
||||
} catch (const ob::Error& e) {
|
||||
response->success = false;
|
||||
response->message = e.getMessage();
|
||||
response->message = orbbec_camera::formatObErrorWithStatus(e);
|
||||
} catch (const std::exception& e) {
|
||||
response->success = false;
|
||||
response->message = e.what();
|
||||
@@ -785,7 +960,7 @@ void OBCameraNode::setLaserEnableCallback(
|
||||
}
|
||||
response->success = true;
|
||||
} catch (const ob::Error& e) {
|
||||
response->message = e.getMessage();
|
||||
response->message = orbbec_camera::formatObErrorWithStatus(e);
|
||||
response->success = false;
|
||||
} catch (const std::exception& e) {
|
||||
response->message = e.what();
|
||||
@@ -821,7 +996,7 @@ void OBCameraNode::setLdpEnableCallback(
|
||||
response->success = true;
|
||||
} catch (const ob::Error& e) {
|
||||
response->success = false;
|
||||
response->message = e.getMessage();
|
||||
response->message = orbbec_camera::formatObErrorWithStatus(e);
|
||||
} catch (const std::exception& e) {
|
||||
response->success = false;
|
||||
response->message = e.what();
|
||||
@@ -857,7 +1032,7 @@ void OBCameraNode::getExposureCallback(const std::shared_ptr<GetInt32::Request>&
|
||||
}
|
||||
response->success = true;
|
||||
} catch (const ob::Error& e) {
|
||||
response->message = e.getMessage();
|
||||
response->message = orbbec_camera::formatObErrorWithStatus(e);
|
||||
response->success = false;
|
||||
} catch (const std::exception& e) {
|
||||
response->message = e.what();
|
||||
@@ -882,7 +1057,7 @@ void OBCameraNode::getDeviceInfoCallback(const std::shared_ptr<GetDeviceInfo::Re
|
||||
response->success = true;
|
||||
} catch (const ob::Error& e) {
|
||||
response->success = false;
|
||||
response->message = e.getMessage();
|
||||
response->message = orbbec_camera::formatObErrorWithStatus(e);
|
||||
} catch (const std::exception& e) {
|
||||
response->success = false;
|
||||
response->message = e.what();
|
||||
@@ -906,7 +1081,7 @@ void OBCameraNode::getSDKVersion(const std::shared_ptr<GetString::Request>& requ
|
||||
response->success = true;
|
||||
} catch (const ob::Error& e) {
|
||||
response->success = false;
|
||||
response->message = e.getMessage();
|
||||
response->message = orbbec_camera::formatObErrorWithStatus(e);
|
||||
} catch (const std::exception& e) {
|
||||
response->success = false;
|
||||
response->message = e.what();
|
||||
@@ -948,7 +1123,7 @@ void OBCameraNode::setMirrorCallback(const std::shared_ptr<SetBool::Request>& re
|
||||
}
|
||||
response->success = true;
|
||||
} catch (const ob::Error& e) {
|
||||
response->message = e.getMessage();
|
||||
response->message = orbbec_camera::formatObErrorWithStatus(e);
|
||||
response->success = false;
|
||||
} catch (const std::exception& e) {
|
||||
response->message = e.what();
|
||||
@@ -993,7 +1168,7 @@ void OBCameraNode::setFlipCallback(const std::shared_ptr<SetBool::Request>& requ
|
||||
}
|
||||
response->success = true;
|
||||
} catch (const ob::Error& e) {
|
||||
response->message = e.getMessage();
|
||||
response->message = orbbec_camera::formatObErrorWithStatus(e);
|
||||
response->success = false;
|
||||
} catch (const std::exception& e) {
|
||||
response->message = e.what();
|
||||
@@ -1038,7 +1213,7 @@ void OBCameraNode::setRotationCallback(const std::shared_ptr<SetInt32::Request>&
|
||||
}
|
||||
response->success = true;
|
||||
} catch (const ob::Error& e) {
|
||||
response->message = e.getMessage();
|
||||
response->message = orbbec_camera::formatObErrorWithStatus(e);
|
||||
response->success = false;
|
||||
} catch (const std::exception& e) {
|
||||
response->message = e.what();
|
||||
@@ -1056,7 +1231,7 @@ void OBCameraNode::getLdpStatusCallback(const std::shared_ptr<GetBool::Request>&
|
||||
response->data = device_->getBoolProperty(OB_PROP_LDP_STATUS_BOOL);
|
||||
response->success = true;
|
||||
} catch (const ob::Error& e) {
|
||||
response->message = e.getMessage();
|
||||
response->message = orbbec_camera::formatObErrorWithStatus(e);
|
||||
response->success = false;
|
||||
} catch (const std::exception& e) {
|
||||
response->message = e.what();
|
||||
@@ -1078,7 +1253,7 @@ void OBCameraNode::getLaserStatusCallback(const std::shared_ptr<GetBool::Request
|
||||
}
|
||||
response->success = true;
|
||||
} catch (const ob::Error& e) {
|
||||
response->message = e.getMessage();
|
||||
response->message = orbbec_camera::formatObErrorWithStatus(e);
|
||||
response->success = false;
|
||||
} catch (const std::exception& e) {
|
||||
response->message = e.what();
|
||||
@@ -1099,14 +1274,14 @@ void OBCameraNode::setPtpConfigCallback(
|
||||
if (!device_->isPropertySupported(OB_DEVICE_PTP_CLOCK_SYNC_ENABLE_BOOL,
|
||||
OB_PERMISSION_READ_WRITE)) {
|
||||
response->success = false;
|
||||
RCLCPP_ERROR(logger_, "OB_DEVICE_PTP_CLOCK_SYNC_ENABLE_BOOL not supported or not writable");
|
||||
RCLCPP_ERROR(logger_, "PTP clock sync property is not supported or not writable");
|
||||
return;
|
||||
}
|
||||
device_->setBoolProperty(OB_DEVICE_PTP_CLOCK_SYNC_ENABLE_BOOL, request->data);
|
||||
response->success = true;
|
||||
} catch (const ob::Error& e) {
|
||||
response->success = false;
|
||||
response->message = e.getMessage();
|
||||
response->message = orbbec_camera::formatObErrorWithStatus(e);
|
||||
} catch (const std::exception& e) {
|
||||
response->success = false;
|
||||
response->message = e.what();
|
||||
@@ -1123,7 +1298,7 @@ void OBCameraNode::getPtpConfigCallback(const std::shared_ptr<GetBool::Request>&
|
||||
response->data = device_->getBoolProperty(OB_DEVICE_PTP_CLOCK_SYNC_ENABLE_BOOL);
|
||||
response->success = true;
|
||||
} catch (const ob::Error& e) {
|
||||
response->message = e.getMessage();
|
||||
response->message = orbbec_camera::formatObErrorWithStatus(e);
|
||||
response->success = false;
|
||||
} catch (const std::exception& e) {
|
||||
response->message = e.what();
|
||||
@@ -1141,7 +1316,7 @@ void OBCameraNode::getLrmMeasureDistanceCallback(const std::shared_ptr<GetInt32:
|
||||
response->data = device_->getIntProperty(OB_PROP_LDP_MEASURE_DISTANCE_INT);
|
||||
response->success = true;
|
||||
} catch (const ob::Error& e) {
|
||||
response->message = e.getMessage();
|
||||
response->message = orbbec_camera::formatObErrorWithStatus(e);
|
||||
response->success = false;
|
||||
} catch (const std::exception& e) {
|
||||
response->message = e.what();
|
||||
@@ -1158,18 +1333,19 @@ void OBCameraNode::toggleSensorCallback(const std::shared_ptr<SetBool::Request>&
|
||||
std::string msg;
|
||||
if (request->data) {
|
||||
if (enable_stream_[stream_index]) {
|
||||
msg = stream_name_[stream_index] + " Already ON";
|
||||
msg = stream_name_[stream_index] + " is already enabled";
|
||||
}
|
||||
RCLCPP_INFO_STREAM(logger_, "toggling sensor " << stream_name_[stream_index] << " ON");
|
||||
RCLCPP_INFO_STREAM(logger_, "Request to set sensor " << stream_name_[stream_index] << " to ON");
|
||||
|
||||
} else {
|
||||
if (!enable_stream_[stream_index]) {
|
||||
msg = stream_name_[stream_index] + " Already OFF";
|
||||
msg = stream_name_[stream_index] + " is already disabled";
|
||||
}
|
||||
RCLCPP_INFO_STREAM(logger_, "toggling sensor " << stream_name_[stream_index] << " OFF");
|
||||
RCLCPP_INFO_STREAM(logger_,
|
||||
"Request to set sensor " << stream_name_[stream_index] << " to OFF");
|
||||
}
|
||||
if (!msg.empty()) {
|
||||
RCLCPP_ERROR_STREAM(logger_, msg);
|
||||
RCLCPP_WARN_STREAM(logger_, msg);
|
||||
response->success = true;
|
||||
response->message = msg;
|
||||
return;
|
||||
@@ -1187,7 +1363,7 @@ bool OBCameraNode::toggleSensor(const stream_index_pair& stream_index, bool enab
|
||||
startStreams();
|
||||
return true;
|
||||
} catch (const ob::Error& e) {
|
||||
msg = e.getMessage();
|
||||
msg = orbbec_camera::formatObErrorWithStatus(e);
|
||||
return false;
|
||||
} catch (const std::exception& e) {
|
||||
msg = e.what();
|
||||
@@ -1236,7 +1412,7 @@ void OBCameraNode::switchIRCameraCallback(const std::shared_ptr<SetString::Reque
|
||||
response->success = true;
|
||||
return;
|
||||
} catch (const ob::Error& e) {
|
||||
response->message = e.getMessage();
|
||||
response->message = orbbec_camera::formatObErrorWithStatus(e);
|
||||
response->success = false;
|
||||
} catch (const std::exception& e) {
|
||||
response->message = e.what();
|
||||
@@ -1253,7 +1429,7 @@ void OBCameraNode::setIRLongExposureCallback(
|
||||
device_->setBoolProperty(OB_PROP_IR_LONG_EXPOSURE_BOOL, request->data);
|
||||
response->success = true;
|
||||
} catch (const ob::Error& e) {
|
||||
response->message = e.getMessage();
|
||||
response->message = orbbec_camera::formatObErrorWithStatus(e);
|
||||
response->success = false;
|
||||
} catch (const std::exception& e) {
|
||||
response->message = e.what();
|
||||
@@ -1273,7 +1449,7 @@ void OBCameraNode::setRESETTimestampCallback(
|
||||
device_->setBoolProperty(OB_PROP_TIMER_RESET_SIGNAL_BOOL, true);
|
||||
response->success = true;
|
||||
} catch (const ob::Error& e) {
|
||||
response->message = e.getMessage();
|
||||
response->message = orbbec_camera::formatObErrorWithStatus(e);
|
||||
response->success = false;
|
||||
} catch (const std::exception& e) {
|
||||
response->message = e.what();
|
||||
@@ -1291,7 +1467,7 @@ void OBCameraNode::setSYNCInterleaveLaserCallback(
|
||||
device_->setIntProperty(OB_PROP_FRAME_INTERLEAVE_LASER_PATTERN_SYNC_DELAY_INT, request->data);
|
||||
response->success = true;
|
||||
} catch (const ob::Error& e) {
|
||||
response->message = e.getMessage();
|
||||
response->message = orbbec_camera::formatObErrorWithStatus(e);
|
||||
response->success = false;
|
||||
} catch (const std::exception& e) {
|
||||
response->message = e.what();
|
||||
@@ -1309,7 +1485,7 @@ void OBCameraNode::setSYNCHostimeCallback(
|
||||
device_->timerSyncWithHost();
|
||||
response->success = true;
|
||||
} catch (const ob::Error& e) {
|
||||
response->message = e.getMessage();
|
||||
response->message = orbbec_camera::formatObErrorWithStatus(e);
|
||||
response->success = false;
|
||||
} catch (const std::exception& e) {
|
||||
response->message = e.what();
|
||||
@@ -1329,7 +1505,7 @@ void OBCameraNode::sendSoftwareTriggerCallback(
|
||||
}
|
||||
response->success = true;
|
||||
} catch (const ob::Error& e) {
|
||||
response->message = e.getMessage();
|
||||
response->message = orbbec_camera::formatObErrorWithStatus(e);
|
||||
response->success = false;
|
||||
} catch (const std::exception& e) {
|
||||
response->message = e.what();
|
||||
@@ -1477,35 +1653,36 @@ void OBCameraNode::getUserCalibParamsCallback(
|
||||
response->message = "exception occurred";
|
||||
}
|
||||
}
|
||||
void OBCameraNode::setAEModeCallback(const std::shared_ptr<SetString::Request>& request,
|
||||
std::shared_ptr<SetString::Response>& response) {
|
||||
void OBCameraNode::setAEReferenceStreamCallback(const std::shared_ptr<SetString::Request>& request,
|
||||
std::shared_ptr<SetString::Response>& response) {
|
||||
try {
|
||||
if (device_->isPropertySupported(OB_PROP_DEVICE_AE_REFERENCE_INT, OB_PERMISSION_WRITE) &&
|
||||
(request->data == "depthbased" || request->data == "colorbased")) {
|
||||
device_->setIntProperty(OB_PROP_DEVICE_AE_REFERENCE_INT,
|
||||
request->data == "depthbased" ? 0 : 1);
|
||||
ae_mode_ = request->data;
|
||||
(request->data == "depth" || request->data == "color")) {
|
||||
device_->setIntProperty(OB_PROP_DEVICE_AE_REFERENCE_INT, request->data == "depth" ? 0 : 1);
|
||||
ae_reference_stream_ = request->data;
|
||||
response->success = true;
|
||||
response->message = "set AE mode success";
|
||||
response->message = "set AE reference stream success";
|
||||
} else {
|
||||
response->success = false;
|
||||
response->message = "set AE mode failed";
|
||||
response->message = "set AE reference stream failed";
|
||||
}
|
||||
} catch (...) {
|
||||
response->success = false;
|
||||
response->message = "exception occurred";
|
||||
}
|
||||
}
|
||||
void OBCameraNode::setSportsModeCallback(const std::shared_ptr<SetBool::Request>& request,
|
||||
std::shared_ptr<SetBool::Response>& response) {
|
||||
void OBCameraNode::setAEStrategyCallback(const std::shared_ptr<SetString::Request>& request,
|
||||
std::shared_ptr<SetString::Response>& response) {
|
||||
try {
|
||||
if (device_->isPropertySupported(OB_PROP_DEVICE_AE_STRATEGY_INT, OB_PERMISSION_WRITE)) {
|
||||
device_->setIntProperty(OB_PROP_DEVICE_AE_STRATEGY_INT, request->data ? 1 : 0);
|
||||
if (device_->isPropertySupported(OB_PROP_DEVICE_AE_STRATEGY_INT, OB_PERMISSION_WRITE) &&
|
||||
(request->data == "default" || request->data == "motion")) {
|
||||
device_->setIntProperty(OB_PROP_DEVICE_AE_STRATEGY_INT, request->data == "motion" ? 1 : 0);
|
||||
ae_strategy_ = request->data;
|
||||
response->success = true;
|
||||
response->message = "set sports mode success";
|
||||
response->message = "set AE strategy success";
|
||||
} else {
|
||||
response->success = false;
|
||||
response->message = "set sports mode failed";
|
||||
response->message = "set AE strategy failed";
|
||||
}
|
||||
} catch (...) {
|
||||
response->success = false;
|
||||
|
||||
@@ -540,6 +540,38 @@ float depthPrecisionFromString(const std::string &depth_precision_level_str) {
|
||||
return std::stof(depth_precision_level_str_num);
|
||||
}
|
||||
|
||||
std::string colorPowerLineFrequencyToString(int value) {
|
||||
switch (value) {
|
||||
case 0:
|
||||
return "disable";
|
||||
case 1:
|
||||
return "50hz";
|
||||
case 2:
|
||||
return "60hz";
|
||||
case 3:
|
||||
return "auto";
|
||||
default:
|
||||
return "unknown";
|
||||
}
|
||||
}
|
||||
|
||||
std::string depthPrecisionLevelToString(int value) {
|
||||
switch (static_cast<OB_DEPTH_PRECISION_LEVEL>(value)) {
|
||||
case OB_PRECISION_1MM:
|
||||
return "1mm";
|
||||
case OB_PRECISION_0MM8:
|
||||
return "0.8mm";
|
||||
case OB_PRECISION_0MM4:
|
||||
return "0.4mm";
|
||||
case OB_PRECISION_0MM2:
|
||||
return "0.2mm";
|
||||
case OB_PRECISION_0MM1:
|
||||
return "0.1mm";
|
||||
default:
|
||||
return "unknown";
|
||||
}
|
||||
}
|
||||
|
||||
OBMultiDeviceSyncMode OBSyncModeFromString(const std::string &mode) {
|
||||
if (mode == "FREE_RUN") {
|
||||
return OBMultiDeviceSyncMode::OB_MULTI_DEVICE_SYNC_MODE_FREE_RUN;
|
||||
@@ -560,6 +592,43 @@ OBMultiDeviceSyncMode OBSyncModeFromString(const std::string &mode) {
|
||||
}
|
||||
}
|
||||
|
||||
std::string disparityRangeModeToString(int value) {
|
||||
switch (value) {
|
||||
case 0:
|
||||
return "64";
|
||||
case 1:
|
||||
return "128";
|
||||
case 2:
|
||||
return "256";
|
||||
default:
|
||||
return "unknown";
|
||||
}
|
||||
}
|
||||
|
||||
std::string exposureRangeModeToString(int value) {
|
||||
switch (value) {
|
||||
case 0:
|
||||
return "regular";
|
||||
case 1:
|
||||
return "ultimate";
|
||||
default:
|
||||
return "unknown";
|
||||
}
|
||||
}
|
||||
|
||||
std::string intraCameraSyncReferenceToString(int value) {
|
||||
switch (value) {
|
||||
case 0:
|
||||
return "Start";
|
||||
case 1:
|
||||
return "Middle";
|
||||
case 2:
|
||||
return "End";
|
||||
default:
|
||||
return "unknown";
|
||||
}
|
||||
}
|
||||
|
||||
OB_SAMPLE_RATE sampleRateFromString(std::string &sample_rate) {
|
||||
// covert to lower case
|
||||
std::transform(sample_rate.begin(), sample_rate.end(), sample_rate.begin(), ::tolower);
|
||||
@@ -941,16 +1010,17 @@ UndistortedImageResult undistortImage(const cv::Mat &image, const OBCameraIntrin
|
||||
cv::Mat dist_coeffs = (cv::Mat_<float>(8, 1) << distortion.k1, distortion.k2, distortion.p1,
|
||||
distortion.p2, distortion.k3, distortion.k4, distortion.k5, distortion.k6);
|
||||
cv::Size image_size(image.cols, image.rows);
|
||||
cv::Mat new_camera_matrix =
|
||||
cv::getOptimalNewCameraMatrix(camera_matrix, dist_coeffs, image_size, 0.0, image_size);
|
||||
// cv::Mat new_camera_matrix =
|
||||
// cv::getOptimalNewCameraMatrix(camera_matrix, dist_coeffs, image_size, 0.0, image_size);
|
||||
// Undistort the image using the new camera matrix
|
||||
cv::undistort(image, result.image, camera_matrix, dist_coeffs, new_camera_matrix);
|
||||
// cv::undistort(image, result.image, camera_matrix, dist_coeffs, new_camera_matrix);
|
||||
cv::undistort(image, result.image, camera_matrix, dist_coeffs);
|
||||
// Update the intrinsic parameters with the new camera matrix
|
||||
result.new_intrinsic = intrinsic; // Copy original values first
|
||||
result.new_intrinsic.fx = new_camera_matrix.at<double>(0, 0);
|
||||
result.new_intrinsic.fy = new_camera_matrix.at<double>(1, 1);
|
||||
result.new_intrinsic.cx = new_camera_matrix.at<double>(0, 2);
|
||||
result.new_intrinsic.cy = new_camera_matrix.at<double>(1, 2);
|
||||
// result.new_intrinsic.fx = new_camera_matrix.at<double>(0, 0);
|
||||
// result.new_intrinsic.fy = new_camera_matrix.at<double>(1, 1);
|
||||
// result.new_intrinsic.cx = new_camera_matrix.at<double>(0, 2);
|
||||
// result.new_intrinsic.cy = new_camera_matrix.at<double>(1, 2);
|
||||
result.new_intrinsic.width = image.cols;
|
||||
result.new_intrinsic.height = image.rows;
|
||||
return result;
|
||||
|
||||
Reference in New Issue
Block a user