Merge branch 'merge/ros_2.9.3' into v2/develop

This commit is contained in:
ob-yalian
2026-07-17 09:45:59 +08:00
58 changed files with 2234 additions and 552 deletions
@@ -78,6 +78,20 @@ typedef enum {
*/
OB_EXPORT ob_application_config *ob_device_get_application_config(ob_device *device, ob_error **error);
/**
* @brief Get the application configuration carried by an externally imported preset, by preset name.
*
* @param[in] device The device object.
* @param[in] preset_name The preset name to query.
* @param[out] error Pointer to an error object that will be set if an error occurs.
*
* @return ob_application_config* The application configuration imported with the given preset, or NULL for
* built-in presets or presets that carry no application configuration.
* @attention The returned config is owned by the device; it should still be released by calling
* @ref ob_delete_application_config (releasing the handle does not destroy the cached object).
*/
OB_EXPORT ob_application_config *ob_device_get_application_config_by_preset(ob_device *device, const char *preset_name, ob_error **error);
/**
* @brief Delete an application configuration object.
*
@@ -163,6 +163,76 @@ OB_EXPORT void ob_device_set_structured_data(ob_device *device, ob_property_id p
*/
OB_EXPORT void ob_device_get_structured_data(ob_device *device, ob_property_id property_id, uint8_t *data, uint32_t *data_size, ob_error **error);
/**
* @brief Check whether the device supports license authorization.
*
* This function only reports whether the device provides the license authorization
* capability. It does not read or validate the license information.
*
* @param[in] device The device object.
* @param[out] error Log error messages.
* @return true if the device supports license authorization, false otherwise.
*/
OB_EXPORT bool ob_device_is_license_authorization_supported(const ob_device *device, ob_error **error);
/**
* @brief Write signed device license information.
*
* The license_info_json is a UTF-8 JSON string with the following structure. All
* binary fields are lowercase hex strings without a "0x" prefix and with a fixed
* length. Before writing, the SDK reads the currently connected device and compares
* it against "devInfo" to prevent writing a license to the wrong device; it does NOT
* verify the signature or recompute deviceHash (signature and device-binding checks
* are performed by the consumer/filter at runtime).
*
* {
* "formatVersion": 1, // license_info envelope version
* "devInfo": { // plaintext, NOT signed; used only to
* "deviceSn": "SN123456789", // guard against mis-writing to the
* "vid": "2BC5", // wrong device. vid/pid are 4-char
* "pid": "0660" // uppercase hex.
* },
* "licenseInfo": { // signed authorization credential
* "schemaVersion": 1, // credential schema version
* "keyVersion": 1, // 16-bit signing public key id
* "featureFlags": "0000000000000001",// 8 bytes, 16-char lowercase hex
* "expireDate": 4294967295, // YYYYMMDD; 0xFFFFFFFF = permanent
* "deviceHash": "00112233445566778899aabbccddeeff", // 16 bytes, 32-char hex
* "signature": "...", // ECDSA P-256 r||s, 64 bytes, 128-char hex
* "vendorLicense": "..." // third-party vendor blob, lowercase hex (235 bytes)
* }
* }
*
* @param[in] device The device object.
* @param[in] license_info_json The SDK license_info JSON string described above.
* @param[in] license_info_json_size The byte size of license_info_json, excluding any trailing null terminator.
* @param[out] error Pointer to an error object that will be set if an error occurs.
*/
OB_EXPORT void ob_device_write_license_info(ob_device *device, const char *license_info_json, uint32_t license_info_json_size, ob_error **error);
/**
* @brief Read signed device license information as SDK license_info JSON.
*
* @param[in] device The device object.
* @param[out] license_info_json The output buffer for SDK license_info JSON, null-terminated on success.
* @param[in] license_info_json_size Size of the output buffer in bytes. Must be large enough to hold the JSON string and a trailing null terminator; 512
* bytes is sufficient for the current schema.
* @param[out] error Pointer to an error object that will be set if an error occurs.
*/
OB_EXPORT void ob_device_read_license_info(const ob_device *device, char *license_info_json, uint32_t license_info_json_size, ob_error **error);
/**
* @brief Clear license information stored on the device.
*
* Erases the device license storage area so that the device returns to the
* "no license" state. Intended for internal repair, re-activation or debugging
* builds and should be gated by caller-side confirmation.
*
* @param[in] device The device object.
* @param[out] error Pointer to an error object that will be set if an error occurs.
*/
OB_EXPORT void ob_device_clear_license_info(ob_device *device, ob_error **error);
/**
* @brief Get raw data of a device property.
*
@@ -286,6 +356,19 @@ OB_EXPORT void ob_device_update_firmware_from_data(ob_device *device, const uint
OB_EXPORT void ob_device_update_optional_depth_presets(ob_device *device, const char file_path_list[][OB_PATH_MAX], uint8_t path_count,
ob_device_fw_update_callback callback, void *user_data, ob_error **error);
/**
* @brief Update the device optional depth presets from data loaded in memory.
*
* @param[in] device The device object.
* @param[in] data_list A list of preset data blocks, each holding a data pointer and its size.
* @param[in] count The number of the preset data blocks.
* @param[in] callback The preset upgrade progress callback.
* @param[in] user_data User-defined data that will be returned in the callback.
* @param[out] error Pointer to an error object that will be set if an error occurs.
*/
OB_EXPORT void ob_device_update_optional_depth_presets_from_data(ob_device *device, const ob_data_view *data_list, uint8_t count,
ob_device_fw_update_callback callback, void *user_data, ob_error **error);
/**
* @brief Device reboot
* @attention The device will be disconnected and reconnected. After the device is disconnected, the interface access to the device handle may be abnormal.
@@ -337,6 +420,16 @@ OB_EXPORT void ob_device_enable_heartbeat(ob_device *device, bool enable, ob_err
*/
OB_EXPORT void ob_device_enable_firmware_log(ob_device *device, bool enable, ob_error **error);
/**
* @brief Check whether the device firmware log is enabled.
*
* @param[in] device The device object.
* @param[out] error Pointer to an error object that will be set if an error occurs.
*
* @return bool Whether the firmware log is enabled.
*/
OB_EXPORT bool ob_device_is_firmware_log_enabled(ob_device *device, ob_error **error);
/**
* @brief Synchronize the device time (synchronize hardwarePPS time to device)
*
@@ -426,7 +519,7 @@ OB_EXPORT const char *ob_device_info_get_uid(const ob_device_info *info, ob_erro
*
* @param[in] info Device Information
* @param[out] error Pointer to an error object that will be set if an error occurs.
*
*
* @return const char* return device serial number
*/
OB_EXPORT const char *ob_device_info_get_serial_number(const ob_device_info *info, ob_error **error);
@@ -436,7 +529,7 @@ OB_EXPORT const char *ob_device_info_get_serial_number(const ob_device_info *inf
*
* @param[in] info Device Information
* @param[out] error Pointer to an error object that will be set if an error occurs.
*
*
* @return int return the firmware version number
*/
OB_EXPORT const char *ob_device_info_get_firmware_version(const ob_device_info *info, ob_error **error);
@@ -458,7 +551,7 @@ OB_EXPORT const char *ob_device_info_get_connection_type(const ob_device_info *i
*
* @param[in] info Device Information
* @param[out] error Pointer to an error object that will be set if an error occurs.
*
*
* @return const char* The IP address, such as "192.168.1.10"
*/
OB_EXPORT const char *ob_device_info_get_ip_address(const ob_device_info *info, ob_error **error);
@@ -520,7 +613,7 @@ OB_EXPORT const char *ob_device_get_extension_info(const ob_device *device, cons
*
* @param[in] info Device Information
* @param[out] error Pointer to an error object that will be set if an error occurs.
*
*
* @return const char* The minimum SDK version number supported by the device
*/
OB_EXPORT const char *ob_device_info_get_supported_min_sdk_version(const ob_device_info *info, ob_error **error);
@@ -530,7 +623,7 @@ OB_EXPORT const char *ob_device_info_get_supported_min_sdk_version(const ob_devi
*
* @param[in] info Device Information
* @param[out] error Pointer to an error object that will be set if an error occurs.
*
*
* @return const char* The ASIC name
*/
OB_EXPORT const char *ob_device_info_get_asicName(const ob_device_info *info, ob_error **error);
@@ -540,7 +633,7 @@ OB_EXPORT const char *ob_device_info_get_asicName(const ob_device_info *info, ob
*
* @param[in] info Device Information
* @param[out] error Pointer to an error object that will be set if an error occurs.
*
*
* @return ob_device_type The device type
*/
OB_EXPORT ob_device_type ob_device_info_get_device_type(const ob_device_info *info, ob_error **error);
@@ -558,7 +651,7 @@ OB_EXPORT void ob_delete_device_list(ob_device_list *list, ob_error **error);
*
* @param[in] list Device list object
* @param[out] error Pointer to an error object that will be set if an error occurs.
*
*
* @return uint32_t return the number of devices
*/
OB_EXPORT uint32_t ob_device_list_get_count(const ob_device_list *list, ob_error **error);
@@ -569,7 +662,7 @@ OB_EXPORT uint32_t ob_device_list_get_count(const ob_device_list *list, ob_error
* @param[in] list Device list object
* @param[in] index Device index
* @param[out] error Pointer to an error object that will be set if an error occurs.
*
*
* @return const char* return device name
*/
OB_EXPORT const char *ob_device_list_get_device_name(const ob_device_list *list, uint32_t index, ob_error **error);
@@ -580,7 +673,7 @@ OB_EXPORT const char *ob_device_list_get_device_name(const ob_device_list *list,
* @param[in] list Device list object
* @param[in] index Device index
* @param[out] error Pointer to an error object that will be set if an error occurs.
*
*
* @return int return the device pid
*/
OB_EXPORT int ob_device_list_get_device_pid(const ob_device_list *list, uint32_t index, ob_error **error);
@@ -763,6 +856,46 @@ OB_EXPORT ob_ip_source_type ob_device_list_get_device_ip_source_type(const ob_de
*/
OB_EXPORT const char *ob_device_list_get_device_user_name(const ob_device_list *list, uint32_t index, ob_error **error);
/**
* @brief Query the current device access state without opening the device.
*
* @attention This is a non-invasive GVCP CCP query for supported Ethernet devices. It reports device-side CCP state, not the owner process or host.
* For non-Ethernet devices or Ethernet devices without CCP support, it returns OB_DEVICE_ACCESS_STATE_UNSUPPORTED.
* CONTROLLED means monitor access may still be available, while default/control access may still fail.
* This call is synchronous and blocks while waiting for the device's GVCP response over the network; querying an unreachable device blocks until the
* underlying retry logic gives up, so prefer calling it off the UI thread when querying multiple devices.
* The returned state reflects the device access state only at the moment of the query and does not guarantee that a subsequent access (such as creating or
* opening the device) will succeed, as another client may change the state in between.
*
* @param[in] list Device list object.
* @param[in] index The index of the device.
* @param[out] error Pointer to an error object that will be set if an error occurs.
*
* @return The current access state of the device.
*/
OB_EXPORT ob_device_access_state ob_device_list_query_device_access_state(const ob_device_list *list, uint32_t index, ob_error **error);
/**
* @brief Query the current device access state by serial number without opening the device.
*
* @attention This is a non-invasive GVCP CCP query for supported Ethernet devices. It reports device-side CCP state, not the owner process or host.
* For non-Ethernet devices or Ethernet devices without CCP support, it returns OB_DEVICE_ACCESS_STATE_UNSUPPORTED.
* CONTROLLED means monitor access may still be available, while default/control access may still fail.
* This call is synchronous and blocks while waiting for the device's GVCP response over the network; querying an unreachable device blocks until the
* underlying retry logic gives up, so prefer calling it off the UI thread when querying multiple devices.
* The returned state reflects the device access state only at the moment of the query and does not guarantee that a subsequent access (such as creating or
* opening the device) will succeed, as another client may change the state in between.
* If no device in the list matches the given serial number, an error is set via the error parameter.
*
* @param[in] list Device list object.
* @param[in] serial_number The serial number of the device.
* @param[out] error Pointer to an error object that will be set if an error occurs.
*
* @return The current access state of the device.
*/
OB_EXPORT ob_device_access_state ob_device_list_query_device_access_state_by_serial_number(const ob_device_list *list, const char *serial_number,
ob_error **error);
/**
* @brief Create a device.
*
@@ -56,6 +56,16 @@ OB_EXPORT const char *ob_filter_get_vendor_specific_code(const char *name, ob_er
*/
OB_EXPORT ob_filter *ob_create_private_filter(const char *name, const char *activation_key, ob_error **error);
/**
* @brief Activate a private filter object with a specific device.
*
* @param[in] filter The private filter object.
* @param[in] device The device to associate with the activation.
* @param[in] options Optional extensible activation options (may be NULL). See @ref ob_priv_filter_activate_options.
* @param[out] error Pointer to an error object that will be set if an error occurs.
*/
OB_EXPORT void ob_filter_activate_private_ex(ob_filter *filter, ob_device *device, const ob_priv_filter_activate_options *options, ob_error **error);
/**
* @brief Delete the filter.
*
@@ -397,6 +397,35 @@ OB_EXPORT ob_sensor *ob_frame_get_sensor(const ob_frame *frame, ob_error **error
*/
OB_EXPORT ob_device *ob_frame_get_device(const ob_frame *frame, ob_error **error);
/**
* @brief Get the auth token carried by the frame.
*
* @param[in] frame Frame object.
* @param[out] error Pointer to an error object that will be set if an error occurs.
*
* @return uint64_t The auth token value.
*/
OB_EXPORT uint64_t ob_frame_get_token(const ob_frame *frame, ob_error **error);
/**
* @brief Set the auth token carried by the frame.
*
* @param[in] frame Frame object.
* @param[in] token The auth token value.
* @param[out] error Pointer to an error object that will be set if an error occurs.
*/
OB_EXPORT void ob_frame_set_token(ob_frame *frame, uint64_t token, ob_error **error);
/**
* @brief Get the device information attached to the frame.
*
* @param[in] frame Frame object.
* @param[out] error Pointer to an error object that will be set if an error occurs.
*
* @return ob_device_info* Return the attached device information, or NULL if not available.
*/
OB_EXPORT ob_device_info *ob_frame_get_device_info(const ob_frame *frame, ob_error **error);
/**
* @brief Get video frame width
*
@@ -152,6 +152,7 @@ typedef enum {
OB_EXCEPTION_TYPE_INVALID_DATA, /**< Runtime data is invalid, check data content or size */
OB_EXCEPTION_TYPE_NOT_FOUND, /**< The requested item was not found */
OB_EXCEPTION_TYPE_RESOURCE_BUSY, /**< Resource is busy or locked by another operation */
OB_EXCEPTION_TYPE_LICENSE_VERIFY_FAILED, /**< License verification failed, the device/feature license is missing, invalid or expired */
} OBExceptionType,
ob_exception_type;
@@ -384,6 +385,14 @@ typedef struct {
uint32_t fullDataSize; ///< Size of full data
} OBDataChunk, ob_data_chunk;
/**
* @brief A read-only, non-owning view over a byte buffer (a data pointer plus its size)
*/
typedef struct {
const uint8_t *data; ///< Pointer to the data
uint32_t dataSize; ///< Size of the data in bytes
} OBDataView, ob_data_view;
/**
* @brief Structure for integer range
*/
@@ -1727,6 +1736,18 @@ typedef struct {
const char *desc; ///< Description of the configuration item
} OBFilterConfigSchemaItem, ob_filter_config_schema_item;
/**
* @brief Extensible options for activating a private filter instance.
* @brief Passed to @ref ob_filter_activate_private_ex / @ref ob_priv_filter_activate_ex. New fields must only be
* appended at the end. The caller sets @ref struct_size to sizeof(ob_priv_filter_activate_options); the callee
* uses it to detect which fields a (possibly older) caller actually provided, keeping the ABI compatible as the
* struct grows. This is the single extension point for future activation parameters.
*/
typedef struct ob_priv_filter_activate_options {
uint32_t struct_size; ///< Size of this struct in bytes, set by the caller to sizeof(ob_priv_filter_activate_options).
const char *model_path; ///< Path to the inference model file. NULL or empty selects the filter's default model.
}OBPrivFilterActivateOptions, ob_priv_filter_activate_options;
/**
* @brief struct of serial number
*/
@@ -2025,6 +2046,20 @@ typedef enum {
} ob_device_access_mode,
OBDeviceAccessMode;
/**
* @brief Device access state queried from GVCP CCP without opening the device.
*/
typedef enum {
OB_DEVICE_ACCESS_STATE_UNKNOWN = 0, ///< The access state cannot be determined
OB_DEVICE_ACCESS_STATE_UNSUPPORTED = 1, ///< The device or current build does not support access-state query
OB_DEVICE_ACCESS_STATE_AVAILABLE = 2, ///< The device is available for control access
OB_DEVICE_ACCESS_STATE_CONTROLLED = 3, ///< The device has a controller; monitor access may still be available
OB_DEVICE_ACCESS_STATE_EXCLUSIVE = 4, ///< The device is held exclusively and cannot be accessed
OB_DEVICE_ACCESS_STATE_UNREACHABLE = 5, ///< The device did not respond or the network path is unreachable
OB_DEVICE_ACCESS_STATE_FW_NOT_SUPPORTED = 6, ///< The device supports CCP, but the firmware version is too old
} ob_device_access_state,
OBDeviceAccessState;
typedef enum {
OB_IP_SOURCE_NONE = 0, ///< No IP configuration active (e.g. USB device).
OB_IP_SOURCE_LLA = 1, ///< LLA (Link-Local Address / Auto IP).
@@ -672,6 +672,16 @@ typedef enum {
*/
OB_PROP_CURRENT_DISP_SEARCH_OFFSET_INT = 272,
/**
* @brief Enable FPS boost in trigger mode
*/
OB_PROP_FPS_BOOST_BOOL = 275,
/**
* @brief MJPEG encoding quality factor
*/
OB_PROP_MJPEG_QUALITY_INT = 277,
/**
* @brief Baseline calibration parameters
*/
@@ -184,6 +184,20 @@ public:
return std::make_shared<ApplicationConfig>(handle);
}
/**
* @brief Get the application config carried by an externally imported preset, by preset name.
* @return nullptr for built-in presets or presets that carry no application config.
*/
static std::shared_ptr<ApplicationConfig> get(const std::shared_ptr<Device> &device, const std::string &presetName) {
ob_error *error = nullptr;
auto handle = ob_device_get_application_config_by_preset(device->getImpl(), presetName.c_str(), &error);
Error::handle(&error);
if(!handle) {
return nullptr;
}
return std::make_shared<ApplicationConfig>(handle);
}
explicit ApplicationConfig(ob_application_config *handle) : handle_(handle) {}
~ApplicationConfig() noexcept {
@@ -302,6 +302,51 @@ public:
Error::handle(&error);
}
/**
* @brief Check whether the device supports license authorization.
*
* @return true if the device supports license authorization, false otherwise.
*/
bool isLicenseAuthorizationSupported() const {
ob_error *error = nullptr;
auto res = ob_device_is_license_authorization_supported(impl_, &error);
Error::handle(&error);
return res;
}
/**
* @brief Write signed device license information.
*
* @param[in] licenseInfo SDK license_info JSON string
*/
void writeLicenseInfo(const std::string &licenseInfo) const {
ob_error *error = nullptr;
ob_device_write_license_info(impl_, licenseInfo.c_str(), static_cast<uint32_t>(licenseInfo.size()), &error);
Error::handle(&error);
}
/**
* @brief Clear license information stored on the device.
*/
void clearLicenseInfo() const {
ob_error *error = nullptr;
ob_device_clear_license_info(impl_, &error);
Error::handle(&error);
}
/**
* @brief Read signed device license information as SDK license_info JSON.
*
* @return std::string SDK license_info JSON string
*/
std::string readLicenseInfo() const {
ob_error *error = nullptr;
char buf[4096] = {};
ob_device_read_license_info(impl_, buf, sizeof(buf), &error);
Error::handle(&error);
return std::string(buf);
}
/**
* @brief Set the customer data type of a device property
*
@@ -393,6 +438,8 @@ public:
/**
* @brief Update the device firmware
*
* @attention Only one firmware/preset update may run per device at a time
*
* @param[in] filePath Firmware path
* @param[in] callback Firmware Update progress and status callback
* @param[in] async Whether to execute asynchronously
@@ -407,6 +454,8 @@ public:
/**
* @brief Update the device firmware from data
*
* @attention Only one firmware/preset update may run per device at a time
*
* @param[in] firmwareData Firmware data
* @param[in] firmwareDataSize Firmware data size
* @param[in] callback Firmware Update progress and status callback
@@ -422,6 +471,8 @@ public:
/**
* @brief Update the device optional depth presets
*
* @attention Only one firmware/preset update may run per device at a time
*
* @param[in] filePathList A list(2D array) of preset file paths, each up to OB_PATH_MAX characters.
* @param[in] pathCount The number of the preset file paths.
* @param[in] callback Preset update progress and status callback
@@ -433,6 +484,27 @@ public:
Error::handle(&error);
}
/**
* @brief Update the device optional depth presets from data loaded in memory
*
* @attention Only one firmware/preset update may run per device at a time
*
* @param[in] dataList A list of preset data blocks, each holding the raw bytes of one preset.
* @param[in] callback Preset update progress and status callback
*/
void updateOptionalDepthPresets(const std::vector<std::vector<uint8_t>> &dataList, DeviceFwUpdateCallback callback) {
ob_error *error = nullptr;
std::vector<OBDataView> presets;
presets.reserve(dataList.size());
for(const auto &data: dataList) {
presets.push_back({data.data(), static_cast<uint32_t>(data.size())});
}
fwUpdateCallback_ = callback;
auto count = static_cast<uint8_t>(presets.size());
ob_device_update_optional_depth_presets_from_data(impl_, presets.data(), count, &Device::firmwareUpdateCallback, this, &error);
Error::handle(&error);
}
/**
* @brief Set the device state changed callbacks
*
@@ -620,6 +692,18 @@ public:
Error::handle(&error);
}
/**
* @brief Check whether the device firmware log is enabled.
*
* @return bool Whether the firmware log is enabled.
*/
bool isFirmwareLogEnabled() const {
ob_error *error = nullptr;
bool enable = ob_device_is_firmware_log_enabled(impl_, &error);
Error::handle(&error);
return enable;
}
/**
* @brief Get the supported multi device sync mode bitmap of the device.
* @brief For example, if the return value is 0b00001100, it means the device supports @ref OB_MULTI_DEVICE_SYNC_MODE_PRIMARY and @ref
@@ -1449,9 +1533,9 @@ public:
*
* @return const char* The host network interface name (e.g., "eth0", "en0").
*/
const char* getLocalNetInterfaceName(uint32_t index) const {
ob_error *error = nullptr;
auto netItfName = ob_device_list_get_device_local_net_if_name(impl_, index, &error);
const char *getLocalNetInterfaceName(uint32_t index) const {
ob_error *error = nullptr;
auto netItfName = ob_device_list_get_device_local_net_if_name(impl_, index, &error);
Error::handle(&error);
return netItfName;
}
@@ -1488,6 +1572,49 @@ public:
return userName;
}
/**
* @brief Query the current device access state without opening the device.
*
* @attention This is a non-invasive GVCP CCP query for supported Ethernet devices. It reports device-side CCP state, not the owner process or host.
* CONTROLLED means monitor access may still be available, while default/control access may still fail.
* This call is synchronous and blocks while waiting for the device's GVCP response over the network; querying an unreachable device blocks until the
* underlying retry logic gives up, so prefer calling it off the UI thread when querying multiple devices.
* The returned state reflects the device access state only at the moment of the query and does not guarantee that a subsequent access (such as creating
* or opening the device) will succeed, as another client may change the state in between.
*
* @param[in] index The index of the device.
*
* @return OBDeviceAccessState The current access state of the device.
*/
OBDeviceAccessState queryDeviceAccessState(uint32_t index) const {
ob_error *error = nullptr;
auto state = ob_device_list_query_device_access_state(impl_, index, &error);
Error::handle(&error);
return state;
}
/**
* @brief Query the current device access state by serial number without opening the device.
*
* @attention This is a non-invasive GVCP CCP query for supported Ethernet devices. It reports device-side CCP state, not the owner process or host.
* CONTROLLED means monitor access may still be available, while default/control access may still fail.
* This call is synchronous and blocks while waiting for the device's GVCP response over the network; querying an unreachable device blocks until the
* underlying retry logic gives up, so prefer calling it off the UI thread when querying multiple devices.
* The returned state reflects the device access state only at the moment of the query and does not guarantee that a subsequent access (such as creating
* or opening the device) will succeed, as another client may change the state in between.
* If no device in the list matches the given serial number, this throws an ob::Error.
*
* @param[in] serialNumber The serial number of the device.
*
* @return OBDeviceAccessState The current access state of the device.
*/
OBDeviceAccessState queryDeviceAccessStateBySN(const char *serialNumber) const {
ob_error *error = nullptr;
auto state = ob_device_list_query_device_access_state_by_serial_number(impl_, serialNumber, &error);
Error::handle(&error);
return state;
}
/**
* @brief Get the device object at the specified index
*
@@ -22,6 +22,7 @@
#include <typeinfo>
#include <typeindex>
#include <unordered_map>
#include <vector>
#include <cstring>
namespace ob {
@@ -2081,6 +2082,175 @@ public:
~DisparityTransform() noexcept override = default;
};
/**
* @brief Enhanced depth filter that requires a device for activation.
*
* @note The constructor is a template so that Filter.hpp does not need to include Device.hpp.
* The template is instantiated at the call site where the device type is complete.
*/
class EnhancedDepthFilter : public Filter {
public:
/**
* @brief Construct an EnhancedDepthFilter and activate it for the given device.
*
* @param[in] device The device the filter is bound to.
* @param[in] modelPath Optional path to the inference model file used during activation. When empty, the
* filter falls back to its default model file at extensions/filters/enhanced_depth_filter/model.sm4
* (located next to the filter library).
*/
template <typename T> explicit EnhancedDepthFilter(std::shared_ptr<T> device, const std::string &modelPath = "") {
if(!device) {
throw std::invalid_argument("device is null");
}
ob_error *error = nullptr;
auto impl = ob_create_private_filter("EnhancedDepthFilter", "", &error);
Error::handle(&error);
// Only pass options when a model path is provided; otherwise hand down nullptr so the filter uses its default.
ob_priv_filter_activate_options options{};
ob_priv_filter_activate_options *optionsPtr = nullptr;
if(!modelPath.empty()) {
options.struct_size = sizeof(options);
options.model_path = modelPath.c_str();
optionsPtr = &options;
}
ob_filter_activate_private_ex(impl, device->getImpl(), optionsPtr, &error);
Error::handle(&error);
init(impl);
}
~EnhancedDepthFilter() noexcept override = default;
/**
* @brief Get the resolutions supported by the enhanced depth filter for the constrained (aligned-to) stream.
*
* @return The list of supported {width, height} pairs. This is the single source of truth used by
* @ref isSupportedResolution.
*/
static const std::vector<std::pair<uint32_t, uint32_t>> &getSupportedResolutions() {
static const std::vector<std::pair<uint32_t, uint32_t>> supportedResolutions = {
{ 640, 480 },
{ 1280, 720 },
{ 1280, 800 },
};
return supportedResolutions;
}
/**
* @brief Get the frame formats supported by the enhanced depth filter for a given stream type.
*
* @param[in] streamType The stream type. Only color and depth streams are supported.
*
* @return The list of supported formats (color: OB_FORMAT_RGB; depth: OB_FORMAT_Y10, OB_FORMAT_Y11,
* OB_FORMAT_Y12, OB_FORMAT_Y14, OB_FORMAT_Y16, OB_FORMAT_Z16). Empty for unsupported stream types. This is the single
* source of truth used by @ref isSupportedFormat.
*/
static std::vector<OBFormat> getSupportedFormats(OBStreamType streamType) {
if(streamType == OB_STREAM_COLOR) {
return { OB_FORMAT_RGB };
}
if(streamType == OB_STREAM_DEPTH) {
return { OB_FORMAT_Y10, OB_FORMAT_Y11, OB_FORMAT_Y12, OB_FORMAT_Y14, OB_FORMAT_Y16, OB_FORMAT_Z16 };
}
return {};
}
/**
* @brief Check whether a resolution is supported by the enhanced depth filter for a given stream alignment pair.
*
* @param[in] sourceStreamType The source stream type that provides the input frames.
* @param[in] alignToStreamType The target stream type that the source stream is aligned to.
* @param[in] width The frame width to validate.
* @param[in] height The frame height to validate.
*
* @return true if the resolution is supported for the specified alignment combination, otherwise false.
*/
static bool isSupportedResolution(OBStreamType sourceStreamType, OBStreamType alignToStreamType, uint32_t width, uint32_t height) {
if(sourceStreamType != alignToStreamType) {
// If the source and target stream types are different, any resolution is supported.
return true;
}
for(const auto &res: getSupportedResolutions()) {
if(res.first == width && res.second == height) {
return true;
}
}
return false;
}
/**
* @brief Check whether a frame format is supported by the enhanced depth filter for a given stream type.
*
* @param[in] streamType The stream type to validate. Only color and depth streams are supported.
* @param[in] format The frame format to validate.
*
* @return true if the format is supported for the given stream type, otherwise false.
*/
static bool isSupportedFormat(OBStreamType streamType, OBFormat format) {
for(const auto &supported: getSupportedFormats(streamType)) {
if(supported == format) {
return true;
}
}
return false;
}
/**
* @brief Set the working resolution of the enhanced depth filter.
*
* @param[in] width The target frame width.
* @param[in] height The target frame height.
*/
void setResolution(uint32_t width, uint32_t height) {
setConfigValue("width", static_cast<double>(width));
setConfigValue("height", static_cast<double>(height));
}
/**
* @brief Get the current configured frame width.
*
* @return uint32_t The current width.
*/
uint32_t getCurrentWidth() const {
return static_cast<uint32_t>(getConfigValue("width"));
}
/**
* @brief Get the current configured frame height.
*
* @return uint32_t The current height.
*/
uint32_t getCurrentHeight() const {
return static_cast<uint32_t>(getConfigValue("height"));
}
/**
* @brief Set the confidence threshold for depth values.
*
* @param value The confidence threshold.
*/
void setConfidenceThreshold(uint32_t value) {
setConfigValue("confidence_threshold", static_cast<double>(value));
}
/**
* @brief Get the property range of the confidence threshold range.
*/
OBIntPropertyRange getConfidenceThresholdRange() {
OBIntPropertyRange range{};
const auto &schemaVec = getConfigSchemaVec();
for(const auto &item: schemaVec) {
const char *name = "confidence_threshold";
if(std::strcmp(item.name, name) == 0) {
range = getPropertyRange<OBIntPropertyRange>(item, getConfigValue(name));
break;
}
}
return range;
}
};
class OBFilterList {
private:
ob_filter_list_t *impl_;
@@ -2151,6 +2321,7 @@ inline const std::unordered_map<std::string, std::type_index> &getFilterTypeMap(
{ "MgcNoiseRemovalFilter", typeid(MgcNoiseRemovalFilter) },
{ "LutNoiseRemovalFilter", typeid(LutNoiseRemovalFilter) },
{ "UnDistortionFilter", typeid(UnDistortionFilter) },
{ "EnhancedDepthFilter", typeid(EnhancedDepthFilter) },
};
return filterTypeMap;
}
@@ -123,6 +123,32 @@ public:
return index;
}
/**
* @brief Get the auth token carried by the frame.
*
* @return uint64_t The auth token value.
*/
uint64_t getToken() const {
ob_error *error = nullptr;
auto token = ob_frame_get_token(impl_, &error);
Error::handle(&error);
return token;
}
/**
* @brief Set the auth token carried by the frame.
*
* @param token The auth token value.
*/
void setToken(uint64_t token) {
ob_error *error = nullptr;
auto unConstImpl = const_cast<ob_frame *>(impl_);
ob_frame_set_token(unConstImpl, token, &error);
Error::handle(&error);
}
/**
* @brief Get frame data
*
@@ -70,10 +70,19 @@ public:
class PlaybackDevice : public Device {
public:
explicit PlaybackDevice(const std::string &file) : Device(nullptr) {
/**
* @brief Constructs a PlaybackDevice for playing back recorded device data.
* @param[in] file Path to the playback file.
* @param[in] presetPath Path to a preset JSON file to load after device creation. If empty, no preset is loaded.
*/
explicit PlaybackDevice(const std::string &file, const std::string &presetPath = "") : Device(nullptr) {
ob_error *error = nullptr;
impl_ = ob_create_playback_device(file.c_str(), &error);
Error::handle(&error);
if(!presetPath.empty()) {
loadPresetFromJsonFile(presetPath.c_str());
}
}
virtual ~PlaybackDevice() noexcept override = default;
@@ -8,12 +8,12 @@ set(CMAKE_IMPORT_FILE_VERSION 1)
# Import target "ob::OrbbecSDK" for configuration "Release"
set_property(TARGET ob::OrbbecSDK APPEND PROPERTY IMPORTED_CONFIGURATIONS RELEASE)
set_target_properties(ob::OrbbecSDK PROPERTIES
IMPORTED_LOCATION_RELEASE "${_IMPORT_PREFIX}/lib/libOrbbecSDK.so.2.9.1"
IMPORTED_LOCATION_RELEASE "${_IMPORT_PREFIX}/lib/libOrbbecSDK.so.2.9.3"
IMPORTED_SONAME_RELEASE "libOrbbecSDK.so.2"
)
list(APPEND _cmake_import_check_targets ob::OrbbecSDK )
list(APPEND _cmake_import_check_files_for_ob::OrbbecSDK "${_IMPORT_PREFIX}/lib/libOrbbecSDK.so.2.9.1" )
list(APPEND _cmake_import_check_files_for_ob::OrbbecSDK "${_IMPORT_PREFIX}/lib/libOrbbecSDK.so.2.9.3" )
# Commands beyond this point should not need to know the version.
set(CMAKE_IMPORT_FILE_VERSION)
@@ -9,19 +9,19 @@
# The variable CVF_VERSION must be set before calling configure_file().
set(PACKAGE_VERSION "2.9.1")
set(PACKAGE_VERSION "2.9.3")
if(PACKAGE_VERSION VERSION_LESS PACKAGE_FIND_VERSION)
set(PACKAGE_VERSION_COMPATIBLE FALSE)
else()
if("2.9.1" MATCHES "^([0-9]+)\\.")
if("2.9.3" MATCHES "^([0-9]+)\\.")
set(CVF_VERSION_MAJOR "${CMAKE_MATCH_1}")
if(NOT CVF_VERSION_MAJOR VERSION_EQUAL 0)
string(REGEX REPLACE "^0+" "" CVF_VERSION_MAJOR "${CVF_VERSION_MAJOR}")
endif()
else()
set(CVF_VERSION_MAJOR "2.9.1")
set(CVF_VERSION_MAJOR "2.9.3")
endif()
if(PACKAGE_FIND_VERSION_RANGE)
@@ -1 +1 @@
libOrbbecSDK.so.2.9.1
libOrbbecSDK.so.2.9.3
@@ -8,12 +8,12 @@ set(CMAKE_IMPORT_FILE_VERSION 1)
# Import target "ob::OrbbecSDK" for configuration "Release"
set_property(TARGET ob::OrbbecSDK APPEND PROPERTY IMPORTED_CONFIGURATIONS RELEASE)
set_target_properties(ob::OrbbecSDK PROPERTIES
IMPORTED_LOCATION_RELEASE "${_IMPORT_PREFIX}/lib/libOrbbecSDK.so.2.9.1"
IMPORTED_LOCATION_RELEASE "${_IMPORT_PREFIX}/lib/libOrbbecSDK.so.2.9.3"
IMPORTED_SONAME_RELEASE "libOrbbecSDK.so.2"
)
list(APPEND _cmake_import_check_targets ob::OrbbecSDK )
list(APPEND _cmake_import_check_files_for_ob::OrbbecSDK "${_IMPORT_PREFIX}/lib/libOrbbecSDK.so.2.9.1" )
list(APPEND _cmake_import_check_files_for_ob::OrbbecSDK "${_IMPORT_PREFIX}/lib/libOrbbecSDK.so.2.9.3" )
# Commands beyond this point should not need to know the version.
set(CMAKE_IMPORT_FILE_VERSION)
@@ -9,19 +9,19 @@
# The variable CVF_VERSION must be set before calling configure_file().
set(PACKAGE_VERSION "2.9.1")
set(PACKAGE_VERSION "2.9.3")
if(PACKAGE_VERSION VERSION_LESS PACKAGE_FIND_VERSION)
set(PACKAGE_VERSION_COMPATIBLE FALSE)
else()
if("2.9.1" MATCHES "^([0-9]+)\\.")
if("2.9.3" MATCHES "^([0-9]+)\\.")
set(CVF_VERSION_MAJOR "${CMAKE_MATCH_1}")
if(NOT CVF_VERSION_MAJOR VERSION_EQUAL 0)
string(REGEX REPLACE "^0+" "" CVF_VERSION_MAJOR "${CVF_VERSION_MAJOR}")
endif()
else()
set(CVF_VERSION_MAJOR "2.9.1")
set(CVF_VERSION_MAJOR "2.9.3")
endif()
if(PACKAGE_FIND_VERSION_RANGE)
+1 -1
View File
@@ -1 +1 @@
libOrbbecSDK.so.2.9.1
libOrbbecSDK.so.2.9.3
@@ -2028,8 +2028,8 @@
</Misc>
<DepthPostProcessing>
<HardwareNoiseRemoveFilter>false</HardwareNoiseRemoveFilter>
<SoftwareNoiseRemoveFilter>true</SoftwareNoiseRemoveFilter>
<HardwareNoiseRemoveFilter>true</HardwareNoiseRemoveFilter>
<SoftwareNoiseRemoveFilter>false</SoftwareNoiseRemoveFilter>
</DepthPostProcessing>
<!-- Whether to enable heartbeat by default -->
+2 -2
View File
@@ -16,9 +16,9 @@ time_domain: "global" # global, device, system
enable_sync_host_time: true
trigger_out_enabled: true
frames_per_trigger: 0
frames_per_trigger: 1
software_trigger_period: 0
enable_fps_boost: false
# color params
enable_color: true
@@ -16,9 +16,9 @@ time_domain: "global" # global, device, system
enable_sync_host_time: true
trigger_out_enabled: false
frames_per_trigger: 0
frames_per_trigger: 1
software_trigger_period: 0
enable_fps_boost: false
# color params
enable_color: true
+4 -248
View File
@@ -1,69 +1,7 @@
# device
device_type: camera
camera_name: camera
serial_number: ""
usb_port: ""
device_num: 1
upgrade_firmware: ""
preset_firmware_path: ""
load_config_json_file_path: ""
export_config_json_file_path: ""
uvc_backend: libuvc
connection_delay: 10
publish_tf: true
tf_publish_rate: 0.0
ir_info_url: ""
color_info_url: ""
# device_misc
device_access_mode: Default
exposure_range_mode: default
log_level: info
log_file_name: ""
enable_publish_extrinsic: false
enable_d2c_viewer: false
disparity_to_depth_mode: ""
align_mode: SW
align_target_stream: COLOR
diagnostic_period: 1.0
# Gemini 305 dual-color preset. Other parameters inherit gemini_301_series.launch.py.
device_preset: Dual Color Streams
color_preset: Default
retry_on_usb3_detection_failure: false
enable_sync_host_time: true
sync_io_voltage_level: -1
time_sync_period: 6.0
time_domain: global
config_file_path: ""
enable_heartbeat: false
gmsl_trigger_fps: 3000
enable_gmsl_trigger: false
disparity_range_mode: -1
disparity_search_offset: -1
disparity_offset_config: false
offset_index0: -1
offset_index1: -1
frame_aggregate_mode: ANY
interleave_ae_mode: hdr
interleave_frame_enable: false
interleave_skip_enable: false
interleave_skip_index: 1
show_fps_enable: false
# color
enable_color: false
color_width: 0
color_height: 0
color_fps: 0
color_format: ANY
color_qos: default
color_camera_info_qos: default
color_rotation: -1
color_flip: false
color_mirror: false
enable_color_decimation_filter: false
color_decimation_filter_scale: -1
# left_color
# left color
enable_left_color: true
left_color_width: 0
left_color_height: 0
@@ -77,8 +15,9 @@ left_color_mirror: false
enable_left_color_decimation_filter: false
left_color_decimation_filter_scale: -1
enable_left_color_undistortion: false
left_color.image_raw.enable_pub_plugins: ["image_transport/compressed", "image_transport/raw", "image_transport/theora"]
# right_color
# right color
enable_right_color: true
right_color_width: 0
right_color_height: 0
@@ -92,187 +31,4 @@ right_color_mirror: false
enable_right_color_decimation_filter: false
right_color_decimation_filter_scale: -1
enable_right_color_undistortion: false
# color_common
enable_color_auto_exposure_priority: false
enable_color_auto_white_balance: true
enable_color_auto_exposure: true
color_ae_roi_left: -1
color_ae_roi_right: -1
color_ae_roi_top: -1
color_ae_roi_bottom: -1
color_exposure: -1
color_gain: -1
color_white_balance: -1
color_ae_max_exposure: -1
color_brightness: -1
color_sharpness: -1
color_gamma: -1
color_saturation: -1
color_contrast: -1
color_hue: -1
color_backlight_compensation: -1
color_powerline_freq: ""
color_denoising_level: -1
enable_color_undistortion: false
enable_depth_undistortion: false
enable_ir_undistortion: false
enable_left_ir_undistortion: false
enable_right_ir_undistortion: false
# hdr_params
hdr_index1_depth_exposure: 1
hdr_index1_depth_gain: 16
hdr_index1_ir_brightness: 30
hdr_index1_ir_ae_max_exposure: 30458
hdr_index0_depth_exposure: 7500
hdr_index0_depth_gain: 16
hdr_index0_ir_brightness: 90
hdr_index0_ir_ae_max_exposure: 30458
# publishers and transports
left_color.image_raw.enable_pub_plugins: ["image_transport/compressed", "image_transport/raw", "image_transport/theora"]
right_color.image_raw.enable_pub_plugins: ["image_transport/compressed", "image_transport/raw", "image_transport/theora"]
# In dual color mode, it is not recommended to change the following parameters
# depth
enable_depth: false
depth_width: 0
depth_height: 0
depth_fps: 0
depth_format: ANY
depth_qos: default
depth_camera_info_qos: default
enable_depth_auto_exposure_priority: false
depth_precision: ""
depth_rotation: -1
depth_flip: false
depth_mirror: false
depth_ae_roi_left: -1
depth_ae_roi_right: -1
depth_ae_roi_top: -1
depth_ae_roi_bottom: -1
mean_intensity_set_point: -1
enable_depth_scale: false
enable_decimation_filter: false
decimation_filter_scale: -1
enable_hdr_merge: false
hdr_merge_exposure_1: -1
hdr_merge_gain_1: -1
hdr_merge_exposure_2: -1
hdr_merge_gain_2: -1
enable_sequence_id_filter: false
sequence_id_filter_id: -1
enable_threshold_filter: false
threshold_filter_max: -1
threshold_filter_min: -1
enable_hardware_noise_removal_filter: false
hardware_noise_removal_filter_threshold: -1.0
enable_noise_removal_filter: false
noise_removal_filter_min_diff: 256
noise_removal_filter_max_size: 80
enable_spatial_filter: false
spatial_filter_alpha: -1.0
spatial_filter_diff_threshold: -1
spatial_filter_magnitude: -1
spatial_filter_radius: -1
enable_temporal_filter: false
temporal_filter_diff_threshold: -1.0
temporal_filter_weight: -1.0
enable_disparity_to_depth: false
hole_filling_filter_mode: ""
enable_hole_filling_filter: false
enable_spatial_fast_filter: false
spatial_fast_filter_radius: -1
enable_spatial_moderate_filter: false
spatial_moderate_filter_diff_threshold: -1
spatial_moderate_filter_magnitude: -1
spatial_moderate_filter_radius: -1
# point_cloud
depth_registration: false
point_cloud_qos: default
enable_point_cloud: false
point_cloud_decimation_filter_factor: 1
enable_colored_point_cloud: false
cloud_frame_id: ""
ordered_pc: false
# ldp
enable_ldp: true
ldp_power_level: -1
# left_ir
enable_left_ir: false
left_ir_width: 0
left_ir_height: 0
left_ir_fps: 0
left_ir_format: ANY
left_ir_qos: default
left_ir_camera_info_qos: default
left_ir_rotation: -1
left_ir_flip: false
left_ir_mirror: false
enable_left_ir_sequence_id_filter: false
left_ir_sequence_id_filter_id: -1
# right_ir
enable_right_ir: false
right_ir_width: 0
right_ir_height: 0
right_ir_fps: 0
right_ir_format: ANY
right_ir_qos: default
right_ir_camera_info_qos: default
right_ir_rotation: -1
right_ir_flip: false
right_ir_mirror: false
enable_right_ir_sequence_id_filter: false
right_ir_sequence_id_filter_id: -1
# ir_common
enable_ir_auto_exposure: false
ir_exposure: -1
ir_gain: -1
ir_ae_max_exposure: -1
ir_brightness: -1
# imu
enable_sync_output_accel_gyro: false
enable_accel: false
enable_accel_data_correction: false
accel_rate: 200hz
accel_range: 4g
enable_gyro: false
enable_gyro_data_correction: false
gyro_rate: 200hz
gyro_range: 1000dps
linear_accel_cov: 0.01
angular_vel_cov: 0.01
depth_delay_us: 0
color_delay_us: 0
trigger2image_delay_us: 0
trigger_out_delay_us: 0
trigger_out_enabled: true
software_trigger_enabled: true
frames_per_trigger: 2
software_trigger_period: 33
enable_ptp_config: false
enable_frame_sync: true
noise_removal_filter_min_diff: 256
noise_removal_filter_max_size: 80
# laser_params
laser_index1_laser_control: 0
laser_index1_depth_exposure: 3000
laser_index1_depth_gain: 16
laser_index1_ir_brightness: 60
laser_index1_ir_ae_max_exposure: 17000
laser_index0_laser_control: 1
laser_index0_depth_exposure: 3000
laser_index0_depth_gain: 16
laser_index0_ir_brightness: 60
laser_index0_ir_ae_max_exposure: 30000
@@ -85,6 +85,7 @@ def generate_launch_description():
DeclareLaunchArgument('color_ae_roi_bottom', default_value='-1'),
DeclareLaunchArgument('color_exposure', default_value='-1'),
DeclareLaunchArgument('color_gain', default_value='-1'),
DeclareLaunchArgument('color_mjpeg_quality', default_value='-1'),
DeclareLaunchArgument('enable_color_auto_white_balance', default_value='true'),
DeclareLaunchArgument('color_white_balance', default_value='-1'),
DeclareLaunchArgument('enable_color_auto_exposure', default_value='true'),
@@ -180,7 +181,8 @@ def generate_launch_description():
DeclareLaunchArgument('trigger2image_delay_us', default_value='0'),
DeclareLaunchArgument('trigger_out_delay_us', default_value='0'),
DeclareLaunchArgument('trigger_out_enabled', default_value='true'),
DeclareLaunchArgument('frames_per_trigger', default_value='2'),
DeclareLaunchArgument('enable_fps_boost', default_value='false'),
DeclareLaunchArgument('frames_per_trigger', default_value='1'),
DeclareLaunchArgument('software_trigger_period', default_value='33'), # ms
DeclareLaunchArgument('enable_ptp_config', default_value='false'),#Only for Gemini 335Le
DeclareLaunchArgument('enable_frame_sync', default_value='true'),
@@ -85,6 +85,7 @@ def generate_launch_description():
DeclareLaunchArgument('color_ae_roi_bottom', default_value='-1'),
DeclareLaunchArgument('color_exposure', default_value='-1'),
DeclareLaunchArgument('color_gain', default_value='-1'),
DeclareLaunchArgument('color_mjpeg_quality', default_value='-1'),
DeclareLaunchArgument('enable_color_auto_white_balance', default_value='true'),
DeclareLaunchArgument('color_white_balance', default_value='-1'),
DeclareLaunchArgument('enable_color_auto_exposure', default_value='true'),
@@ -180,7 +181,8 @@ def generate_launch_description():
DeclareLaunchArgument('trigger2image_delay_us', default_value='0'),
DeclareLaunchArgument('trigger_out_delay_us', default_value='0'),
DeclareLaunchArgument('trigger_out_enabled', default_value='true'),
DeclareLaunchArgument('frames_per_trigger', default_value='2'),
DeclareLaunchArgument('enable_fps_boost', default_value='false'),
DeclareLaunchArgument('frames_per_trigger', default_value='1'),
DeclareLaunchArgument('software_trigger_period', default_value='33'), # ms
DeclareLaunchArgument('enable_ptp_config', default_value='false'),#Only for Gemini 335Le
DeclareLaunchArgument('enable_frame_sync', default_value='true'),
@@ -85,6 +85,7 @@ def generate_launch_description():
DeclareLaunchArgument('color_ae_roi_bottom', default_value='-1'),
DeclareLaunchArgument('color_exposure', default_value='-1'),
DeclareLaunchArgument('color_gain', default_value='-1'),
DeclareLaunchArgument('color_mjpeg_quality', default_value='-1'),
DeclareLaunchArgument('enable_color_auto_white_balance', default_value='true'),
DeclareLaunchArgument('color_white_balance', default_value='-1'),
DeclareLaunchArgument('enable_color_auto_exposure', default_value='true'),
@@ -180,7 +181,8 @@ def generate_launch_description():
DeclareLaunchArgument('trigger2image_delay_us', default_value='0'),
DeclareLaunchArgument('trigger_out_delay_us', default_value='0'),
DeclareLaunchArgument('trigger_out_enabled', default_value='true'),
DeclareLaunchArgument('frames_per_trigger', default_value='2'),
DeclareLaunchArgument('enable_fps_boost', default_value='false'),
DeclareLaunchArgument('frames_per_trigger', default_value='1'),
DeclareLaunchArgument('software_trigger_period', default_value='33'), # ms
DeclareLaunchArgument('enable_ptp_config', default_value='false'),#Only for Gemini 335Le
DeclareLaunchArgument('enable_frame_sync', default_value='true'),
@@ -24,7 +24,7 @@
#define OB_ROS_MAJOR_VERSION 2
#define OB_ROS_MINOR_VERSION 9
#define OB_ROS_PATCH_VERSION 1
#define OB_ROS_PATCH_VERSION 3
#ifndef STRINGIFY
#define STRINGIFY(arg) #arg
@@ -40,6 +40,7 @@ class FrameTimestampCsvLogger {
void recordPreImagePublish(OBStreamType stream_type, const std::shared_ptr<ob::Frame> &frame,
int64_t publish_system_us, int64_t publish_steady_us);
void recordImagePublishSkipped(OBStreamType stream_type, const std::shared_ptr<ob::Frame> &frame);
void shutdown();
@@ -112,9 +113,10 @@ class FrameTimestampCsvLogger {
const std::shared_ptr<ob::Frame> &frame,
int64_t arrival_system_us, int64_t arrival_steady_us,
bool image_publish_expected);
void recordPreImagePublishInternal(OBStreamType stream_type,
const std::shared_ptr<ob::Frame> &frame,
int64_t publish_system_us, int64_t publish_steady_us);
void completeImagePublishInternal(OBStreamType stream_type,
const std::shared_ptr<ob::Frame> &frame,
std::optional<int64_t> publish_system_us,
std::optional<int64_t> publish_steady_us);
void populateArrivalData(StreamState &state, TrackedStream stream,
const std::shared_ptr<ob::Frame> &frame, int64_t arrival_system_us,
@@ -18,7 +18,9 @@
#include <nlohmann/json.hpp>
#include <cstddef>
#include <memory>
#include <optional>
#include <rclcpp/rclcpp.hpp>
#include <string>
#include <unordered_map>
@@ -37,9 +39,11 @@
#include <std_srvs/srv/set_bool.hpp>
#include <std_srvs/srv/empty.hpp>
#include <diagnostic_updater/diagnostic_updater.hpp>
#include <std_msgs/msg/int32.hpp>
#include <sensor_msgs/msg/camera_info.hpp>
#include <sensor_msgs/msg/compressed_image.hpp>
#include <sensor_msgs/msg/image.hpp>
#include <camera_info_manager/camera_info_manager.hpp>
#include <image_publisher/image_publisher.hpp>
@@ -63,6 +67,7 @@
#include "orbbec_camera_msgs/srv/set_string.hpp"
#include "orbbec_camera_msgs/srv/set_filter.hpp"
#include "orbbec_camera_msgs/srv/set_arrays.hpp"
#include "orbbec_camera_msgs/srv/set_stream_profile.hpp"
#include "orbbec_camera_msgs/srv/get_user_calib_params.hpp"
#include "orbbec_camera_msgs/srv/set_user_calib_params.hpp"
#include "orbbec_camera/constants.h"
@@ -122,6 +127,7 @@ using SetBool = std_srvs::srv::SetBool;
using GetBool = orbbec_camera_msgs::srv::GetBool;
using SetFilter = orbbec_camera_msgs::srv::SetFilter;
using SetArrays = orbbec_camera_msgs::srv::SetArrays;
using SetStreamProfile = orbbec_camera_msgs::srv::SetStreamProfile;
using SetUserCalibParams = orbbec_camera_msgs::srv::SetUserCalibParams;
using GetUserCalibParams = orbbec_camera_msgs::srv::GetUserCalibParams;
using DepthFilterState = orbbec_camera_msgs::msg::DepthFilterState;
@@ -238,6 +244,14 @@ class OBCameraNode {
double timestamp_ = -1; // in nanoseconds
};
struct PendingStreamProfile {
stream_index_pair stream_index;
int requested_width = 0;
int requested_height = 0;
int requested_fps = 0;
std::shared_ptr<ob::VideoStreamProfile> profile;
};
void setupDevices();
void loadConfigJson();
@@ -267,6 +281,24 @@ class OBCameraNode {
void setupProfiles();
std::shared_ptr<ob::VideoStreamProfile> selectVideoStreamProfile(
const stream_index_pair& stream_index, int width, int height, int fps, OBFormat format);
std::optional<stream_index_pair> getImageStreamByName(const std::string& stream_name) const;
bool validateStreamProfileRequest(const std::shared_ptr<SetStreamProfile::Request>& request,
std::vector<PendingStreamProfile>& pending_profiles,
std::string& message);
bool applyStreamProfiles(const std::vector<PendingStreamProfile>& pending_profiles,
std::string& message);
void clearColorFrameQueues();
void stopColorFrameThreads();
void setupImageBuffers();
void updateImageConfig(const stream_index_pair& stream_index);
void printSensorProfiles(const std::shared_ptr<ob::Sensor>& sensor);
@@ -277,6 +309,8 @@ class OBCameraNode {
void setupTopics();
void setupImagePublisher(const stream_index_pair& stream_index);
void setupPipelineConfig();
void setupDiagnosticUpdater();
@@ -293,10 +327,15 @@ class OBCameraNode {
void setupPublishers();
void syncSoftwareAlignment();
void publishDepthFiltersStatus();
void publishLrmObstacleDistance();
DepthFilterState buildDepthFilterState(const std::string& filter_name, bool enabled,
const std::shared_ptr<ob::Filter>& filter) const;
DepthFilterState buildEnhancedDepthFilterState() const;
static std::string normalizeDepthFilterName(const std::string& filter_name);
@@ -308,6 +347,18 @@ class OBCameraNode {
bool applyNamedDepthFilterConfig(
const std::string& filter_name, bool enabled,
const std::vector<orbbec_camera_msgs::msg::DepthFilterParam>& params, std::string& message);
bool applyEnhancedDepthFilterConfig(
bool enabled, const std::vector<float>& positional_params,
const std::vector<orbbec_camera_msgs::msg::DepthFilterParam>& named_params,
std::string& message);
bool validateEnhancedDepthFilterConfig(std::string& message) const;
bool ensureEnhancedDepthFilter(std::string& message);
void applyEnhancedDepthConfidenceThreshold();
std::shared_ptr<ob::FrameSet> processEnhancedDepthFilter(
const std::shared_ptr<ob::FrameSet>& frame_set);
bool convertEnhancedDepthColorFrame(const std::shared_ptr<ob::FrameSet>& frame_set);
void setupConfidencePublishers();
void publishConfidenceFrame(const std::shared_ptr<ob::Frame>& confidence_frame);
void setupCameraInfo();
@@ -328,6 +379,8 @@ class OBCameraNode {
void setStreamsEnableCallback(const std::shared_ptr<std_srvs::srv::SetBool::Request> request,
std::shared_ptr<std_srvs::srv::SetBool::Response> response);
void setImageRegistrationModeCallback(const std::shared_ptr<SetString::Request> request,
std::shared_ptr<SetString::Response> response);
void getStreamsEnableCallback(
const std::shared_ptr<orbbec_camera_msgs::srv::GetBool::Request> request,
@@ -475,6 +528,9 @@ class OBCameraNode {
void setAEStrategyCallback(const std::shared_ptr<SetString::Request>& request,
std::shared_ptr<SetString::Response>& response);
void setStreamProfileCallback(const std::shared_ptr<SetStreamProfile::Request>& request,
std::shared_ptr<SetStreamProfile::Response>& response);
void setUserCalibParamsCallback(const std::shared_ptr<SetUserCalibParams::Request>& request,
std::shared_ptr<SetUserCalibParams::Response>& response);
@@ -699,6 +755,8 @@ class OBCameraNode {
rclcpp::Service<SetInt32>::SharedPtr set_sync_io_voltage_level_srv_;
rclcpp::Service<orbbec_camera_msgs::srv::GetBool>::SharedPtr get_streams_enable_srv_;
rclcpp::Service<std_srvs::srv::SetBool>::SharedPtr set_streams_enable_srv_;
rclcpp::Service<SetString>::SharedPtr set_image_registration_mode_srv_;
rclcpp::Service<SetStreamProfile>::SharedPtr set_stream_profile_srv_;
rclcpp::Service<GetUserCalibParams>::SharedPtr get_user_calib_params_srv_;
rclcpp::Service<SetUserCalibParams>::SharedPtr set_user_calib_params_srv_;
rclcpp::Service<SetString>::SharedPtr set_ae_reference_stream_srv_;
@@ -755,6 +813,7 @@ class OBCameraNode {
int color_ae_roi_bottom_ = -1;
int color_exposure_ = -1;
int color_gain_ = -1;
int color_mjpeg_quality_ = -1;
int color_white_balance_ = -1;
int color_ae_max_exposure_ = -1;
int color_ae_max_gain_ = -1;
@@ -806,7 +865,7 @@ class OBCameraNode {
int trigger_out_delay_us_ = 0;
bool trigger_out_enabled_ = false;
bool software_trigger_enabled_ = false;
int frames_per_trigger_ = 2;
int frames_per_trigger_ = 1;
bool enable_ptp_config_ = false;
std::string depth_precision_str_;
OB_DEPTH_PRECISION_LEVEL depth_precision_ = OB_PRECISION_0MM8;
@@ -832,6 +891,9 @@ class OBCameraNode {
uint8_t* rgb_buffer_ = nullptr;
uint8_t* rgb_buffer_left_ = nullptr;
uint8_t* rgb_buffer_right_ = nullptr;
size_t rgb_buffer_size_ = 0;
size_t rgb_buffer_left_size_ = 0;
size_t rgb_buffer_right_size_ = 0;
bool is_left_color_frame_decoded_ = false;
bool is_right_color_frame_decoded_ = false;
bool is_color_frame_decoded_ = false;
@@ -839,6 +901,7 @@ class OBCameraNode {
// For color
std::queue<std::shared_ptr<ob::FrameSet>> color_frame_queue_;
std::shared_ptr<std::thread> colorFrameThread_ = nullptr;
std::atomic_bool stop_color_frame_threads_{false};
std::mutex color_frame_queue_lock_;
std::condition_variable color_frame_queue_cv_;
@@ -913,6 +976,14 @@ class OBCameraNode {
double diagnostic_period_ = 1.0;
bool enable_laser_ = false;
std::unique_ptr<ob::Align> align_filter_ = nullptr;
std::shared_ptr<ob::EnhancedDepthFilter> enhanced_depth_filter_ = nullptr;
ob::FormatConvertFilter enhanced_depth_format_convert_filter_;
std::mutex enhanced_depth_filter_mutex_;
std::atomic_bool enable_enhanced_depth_{false};
std::string enhanced_depth_model_path_;
int enhanced_depth_confidence_threshold_ = -1;
rclcpp::Publisher<sensor_msgs::msg::Image>::SharedPtr confidence_image_publisher_;
cv::Mat confidence_image_;
OBStreamType align_target_stream_ = OB_STREAM_COLOR;
bool retry_on_usb3_detection_failure_ = false;
bool config_json_loaded_ = false;
@@ -943,13 +1014,18 @@ class OBCameraNode {
std::string export_config_json_file_path_ = "";
// soft ware trigger
rclcpp::TimerBase::SharedPtr software_trigger_timer_;
rclcpp::TimerBase::SharedPtr lrm_obstacle_distance_timer_;
rclcpp::TimerBase::SharedPtr diagnostic_timer_;
rclcpp::Publisher<std_msgs::msg::Int32>::SharedPtr lrm_obstacle_distance_pub_;
std::mutex diagnostic_mutex_;
std::condition_variable diagnostic_cv_;
bool diagnostic_running_ = false;
std::chrono::milliseconds software_trigger_period_{33};
bool enable_lrm_obstacle_distance_publish_ = false;
double lrm_obstacle_distance_publish_rate_ = 10.0;
bool enable_heartbeat_ = false;
bool enable_firmware_log_ = false;
bool enable_fps_boost_ = false;
std::map<stream_index_pair, bool> enable_undistortion_;
std::shared_ptr<ob::UnDistortionFilter> hw_d2c_color_undistortion_filter_;
bool hw_d2c_color_undistortion_configured_ = false;
@@ -155,6 +155,7 @@ class OBCameraNodeDriver : public rclcpp::Node {
std::atomic<bool> firmware_update_success_{false};
std::atomic<bool> need_reupdate_{false};
std::atomic<bool> is_reupdating_{false}; // Flag to track if we're in reupdate process
std::atomic<bool> delay_stream_start_after_reconnect_{false};
rclcpp::TimerBase::SharedPtr device_status_timer_ = nullptr;
int device_status_interval_hz = 2; // 2Hz
rclcpp::Publisher<orbbec_camera_msgs::msg::DeviceStatus>::SharedPtr device_status_pub_ = nullptr;
+1 -1
View File
@@ -167,7 +167,7 @@ def generate_launch_description():
DeclareLaunchArgument('trigger2image_delay_us', default_value='0'),
DeclareLaunchArgument('trigger_out_delay_us', default_value='0'),
DeclareLaunchArgument('trigger_out_enabled', default_value='true'),
DeclareLaunchArgument('frames_per_trigger', default_value='2'),
DeclareLaunchArgument('frames_per_trigger', default_value='1'),
DeclareLaunchArgument('software_trigger_period', default_value='33'), # ms
DeclareLaunchArgument('enable_frame_sync', default_value='true'),
DeclareLaunchArgument('ordered_pc', default_value='false'),
+1 -1
View File
@@ -167,7 +167,7 @@ def generate_launch_description():
DeclareLaunchArgument('trigger2image_delay_us', default_value='0'),
DeclareLaunchArgument('trigger_out_delay_us', default_value='0'),
DeclareLaunchArgument('trigger_out_enabled', default_value='true'),
DeclareLaunchArgument('frames_per_trigger', default_value='2'),
DeclareLaunchArgument('frames_per_trigger', default_value='1'),
DeclareLaunchArgument('software_trigger_period', default_value='33'), # ms
DeclareLaunchArgument('enable_frame_sync', default_value='true'),
DeclareLaunchArgument('ordered_pc', default_value='false'),
+1 -1
View File
@@ -166,7 +166,7 @@ def generate_launch_description():
DeclareLaunchArgument('trigger2image_delay_us', default_value='0'),
DeclareLaunchArgument('trigger_out_delay_us', default_value='0'),
DeclareLaunchArgument('trigger_out_enabled', default_value='true'),
DeclareLaunchArgument('frames_per_trigger', default_value='2'),
DeclareLaunchArgument('frames_per_trigger', default_value='1'),
DeclareLaunchArgument('software_trigger_period', default_value='33'), # ms
DeclareLaunchArgument('enable_frame_sync', default_value='true'),
DeclareLaunchArgument('ordered_pc', default_value='false'),
+1 -1
View File
@@ -167,7 +167,7 @@ def generate_launch_description():
DeclareLaunchArgument('trigger2image_delay_us', default_value='0'),
DeclareLaunchArgument('trigger_out_delay_us', default_value='0'),
DeclareLaunchArgument('trigger_out_enabled', default_value='true'),
DeclareLaunchArgument('frames_per_trigger', default_value='2'),
DeclareLaunchArgument('frames_per_trigger', default_value='1'),
DeclareLaunchArgument('software_trigger_period', default_value='33'), # ms
DeclareLaunchArgument('enable_frame_sync', default_value='true'),
DeclareLaunchArgument('ordered_pc', default_value='false'),
+1 -1
View File
@@ -198,7 +198,7 @@ def generate_launch_description():
DeclareLaunchArgument('trigger_out_delay_us', default_value='0'),
DeclareLaunchArgument('trigger_out_enabled', default_value='true'),
DeclareLaunchArgument('software_trigger_enabled', default_value='true'),
DeclareLaunchArgument('frames_per_trigger', default_value='2'),
DeclareLaunchArgument('frames_per_trigger', default_value='1'),
DeclareLaunchArgument('software_trigger_period', default_value='33'), # ms
DeclareLaunchArgument('enable_ptp_config', default_value='false'),
DeclareLaunchArgument('enable_frame_sync', default_value='true'),
@@ -197,24 +197,11 @@ def generate_launch_description():
DeclareLaunchArgument('ir_gain', default_value='-1'),
DeclareLaunchArgument('ir_ae_max_exposure', default_value='-1'),
DeclareLaunchArgument('ir_brightness', default_value='-1'),
DeclareLaunchArgument('enable_sync_output_accel_gyro', default_value='false'),
DeclareLaunchArgument('enable_accel', default_value='false'),
DeclareLaunchArgument('enable_accel_data_correction', default_value='true'),
DeclareLaunchArgument('accel_rate', default_value='200hz'),
DeclareLaunchArgument('accel_range', default_value='4g'),
DeclareLaunchArgument('enable_gyro', default_value='false'),
DeclareLaunchArgument('enable_gyro_data_correction', default_value='true'),
DeclareLaunchArgument('gyro_rate', default_value='200hz'),
DeclareLaunchArgument('gyro_range', default_value='1000dps'),
DeclareLaunchArgument('linear_accel_cov', default_value='0.01'),
DeclareLaunchArgument('angular_vel_cov', default_value='0.01'),
DeclareLaunchArgument('publish_tf', default_value='true'),
DeclareLaunchArgument('tf_publish_rate', default_value='0.0'),
DeclareLaunchArgument('ir_info_url', default_value=''),
DeclareLaunchArgument('color_info_url', default_value=''),
DeclareLaunchArgument('device_access_mode', default_value='Default'), # Default, EA or CA . only for 335le
DeclareLaunchArgument('exposure_range_mode', default_value='default'),#default, ultimate or regular
DeclareLaunchArgument('log_level', default_value='info'),
DeclareLaunchArgument('log_file_name', default_value=''),
DeclareLaunchArgument('enable_publish_extrinsic', default_value='false'),
@@ -227,7 +214,7 @@ def generate_launch_description():
DeclareLaunchArgument('trigger_out_delay_us', default_value='0'),
DeclareLaunchArgument('trigger_out_enabled', default_value='true'),
DeclareLaunchArgument('software_trigger_enabled', default_value='true'),
DeclareLaunchArgument('frames_per_trigger', default_value='2'),
DeclareLaunchArgument('frames_per_trigger', default_value='1'),
DeclareLaunchArgument('software_trigger_period', default_value='33'), # ms
DeclareLaunchArgument('enable_frame_sync', default_value='true'),
DeclareLaunchArgument('ordered_pc', default_value='false'),
@@ -236,9 +223,8 @@ def generate_launch_description():
DeclareLaunchArgument('enable_hdr_merge', default_value='false'),
DeclareLaunchArgument('enable_sequence_id_filter', default_value='false'),
DeclareLaunchArgument('enable_threshold_filter', default_value='false'),
DeclareLaunchArgument('enable_hardware_noise_removal_filter', default_value='false'),
DeclareLaunchArgument('enable_hardware_noise_removal_filter', default_value='true'),
DeclareLaunchArgument('enable_noise_removal_filter', default_value='false'),
DeclareLaunchArgument('enable_disp_outliers_filter', default_value='false'),
DeclareLaunchArgument('enable_spatial_filter', default_value='false'),
DeclareLaunchArgument('enable_temporal_filter', default_value='false'),
DeclareLaunchArgument('enable_disparity_to_depth', default_value='true'),
@@ -296,9 +282,6 @@ def generate_launch_description():
DeclareLaunchArgument('frame_aggregate_mode', default_value='ANY'), # full_frame, color_frame, ANY or disable
DeclareLaunchArgument('interleave_ae_mode', default_value='hdr'),
DeclareLaunchArgument('interleave_frame_enable', default_value='false'),
DeclareLaunchArgument('interleave_skip_enable', default_value='false'),
DeclareLaunchArgument('interleave_skip_index', default_value='1'), # 0:skip pattern ir 1: skip flood ir
DeclareLaunchArgument('hdr_index1_depth_exposure', default_value='1'),
DeclareLaunchArgument('hdr_index1_depth_gain', default_value='16'),
DeclareLaunchArgument('hdr_index1_ir_brightness', default_value='30'),
@@ -42,7 +42,8 @@ def load_parameters(context, args):
if config_file_path:
yaml_params = load_yaml(config_file_path)
default_params = merge_params(default_params, yaml_params)
skip_convert = {'config_file_path', 'usb_port', 'serial_number', 'bag_record_filename', 'bag_filename'}
skip_convert = {'config_file_path', 'usb_port', 'serial_number', 'bag_record_filename', 'bag_filename',
'enhanced_depth_model_path'}
result = {}
for key, value in default_params.items():
@@ -108,6 +109,7 @@ def generate_launch_description():
DeclareLaunchArgument('color_ae_roi_bottom', default_value='-1'),
DeclareLaunchArgument('color_exposure', default_value='-1'),
DeclareLaunchArgument('color_gain', default_value='-1'),
DeclareLaunchArgument('color_mjpeg_quality', default_value='-1'),
DeclareLaunchArgument('enable_color_auto_white_balance', default_value='true'),
DeclareLaunchArgument('color_white_balance', default_value='-1'),
DeclareLaunchArgument('enable_color_auto_exposure', default_value='true'),
@@ -203,14 +205,17 @@ def generate_launch_description():
DeclareLaunchArgument('disparity_to_depth_mode', default_value='HW'),
DeclareLaunchArgument('enable_ldp', default_value='false'),
DeclareLaunchArgument('ldp_power_level', default_value='-1'),
DeclareLaunchArgument('enable_lrm_obstacle_distance_publish', default_value='false'),
DeclareLaunchArgument('lrm_obstacle_distance_publish_rate', default_value='10.0'),
DeclareLaunchArgument('sync_mode', default_value='standalone'),
DeclareLaunchArgument('depth_delay_us', default_value='0'),
DeclareLaunchArgument('color_delay_us', default_value='0'),
DeclareLaunchArgument('trigger2image_delay_us', default_value='0'),
DeclareLaunchArgument('trigger_out_delay_us', default_value='0'),
DeclareLaunchArgument('trigger_out_enabled', default_value='true'),
DeclareLaunchArgument('enable_fps_boost', default_value='false'),
DeclareLaunchArgument('software_trigger_enabled', default_value='true'),
DeclareLaunchArgument('frames_per_trigger', default_value='2'),
DeclareLaunchArgument('frames_per_trigger', default_value='1'),
DeclareLaunchArgument('software_trigger_period', default_value='33'), # ms
DeclareLaunchArgument('enable_ptp_config', default_value='false'),#Only for Gemini 335Le
DeclareLaunchArgument('enable_frame_sync', default_value='true'),
@@ -230,6 +235,9 @@ def generate_launch_description():
DeclareLaunchArgument('enable_spatial_fast_filter', default_value='false'),
DeclareLaunchArgument('enable_spatial_moderate_filter', default_value='false'),
DeclareLaunchArgument('enable_false_positive_filter', default_value='false'),
DeclareLaunchArgument('enable_enhanced_depth', default_value='false'),
DeclareLaunchArgument('enhanced_depth_model_path', default_value=''),
DeclareLaunchArgument('enhanced_depth_confidence_threshold', default_value='51'),
DeclareLaunchArgument('decimation_filter_scale', default_value='-1'),
DeclareLaunchArgument('sequence_id_filter_id', default_value='-1'),
DeclareLaunchArgument('threshold_filter_max', default_value='-1'),
@@ -42,7 +42,8 @@ def load_parameters(context, args):
if config_file_path:
yaml_params = load_yaml(config_file_path)
default_params = merge_params(default_params, yaml_params)
skip_convert = {'config_file_path', 'usb_port', 'serial_number', 'bag_record_filename', 'bag_filename'}
skip_convert = {'config_file_path', 'usb_port', 'serial_number', 'bag_record_filename', 'bag_filename',
'enhanced_depth_model_path'}
result = {}
for key, value in default_params.items():
@@ -106,6 +107,7 @@ def generate_launch_description():
DeclareLaunchArgument('color_ae_roi_bottom', default_value='-1'),
DeclareLaunchArgument('color_exposure', default_value='-1'),
DeclareLaunchArgument('color_gain', default_value='-1'),
DeclareLaunchArgument('color_mjpeg_quality', default_value='-1'),
DeclareLaunchArgument('enable_color_auto_white_balance', default_value='true'),
DeclareLaunchArgument('color_white_balance', default_value='-1'),
DeclareLaunchArgument('enable_color_auto_exposure', default_value='true'),
@@ -206,8 +208,9 @@ def generate_launch_description():
DeclareLaunchArgument('trigger2image_delay_us', default_value='0'),
DeclareLaunchArgument('trigger_out_delay_us', default_value='0'),
DeclareLaunchArgument('trigger_out_enabled', default_value='true'),
DeclareLaunchArgument('enable_fps_boost', default_value='false'),
DeclareLaunchArgument('software_trigger_enabled', default_value='true'),
DeclareLaunchArgument('frames_per_trigger', default_value='2'),
DeclareLaunchArgument('frames_per_trigger', default_value='1'),
DeclareLaunchArgument('software_trigger_period', default_value='33'), # ms
DeclareLaunchArgument('enable_ptp_config', default_value='false'),#Only for Gemini 335Le
DeclareLaunchArgument('enable_frame_sync', default_value='true'),
@@ -227,6 +230,9 @@ def generate_launch_description():
DeclareLaunchArgument('enable_spatial_fast_filter', default_value='false'),
DeclareLaunchArgument('enable_spatial_moderate_filter', default_value='false'),
DeclareLaunchArgument('enable_false_positive_filter', default_value='false'),
DeclareLaunchArgument('enable_enhanced_depth', default_value='false'),
DeclareLaunchArgument('enhanced_depth_model_path', default_value=''),
DeclareLaunchArgument('enhanced_depth_confidence_threshold', default_value='51'),
DeclareLaunchArgument('decimation_filter_scale', default_value='-1'),
DeclareLaunchArgument('sequence_id_filter_id', default_value='-1'),
DeclareLaunchArgument('threshold_filter_max', default_value='-1'),
@@ -125,7 +125,7 @@ def generate_launch_description():
DeclareLaunchArgument('trigger2image_delay_us', default_value='0'),
DeclareLaunchArgument('trigger_out_delay_us', default_value='0'),
DeclareLaunchArgument('trigger_out_enabled', default_value='true'),
DeclareLaunchArgument('frames_per_trigger', default_value='2'),
DeclareLaunchArgument('frames_per_trigger', default_value='1'),
DeclareLaunchArgument('software_trigger_period', default_value='33'), # ms
DeclareLaunchArgument('enable_frame_sync', default_value='true'),
DeclareLaunchArgument('ordered_pc', default_value='false'),
+1 -1
View File
@@ -2,7 +2,7 @@
<?xml-model href="http://download.ros.org/schema/package_format3.xsd" schematypens="http://www.w3.org/2001/XMLSchema"?>
<package format="3">
<name>orbbec_camera</name>
<version>2.9.1</version>
<version>2.9.3</version>
<description>Orbbec Camera package</description>
<maintainer email="yalian@orbbec.com">yalian</maintainer>
<license>Apache-2.0</license>
@@ -109,7 +109,15 @@ void FrameTimestampCsvLogger::recordPreImagePublish(OBStreamType stream_type,
if (!enabled_ || !frame || !isTrackedStream(stream_type)) {
return;
}
recordPreImagePublishInternal(stream_type, frame, publish_system_us, publish_steady_us);
completeImagePublishInternal(stream_type, frame, publish_system_us, publish_steady_us);
}
void FrameTimestampCsvLogger::recordImagePublishSkipped(OBStreamType stream_type,
const std::shared_ptr<ob::Frame> &frame) {
if (!enabled_ || !frame || !isTrackedStream(stream_type)) {
return;
}
completeImagePublishInternal(stream_type, frame, std::nullopt, std::nullopt);
}
void FrameTimestampCsvLogger::shutdown() {
@@ -257,10 +265,9 @@ void FrameTimestampCsvLogger::recordStandaloneFrameArrivalInternal(
}
}
void FrameTimestampCsvLogger::recordPreImagePublishInternal(OBStreamType stream_type,
const std::shared_ptr<ob::Frame> &frame,
int64_t publish_system_us,
int64_t publish_steady_us) {
void FrameTimestampCsvLogger::completeImagePublishInternal(
OBStreamType stream_type, const std::shared_ptr<ob::Frame> &frame,
std::optional<int64_t> publish_system_us, std::optional<int64_t> publish_steady_us) {
std::optional<PendingRow> ready_row;
const auto frame_index = frame->getIndex();
@@ -275,10 +282,12 @@ void FrameTimestampCsvLogger::recordPreImagePublishInternal(OBStreamType stream_
: 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);
if (publish_system_us.has_value()) {
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;
@@ -290,8 +299,16 @@ void FrameTimestampCsvLogger::recordPreImagePublishInternal(OBStreamType stream_
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 (state.final) {
return;
}
if (publish_system_us.has_value() && publish_steady_us.has_value()) {
populatePublishData(state, tracked_stream, publish_system_us.value(),
publish_steady_us.value());
state.final = true;
} else {
finalizeStreamWithoutPublish(state);
}
if (isRowReady(pending_it->second)) {
ready_row = pending_it->second;
@@ -440,6 +457,8 @@ void FrameTimestampCsvLogger::flushPendingRowsLocked(std::vector<PendingRow> &ro
row.depth.final = true;
rows.push_back(std::move(row));
}
std::stable_sort(rows.begin(), rows.end(),
[](const auto &lhs, const auto &rhs) { return lhs.row_id < rhs.row_id; });
pending_rows_.clear();
color_frame_index_to_row_id_.clear();
depth_frame_index_to_row_id_.clear();
File diff suppressed because it is too large Load Diff
+13 -2
View File
@@ -37,6 +37,8 @@
std::string g_camera_name = "orbbec_camera"; // Assuming this is declared elsewhere
std::string g_time_domain = "global"; // Assuming this is declared elsewhere
namespace {
constexpr auto kStreamStartDelayAfterReconnect = std::chrono::seconds(5);
std::string getLogDirectoryForCamera(const std::string &camera_name) {
const char *log_dir_override = std::getenv("ORBBEC_LOG_DIR");
if (log_dir_override && log_dir_override[0] != '\0') {
@@ -77,7 +79,7 @@ void signalHandler(int sig) {
_exit(sig);
}
std::cout << "Received signal: " << sig << std::endl;
std::cerr << "Received signal: " << sig << std::endl;
if (sig == SIGINT || sig == SIGTERM) {
static int signal_count = 0;
signal_count++;
@@ -111,7 +113,7 @@ void signalHandler(int sig) {
std::filesystem::create_directories(log_dir);
}
std::cout << "Log crash stack trace to " << log_file_path.string() << std::endl;
std::cerr << "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()) {
@@ -475,6 +477,7 @@ void OBCameraNodeDriver::onDeviceDisconnected(const std::shared_ptr<ob::DeviceLi
if (uid == device_unique_id_ || serial_number_ == serial_number) {
RCLCPP_INFO_STREAM(logger_,
"device with " << uid << " disconnected, notify reset device thread");
delay_stream_start_after_reconnect_ = true;
reset_device_flag_ = true;
reset_device_cond_.notify_all();
break;
@@ -905,6 +908,7 @@ void OBCameraNodeDriver::rebootDeviceCallback(
} else {
std::string current_device_uid = device_unique_id_;
RCLCPP_INFO_STREAM(logger_, "Rebooting device with UID: " << current_device_uid);
delay_stream_start_after_reconnect_ = true;
if (ob_lidar_node_) {
ob_lidar_node_->rebootDevice();
} else if (ob_camera_node_) {
@@ -1329,6 +1333,12 @@ void OBCameraNodeDriver::initializeDevice(const std::shared_ptr<ob::Device> &dev
}
}
const bool should_delay_stream_start = delay_stream_start_after_reconnect_.exchange(false) &&
isGemini305SeriesPID(device_info_->getPid());
if (should_delay_stream_start) {
std::this_thread::sleep_for(kStreamStartDelayAfterReconnect);
}
if (ob_camera_node_) {
ob_camera_node_->startIMU();
ob_camera_node_->startStreams();
@@ -1739,6 +1749,7 @@ void OBCameraNodeDriver::firmwareUpdateCallback(OBFwUpdateState state, const cha
RCLCPP_WARN_STREAM(logger_, "Exception during sync timer cleanup in firmware update");
}
}
delay_stream_start_after_reconnect_ = true;
device_->reboot();
} else if (ob_lidar_node_) {
ob_lidar_node_.reset();
+323 -93
View File
@@ -15,6 +15,8 @@
*******************************************************************************/
#include "orbbec_camera/ob_camera_node.h"
#include <algorithm>
#include <cctype>
#include <rclcpp/rclcpp.hpp>
#include <nlohmann/json.hpp>
#include <thread>
@@ -72,6 +74,28 @@ std::string disparityToDepthModeToString(bool hardware_enabled, bool software_en
return "disable";
}
bool isPropertySupported(const std::shared_ptr<ob::Device>& device, OBPropertyID property_id,
OBPermissionType permission) {
if (!device) {
return false;
}
try {
return device->isPropertySupported(property_id, permission);
} catch (...) {
return false;
}
}
bool isPropertyReadable(const std::shared_ptr<ob::Device>& device, OBPropertyID property_id) {
return isPropertySupported(device, property_id, OB_PERMISSION_READ) ||
isPropertySupported(device, property_id, OB_PERMISSION_READ_WRITE);
}
bool isPropertyWritable(const std::shared_ptr<ob::Device>& device, OBPropertyID property_id) {
return isPropertySupported(device, property_id, OB_PERMISSION_WRITE) ||
isPropertySupported(device, property_id, OB_PERMISSION_READ_WRITE);
}
std::string OBSyncModeToString(const OBMultiDeviceSyncMode& mode) {
switch (mode) {
case OBMultiDeviceSyncMode::OB_MULTI_DEVICE_SYNC_MODE_FREE_RUN:
@@ -178,56 +202,80 @@ void OBCameraNode::setupCameraCtrlServices() {
setRotationCallback(request, response, stream_index);
});
}
set_fan_work_mode_srv_ = node_->create_service<SetInt32>(
"set_fan_work_mode", [this](const std::shared_ptr<SetInt32::Request> request,
std::shared_ptr<SetInt32::Response> response) {
setFanWorkModeCallback(request, response);
});
set_floor_enable_srv_ = node_->create_service<SetBool>(
"set_floor_enable", [this](const std::shared_ptr<rmw_request_id_t> request_header,
if (isPropertyWritable(device_, OB_PROP_FAN_WORK_MODE_INT)) {
set_fan_work_mode_srv_ = node_->create_service<SetInt32>(
"set_fan_work_mode", [this](const std::shared_ptr<SetInt32::Request> request,
std::shared_ptr<SetInt32::Response> response) {
setFanWorkModeCallback(request, response);
});
}
if (isPropertyWritable(device_, OB_PROP_FLOOD_BOOL)) {
set_floor_enable_srv_ = node_->create_service<SetBool>(
"set_floor_enable", [this](const std::shared_ptr<rmw_request_id_t> request_header,
const std::shared_ptr<SetBool::Request> request,
std::shared_ptr<SetBool::Response> response) {
setFloorEnableCallback(request_header, request, response);
});
}
if (isPropertyWritable(device_, OB_PROP_LASER_CONTROL_INT) ||
isPropertyWritable(device_, OB_PROP_LASER_BOOL)) {
set_laser_enable_srv_ = node_->create_service<SetBool>(
"set_laser_enable", [this](const std::shared_ptr<rmw_request_id_t> request_header,
const std::shared_ptr<SetBool::Request> request,
std::shared_ptr<SetBool::Response> response) {
setLaserEnableCallback(request_header, request, response);
});
}
if (isPropertyWritable(device_, OB_PROP_LDP_BOOL) &&
((isPropertyReadable(device_, OB_PROP_LASER_CONTROL_INT) &&
isPropertyWritable(device_, OB_PROP_LASER_CONTROL_INT)) ||
(isPropertyReadable(device_, OB_PROP_LASER_BOOL) &&
isPropertyWritable(device_, OB_PROP_LASER_BOOL)))) {
set_ldp_enable_srv_ = node_->create_service<SetBool>(
"set_ldp_enable", [this](const std::shared_ptr<rmw_request_id_t> request_header,
const std::shared_ptr<SetBool::Request> request,
std::shared_ptr<SetBool::Response> response) {
setFloorEnableCallback(request_header, request, response);
});
set_laser_enable_srv_ = node_->create_service<SetBool>(
"set_laser_enable", [this](const std::shared_ptr<rmw_request_id_t> request_header,
const std::shared_ptr<SetBool::Request> request,
std::shared_ptr<SetBool::Response> response) {
setLaserEnableCallback(request_header, request, response);
});
set_ldp_enable_srv_ = node_->create_service<SetBool>(
"set_ldp_enable", [this](const std::shared_ptr<rmw_request_id_t> request_header,
const std::shared_ptr<SetBool::Request> request,
std::shared_ptr<SetBool::Response> response) {
setLdpEnableCallback(request_header, request, response);
});
get_ldp_status_srv_ = node_->create_service<GetBool>(
"get_ldp_status", [this](const std::shared_ptr<rmw_request_id_t> request_header,
const std::shared_ptr<GetBool::Request> request,
std::shared_ptr<GetBool::Response> response) {
(void)request_header;
getLdpStatusCallback(request, response);
});
get_laser_status_srv_ = node_->create_service<GetBool>(
"get_laser_status", [this](const std::shared_ptr<rmw_request_id_t> request_header,
setLdpEnableCallback(request_header, request, response);
});
}
if (isPropertyReadable(device_, OB_PROP_LDP_BOOL) &&
isPropertyReadable(device_, OB_PROP_LDP_STATUS_BOOL)) {
get_ldp_status_srv_ = node_->create_service<GetBool>(
"get_ldp_status", [this](const std::shared_ptr<rmw_request_id_t> request_header,
const std::shared_ptr<GetBool::Request> request,
std::shared_ptr<GetBool::Response> response) {
(void)request_header;
getLaserStatusCallback(request, response);
});
set_ptp_config_srv_ = node_->create_service<SetBool>(
"set_ptp_config", [this](const std::shared_ptr<rmw_request_id_t> request_header,
const std::shared_ptr<SetBool::Request> request,
std::shared_ptr<SetBool::Response> response) {
setPtpConfigCallback(request_header, request, response);
});
get_ptp_config_srv_ = node_->create_service<GetBool>(
"get_ptp_config", [this](const std::shared_ptr<rmw_request_id_t> request_header,
const std::shared_ptr<GetBool::Request> request,
std::shared_ptr<GetBool::Response> response) {
(void)request_header;
getPtpConfigCallback(request, response);
});
(void)request_header;
getLdpStatusCallback(request, response);
});
}
if (isPropertyReadable(device_, OB_PROP_LASER_CONTROL_INT) ||
isPropertyReadable(device_, OB_PROP_LASER_BOOL)) {
get_laser_status_srv_ = node_->create_service<GetBool>(
"get_laser_status", [this](const std::shared_ptr<rmw_request_id_t> request_header,
const std::shared_ptr<GetBool::Request> request,
std::shared_ptr<GetBool::Response> response) {
(void)request_header;
getLaserStatusCallback(request, response);
});
}
if (isPropertyReadable(device_, OB_DEVICE_PTP_CLOCK_SYNC_ENABLE_BOOL) &&
isPropertyWritable(device_, OB_DEVICE_PTP_CLOCK_SYNC_ENABLE_BOOL)) {
set_ptp_config_srv_ = node_->create_service<SetBool>(
"set_ptp_config", [this](const std::shared_ptr<rmw_request_id_t> request_header,
const std::shared_ptr<SetBool::Request> request,
std::shared_ptr<SetBool::Response> response) {
setPtpConfigCallback(request_header, request, response);
});
}
if (isPropertyReadable(device_, OB_DEVICE_PTP_CLOCK_SYNC_ENABLE_BOOL)) {
get_ptp_config_srv_ = node_->create_service<GetBool>(
"get_ptp_config", [this](const std::shared_ptr<rmw_request_id_t> request_header,
const std::shared_ptr<GetBool::Request> request,
std::shared_ptr<GetBool::Response> response) {
(void)request_header;
getPtpConfigCallback(request, response);
});
}
get_white_balance_srv_ = node_->create_service<GetInt32>(
"get_white_balance", [this](const std::shared_ptr<GetInt32::Request> request,
@@ -279,31 +327,42 @@ void OBCameraNode::setupCameraCtrlServices() {
std::shared_ptr<SetString::Response> response) {
exportConfigJsonCallback(request, response);
});
switch_ir_camera_srv_ = node_->create_service<SetString>(
"switch_ir", [this](const std::shared_ptr<SetString::Request> request,
std::shared_ptr<SetString::Response> response) {
switchIRCameraCallback(request, response);
});
set_ir_long_exposure_srv_ = node_->create_service<SetBool>(
"set_ir_long_exposure", [this](const std::shared_ptr<SetBool::Request> request,
std::shared_ptr<SetBool::Response> response) {
setIRLongExposureCallback(request, response);
});
get_lrm_measure_distance_srv_ = node_->create_service<GetInt32>(
"get_lrm_measure_distance", [this](const std::shared_ptr<GetInt32::Request> request,
std::shared_ptr<GetInt32::Response> response) {
getLrmMeasureDistanceCallback(request, response);
});
set_reset_timestamp_srv_ = node_->create_service<SetBool>(
"set_reset_timestamp", [this](const std::shared_ptr<SetBool::Request> request,
std::shared_ptr<SetBool::Response> response) {
setRESETTimestampCallback(request, response);
});
set_interleaver_laser_sync_srv_ = node_->create_service<SetInt32>(
"set_sync_interleaverlaser", [this](const std::shared_ptr<SetInt32::Request> request,
std::shared_ptr<SetInt32::Response> response) {
setSYNCInterleaveLaserCallback(request, response);
});
if (isPropertyWritable(device_, OB_PROP_IR_CHANNEL_DATA_SOURCE_INT)) {
switch_ir_camera_srv_ = node_->create_service<SetString>(
"switch_ir", [this](const std::shared_ptr<SetString::Request> request,
std::shared_ptr<SetString::Response> response) {
switchIRCameraCallback(request, response);
});
}
if (isPropertyWritable(device_, OB_PROP_IR_LONG_EXPOSURE_BOOL)) {
set_ir_long_exposure_srv_ = node_->create_service<SetBool>(
"set_ir_long_exposure", [this](const std::shared_ptr<SetBool::Request> request,
std::shared_ptr<SetBool::Response> response) {
setIRLongExposureCallback(request, response);
});
}
if (isPropertyReadable(device_, OB_PROP_LDP_MEASURE_DISTANCE_INT)) {
get_lrm_measure_distance_srv_ = node_->create_service<GetInt32>(
"get_lrm_measure_distance", [this](const std::shared_ptr<GetInt32::Request> request,
std::shared_ptr<GetInt32::Response> response) {
getLrmMeasureDistanceCallback(request, response);
});
}
if (isPropertyWritable(device_, OB_PROP_TIMER_RESET_TRIGGER_OUT_ENABLE_BOOL) &&
isPropertyWritable(device_, OB_PROP_TIMER_RESET_SIGNAL_BOOL)) {
set_reset_timestamp_srv_ = node_->create_service<SetBool>(
"set_reset_timestamp", [this](const std::shared_ptr<SetBool::Request> request,
std::shared_ptr<SetBool::Response> response) {
setRESETTimestampCallback(request, response);
});
}
if (isPropertyWritable(device_, OB_PROP_FRAME_INTERLEAVE_LASER_PATTERN_SYNC_DELAY_INT)) {
set_interleaver_laser_sync_srv_ = node_->create_service<SetInt32>(
"set_sync_interleaverlaser", [this](const std::shared_ptr<SetInt32::Request> request,
std::shared_ptr<SetInt32::Response> response) {
setSYNCInterleaveLaserCallback(request, response);
});
}
set_sync_host_time_srv_ = node_->create_service<SetBool>(
"set_sync_hosttime", [this](const std::shared_ptr<SetBool::Request> request,
std::shared_ptr<SetBool::Response> response) {
@@ -351,6 +410,16 @@ void OBCameraNode::setupCameraCtrlServices() {
std::shared_ptr<SetBool::Response> response) {
setStreamsEnableCallback(request, response);
});
set_image_registration_mode_srv_ = node_->create_service<SetString>(
"set_image_registration_mode", [this](const std::shared_ptr<SetString::Request> request,
std::shared_ptr<SetString::Response> response) {
setImageRegistrationModeCallback(request, response);
});
set_stream_profile_srv_ = node_->create_service<SetStreamProfile>(
"set_stream_profile", [this](const std::shared_ptr<SetStreamProfile::Request> request,
std::shared_ptr<SetStreamProfile::Response> response) {
setStreamProfileCallback(request, response);
});
get_streams_enable_srv_ = node_->create_service<GetBool>(
"get_streams_enable", [this](const std::shared_ptr<GetBool::Request> request,
std::shared_ptr<GetBool::Response> response) {
@@ -366,21 +435,27 @@ 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,
if (isPropertyWritable(device_, OB_PROP_DISP_SEARCH_RANGE_MODE_INT)) {
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);
});
}
if (isPropertyWritable(device_, OB_PROP_DISP_SEARCH_OFFSET_INT)) {
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);
});
}
if (isPropertyWritable(device_, OB_PROP_USB_SYNC_VOLTAGE_LEVEL_INT)) {
set_sync_io_voltage_level_srv_ = node_->create_service<SetInt32>(
"set_sync_io_voltage_level", [this](const std::shared_ptr<SetInt32::Request> request,
std::shared_ptr<SetInt32::Response> response) {
setDisparitySearchOffsetCallback(request, response);
});
set_sync_io_voltage_level_srv_ = node_->create_service<SetInt32>(
"set_sync_io_voltage_level", [this](const std::shared_ptr<SetInt32::Request> request,
std::shared_ptr<SetInt32::Response> response) {
setSyncIoVoltageLevelCallback(request, response);
});
setSyncIoVoltageLevelCallback(request, response);
});
}
}
void OBCameraNode::getPointCloudDecimationCallback(
@@ -632,6 +707,146 @@ void OBCameraNode::setStreamsEnableCallback(
}
}
void OBCameraNode::setImageRegistrationModeCallback(
const std::shared_ptr<SetString::Request> request,
std::shared_ptr<SetString::Response> response) {
auto mode = request->data;
std::transform(mode.begin(), mode.end(), mode.begin(),
[](unsigned char ch) { return static_cast<char>(std::toupper(ch)); });
if (mode != "OFF" && mode != "HW_D2C" && mode != "SW_D2C" && mode != "SW_C2D") {
response->success = false;
response->message = "Invalid image registration mode '" + request->data +
"'. Valid values: OFF, HW_D2C, SW_D2C, SW_C2D";
return;
}
std::lock_guard<decltype(device_lock_)> lock(device_lock_);
if (mode != "OFF" && (!enable_stream_[COLOR] || !enable_stream_[DEPTH])) {
response->success = false;
response->message =
"Image registration mode " + mode + " requires both color and depth streams to be enabled";
return;
}
const bool old_depth_registration = depth_registration_;
const std::string old_align_mode = align_mode_;
const OBStreamType old_align_target_stream = align_target_stream_;
const bool was_running = pipeline_started_.load();
auto mode_from_state = [](bool depth_registration, const std::string& align_mode,
OBStreamType align_target_stream) {
if (!depth_registration) {
return std::string("OFF");
}
if (align_mode == "HW") {
return std::string("HW_D2C");
}
return align_target_stream == OB_STREAM_DEPTH ? std::string("SW_C2D") : std::string("SW_D2C");
};
const auto old_mode =
mode_from_state(old_depth_registration, old_align_mode, old_align_target_stream);
auto apply_image_registration_mode = [this](const std::string& mode) {
if (mode == "OFF") {
depth_registration_ = false;
align_mode_ = "HW";
align_target_stream_ = OB_STREAM_COLOR;
} else if (mode == "HW_D2C") {
depth_registration_ = true;
align_mode_ = "HW";
align_target_stream_ = OB_STREAM_COLOR;
} else {
depth_registration_ = true;
align_mode_ = "SW";
align_target_stream_ = mode == "SW_C2D" ? OB_STREAM_DEPTH : OB_STREAM_COLOR;
}
align_filter_.reset();
syncSoftwareAlignment();
};
auto restore_old_mode = [this, old_depth_registration, old_align_mode,
old_align_target_stream]() {
depth_registration_ = old_depth_registration;
align_mode_ = old_align_mode;
align_target_stream_ = old_align_target_stream;
align_filter_.reset();
syncSoftwareAlignment();
};
auto rollback_after_error = [&](const std::string& error_message) {
try {
restore_old_mode();
if (was_running && !pipeline_started_.load()) {
startStreams();
}
response->message = "Failed to set image registration mode to " + mode + ": " +
error_message + ". Rolled back to " + old_mode;
} catch (const std::exception& rollback_error) {
response->message = "Failed to set image registration mode to " + mode + ": " +
error_message + ". Rollback to " + old_mode +
" also failed: " + rollback_error.what();
} catch (...) {
response->message = "Failed to set image registration mode to " + mode + ": " +
error_message + ". Rollback to " + old_mode + " also failed";
}
response->success = false;
};
try {
if (was_running) {
stopStreams();
}
apply_image_registration_mode(mode);
if (was_running) {
startStreams();
response->message = "Image registration mode changed from " + old_mode + " to " + mode +
"; streams restarted";
} else {
response->message = "Image registration mode set to " + mode + "; streams remain stopped";
}
response->success = true;
} catch (const ob::Error& e) {
rollback_after_error(orbbec_camera::formatObErrorWithStatus(e));
} catch (const std::exception& e) {
rollback_after_error(e.what());
} catch (...) {
rollback_after_error("unknown error");
}
}
void OBCameraNode::setStreamProfileCallback(
const std::shared_ptr<SetStreamProfile::Request>& request,
std::shared_ptr<SetStreamProfile::Response>& response) {
try {
std::vector<PendingStreamProfile> pending_profiles;
std::string message;
if (!validateStreamProfileRequest(request, pending_profiles, message)) {
response->success = false;
response->message = message;
return;
}
if (!applyStreamProfiles(pending_profiles, message)) {
response->success = false;
response->message = message;
return;
}
response->success = true;
response->message = message;
} 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::getStreamsEnableCallback(
const std::shared_ptr<orbbec_camera_msgs::srv::GetBool::Request> request,
std::shared_ptr<orbbec_camera_msgs::srv::GetBool::Response> response) {
@@ -1089,10 +1304,10 @@ void OBCameraNode::setLaserEnableCallback(
int laser_enable = request->data ? 1 : 0;
try {
bool property_modified = false;
if (device_->isPropertySupported(OB_PROP_LASER_CONTROL_INT, OB_PERMISSION_READ_WRITE)) {
if (isPropertyWritable(device_, OB_PROP_LASER_CONTROL_INT)) {
device_->setIntProperty(OB_PROP_LASER_CONTROL_INT, laser_enable);
property_modified = true;
} else if (device_->isPropertySupported(OB_PROP_LASER_BOOL, OB_PERMISSION_READ_WRITE)) {
} else if (isPropertyWritable(device_, OB_PROP_LASER_BOOL)) {
device_->setIntProperty(OB_PROP_LASER_BOOL, laser_enable);
property_modified = true;
}
@@ -1121,12 +1336,19 @@ void OBCameraNode::setLdpEnableCallback(
bool ldp_enable = request->data;
try {
bool property_modified = false;
if (device_->isPropertySupported(OB_PROP_LASER_CONTROL_INT, OB_PERMISSION_READ_WRITE)) {
if (!isPropertyWritable(device_, OB_PROP_LDP_BOOL)) {
response->success = false;
response->message = "LDP property is not supported";
return;
}
if (isPropertyReadable(device_, OB_PROP_LASER_CONTROL_INT) &&
isPropertyWritable(device_, OB_PROP_LASER_CONTROL_INT)) {
auto laser_enable = device_->getIntProperty(OB_PROP_LASER_CONTROL_INT);
device_->setBoolProperty(OB_PROP_LDP_BOOL, ldp_enable);
device_->setIntProperty(OB_PROP_LASER_CONTROL_INT, laser_enable);
property_modified = true;
} else if (device_->isPropertySupported(OB_PROP_LASER_BOOL, OB_PERMISSION_READ_WRITE)) {
} else if (isPropertyReadable(device_, OB_PROP_LASER_BOOL) &&
isPropertyWritable(device_, OB_PROP_LASER_BOOL)) {
if (!ldp_enable) {
auto laser_enable = device_->getIntProperty(OB_PROP_LASER_BOOL);
device_->setBoolProperty(OB_PROP_LDP_BOOL, ldp_enable);
@@ -1139,6 +1361,10 @@ void OBCameraNode::setLdpEnableCallback(
}
if (property_modified) {
enable_ldp_ = ldp_enable;
} else {
response->success = false;
response->message = "Laser property is not supported";
return;
}
response->success = true;
} catch (const ob::Error& e) {
@@ -1598,10 +1824,14 @@ void OBCameraNode::getLaserStatusCallback(const std::shared_ptr<GetBool::Request
std::shared_ptr<GetBool::Response>& response) {
(void)request;
try {
if (device_->isPropertySupported(OB_PROP_LASER_CONTROL_INT, OB_PERMISSION_READ_WRITE)) {
if (isPropertyReadable(device_, OB_PROP_LASER_CONTROL_INT)) {
response->data = device_->getBoolProperty(OB_PROP_LASER_CONTROL_INT);
} else if (device_->isPropertySupported(OB_PROP_LASER_BOOL, OB_PERMISSION_READ_WRITE)) {
} else if (isPropertyReadable(device_, OB_PROP_LASER_BOOL)) {
response->data = device_->getBoolProperty(OB_PROP_LASER_BOOL);
} else {
response->success = false;
response->message = "Laser property is not supported";
return;
}
response->success = true;
} catch (const ob::Error& e) {
@@ -1623,8 +1853,8 @@ void OBCameraNode::setPtpConfigCallback(
(void)request_header;
try {
if (!device_->isPropertySupported(OB_DEVICE_PTP_CLOCK_SYNC_ENABLE_BOOL,
OB_PERMISSION_READ_WRITE)) {
if (!isPropertyReadable(device_, OB_DEVICE_PTP_CLOCK_SYNC_ENABLE_BOOL) ||
!isPropertyWritable(device_, OB_DEVICE_PTP_CLOCK_SYNC_ENABLE_BOOL)) {
response->success = false;
RCLCPP_ERROR(logger_, "PTP clock sync property is not supported or not writable");
return;
+40
View File
@@ -93,6 +93,43 @@ std::string ipSourceTypeToString(int ip_source_type) {
}
}
std::string deviceAccessStateToString(OBDeviceAccessState state) {
switch (state) {
case OB_DEVICE_ACCESS_STATE_UNKNOWN:
return "UNKNOWN";
case OB_DEVICE_ACCESS_STATE_UNSUPPORTED:
return "UNSUPPORTED";
case OB_DEVICE_ACCESS_STATE_AVAILABLE:
return "AVAILABLE";
case OB_DEVICE_ACCESS_STATE_CONTROLLED:
return "CONTROLLED";
case OB_DEVICE_ACCESS_STATE_EXCLUSIVE:
return "EXCLUSIVE";
case OB_DEVICE_ACCESS_STATE_UNREACHABLE:
return "UNREACHABLE";
case OB_DEVICE_ACCESS_STATE_FW_NOT_SUPPORTED:
return "FW_NOT_SUPPORTED";
default:
return "UNKNOWN(" + std::to_string(static_cast<int>(state)) + ")";
}
}
void printDeviceAccessState(const std::shared_ptr<ob::DeviceList> &list, uint32_t index) {
auto logger = rclcpp::get_logger("list_device_node");
try {
const auto state = list->queryDeviceAccessState(index);
RCLCPP_INFO_STREAM(
logger, "device access state [serial: " << list->getSerialNumber(index)
<< ", ip: " << list->getIpAddress(index)
<< "]: " << deviceAccessStateToString(state));
} catch (const ob::Error &e) {
RCLCPP_WARN_STREAM(logger, "device access state: UNKNOWN ("
<< orbbec_camera::formatObErrorWithStatus(e) << ")");
} catch (const std::exception &e) {
RCLCPP_WARN_STREAM(logger, "device access state: UNKNOWN (" << e.what() << ")");
}
}
std::string boolToString(bool value) { return value ? "true" : "false"; }
bool isPropertyReadable(const std::shared_ptr<ob::Device> &device, OBPropertyID property_id) {
@@ -224,6 +261,9 @@ int main(int argc, char **argv) {
bool firmware_log_enabled = false;
for (size_t i = 0; i < list->deviceCount(); i++) {
try {
if (std::string(list->getConnectionType(i)) == "Ethernet") {
printDeviceAccessState(list, static_cast<uint32_t>(i));
}
auto device_ = list->getDevice(i);
if (isSdkLogEnabled(args.sdk_log_level)) {
firmware_log_enabled = enableFirmwareLog(device_) || firmware_log_enabled;
+2
View File
@@ -25,6 +25,7 @@ rosidl_generate_interfaces(
"msg/Metadata.msg"
"msg/IMUInfo.msg"
"msg/RGBD.msg"
"msg/StreamProfile.msg"
"srv/GetBool.srv"
"srv/GetDeviceConfig.srv"
"srv/GetDeviceInfo.srv"
@@ -38,6 +39,7 @@ rosidl_generate_interfaces(
"srv/GetUserCalibParams.srv"
"srv/SetUserCalibParams.srv"
"srv/SetBagRecording.srv"
"srv/SetStreamProfile.srv"
DEPENDENCIES
sensor_msgs
std_msgs
+5
View File
@@ -0,0 +1,5 @@
string stream_name
int32 width
int32 height
int32 fps
string format
+1 -1
View File
@@ -2,7 +2,7 @@
<?xml-model href="http://download.ros.org/schema/package_format3.xsd" schematypens="http://www.w3.org/2001/XMLSchema"?>
<package format="3">
<name>orbbec_camera_msgs</name>
<version>2.9.1</version>
<version>2.9.3</version>
<description>A package containing orbbec camera messages definitions.</description>
<maintainer email="yalian@orbbec.com">yalian</maintainer>
<license>Apache-2.0</license>
@@ -0,0 +1,4 @@
StreamProfile[] profiles
---
bool success
string message
+1 -1
View File
@@ -2,7 +2,7 @@
<?xml-model href="http://download.ros.org/schema/package_format3.xsd" schematypens="http://www.w3.org/2001/XMLSchema"?>
<package format="3">
<name>orbbec_description</name>
<version>2.9.1</version>
<version>2.9.3</version>
<description>TODO: Package description</description>
<maintainer email="yalian@orbbec.com">yalian</maintainer>
<license>Apache-2.0</license>