Files
OrbbecSDK_ROS2/orbbec_camera/src/ob_camera_node_driver.cpp
T

416 lines
16 KiB
C++
Raw Normal View History

2023-09-08 08:55:16 +08:00
/*******************************************************************************
* Copyright (c) 2023 Orbbec 3D Technology, Inc
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*******************************************************************************/
2022-06-08 14:51:00 +08:00
#include "orbbec_camera/ob_camera_node_driver.h"
2022-12-28 13:55:26 +08:00
#include <fcntl.h>
#include <semaphore.h>
#include <sys/shm.h>
2023-03-22 16:10:22 +08:00
#include <ament_index_cpp/get_package_share_directory.hpp>
2023-08-22 21:11:59 +08:00
#include <rclcpp_components/register_node_macro.hpp>
2023-09-05 17:59:19 +08:00
#include <csignal>
2022-12-28 13:55:26 +08:00
2022-06-06 19:00:12 +08:00
namespace orbbec_camera {
OBCameraNodeDriver::OBCameraNodeDriver(const rclcpp::NodeOptions &node_options)
2022-06-06 19:00:12 +08:00
: Node("orbbec_camera_node", "/", node_options),
2023-03-22 16:10:22 +08:00
config_path_(ament_index_cpp::get_package_share_directory("orbbec_camera") +
"/config/OrbbecSDKConfig_v1.0.xml"),
ctx_(std::make_unique<ob::Context>(config_path_.c_str())),
2022-06-06 19:00:12 +08:00
logger_(this->get_logger()) {
init();
}
2023-02-06 17:26:10 +08:00
OBCameraNodeDriver::OBCameraNodeDriver(const std::string &node_name, const std::string &ns,
const rclcpp::NodeOptions &node_options)
2022-06-06 19:00:12 +08:00
: Node(node_name, ns, node_options),
ctx_(std::make_unique<ob::Context>()),
logger_(this->get_logger()) {
init();
}
OBCameraNodeDriver::~OBCameraNodeDriver() {
2022-06-06 19:00:12 +08:00
is_alive_.store(false);
2022-12-28 17:30:12 +08:00
sem_unlink(DEFAULT_SEM_NAME.c_str());
2023-02-06 17:26:10 +08:00
if (int shm_id = shmget(DEFAULT_SEM_KEY, 1, 0666 | IPC_CREAT); shm_id != -1) {
2022-12-28 17:30:12 +08:00
shmctl(shm_id, IPC_RMID, nullptr);
}
if (device_count_update_thread_ && device_count_update_thread_->joinable()) {
device_count_update_thread_->join();
}
2023-07-05 15:00:34 +08:00
if (sync_time_thread_ && sync_time_thread_->joinable()) {
sync_time_thread_->join();
}
2022-12-28 13:55:26 +08:00
if (query_thread_ && query_thread_->joinable()) {
query_thread_->join();
2022-06-06 19:00:12 +08:00
}
2023-07-13 17:15:48 +08:00
if (reset_device_thread_ && reset_device_thread_->joinable()) {
reset_device_cond_.notify_all();
reset_device_thread_->join();
}
2022-06-06 19:00:12 +08:00
}
2022-10-10 18:04:09 +08:00
void OBCameraNodeDriver::init() {
2023-02-06 17:26:10 +08:00
auto log_level_str = declare_parameter<std::string>("log_level", "none");
auto log_level = obLogSeverityFromString(log_level_str);
ob::Context::setLoggerSeverity(log_level);
2022-06-06 19:00:12 +08:00
is_alive_.store(true);
2022-06-08 14:51:00 +08:00
parameters_ = std::make_shared<Parameters>(this);
2022-06-08 13:41:31 +08:00
serial_number_ = declare_parameter<std::string>("serial_number", "");
2023-02-17 22:25:24 +08:00
device_num_ = static_cast<int>(declare_parameter<int>("device_num", 1));
2023-07-05 17:50:44 +08:00
usb_port_ = declare_parameter<std::string>("usb_port", "");
2023-07-05 15:00:34 +08:00
ctx_->setDeviceChangedCallback([this](const std::shared_ptr<ob::DeviceList> &removed_list,
const std::shared_ptr<ob::DeviceList> &added_list) {
2023-02-13 14:58:51 +08:00
(void)added_list;
2023-02-06 17:26:10 +08:00
onDeviceDisconnected(removed_list);
2022-06-06 19:00:12 +08:00
});
2022-12-28 17:11:30 +08:00
check_connect_timer_ =
this->create_wall_timer(std::chrono::milliseconds(1000), [this]() { checkConnectTimer(); });
2023-02-06 17:26:10 +08:00
CHECK_NOTNULL(check_connect_timer_);
2022-12-28 13:55:26 +08:00
query_thread_ = std::make_shared<std::thread>([this]() { queryDevice(); });
device_count_update_thread_ = std::make_shared<std::thread>([this]() { deviceCountUpdate(); });
2023-07-05 15:00:34 +08:00
sync_time_thread_ = std::make_shared<std::thread>([this]() { syncTime(); });
2023-07-13 17:15:48 +08:00
reset_device_thread_ = std::make_shared<std::thread>([this]() { resetDevice(); });
2022-06-06 19:00:12 +08:00
}
void OBCameraNodeDriver::onDeviceConnected(const std::shared_ptr<ob::DeviceList> &device_list) {
2023-02-06 17:40:01 +08:00
CHECK_NOTNULL(device_list);
2022-06-08 13:41:31 +08:00
if (device_list->deviceCount() == 0) {
return;
}
2023-02-13 14:58:51 +08:00
RCLCPP_INFO_STREAM_THROTTLE(logger_, *get_clock(), 1000, "onDeviceConnected");
2022-06-06 19:00:12 +08:00
if (!device_) {
2022-12-28 13:55:26 +08:00
try {
startDevice(device_list);
2023-02-13 14:58:51 +08:00
} catch (ob::Error &e) {
RCLCPP_ERROR_STREAM(logger_, "startDevice failed: " << e.getMessage());
2022-12-28 13:55:26 +08:00
} catch (const std::exception &e) {
RCLCPP_ERROR_STREAM(logger_, "startDevice failed: " << e.what());
} catch (...) {
RCLCPP_ERROR_STREAM(logger_, "startDevice failed");
2022-06-06 19:00:12 +08:00
}
}
}
void OBCameraNodeDriver::onDeviceDisconnected(const std::shared_ptr<ob::DeviceList> &device_list) {
2023-02-06 17:40:01 +08:00
CHECK_NOTNULL(device_list);
2022-06-08 13:41:31 +08:00
if (device_list->deviceCount() == 0) {
return;
2022-06-06 19:00:12 +08:00
}
2023-02-06 17:26:10 +08:00
RCLCPP_INFO_STREAM(logger_, "onDeviceDisconnected");
2023-02-17 22:25:24 +08:00
bool current_device_disconnected = false;
2022-12-28 13:55:26 +08:00
for (size_t i = 0; i < device_list->deviceCount(); i++) {
2023-02-15 19:50:30 +08:00
std::string uid = device_list->uid(i);
2023-02-06 17:26:10 +08:00
std::scoped_lock<decltype(device_lock_)> lock(device_lock_);
2023-02-15 21:20:02 +08:00
RCLCPP_INFO_STREAM(logger_, "device with " << uid << " disconnected");
2023-02-15 19:50:30 +08:00
if (uid == device_unique_id_) {
2023-07-13 17:15:48 +08:00
std::unique_lock<decltype(reset_device_mutex_)> reset_device_lock(reset_device_mutex_);
reset_device_flag_ = true;
reset_device_cond_.notify_all();
2023-02-17 22:25:24 +08:00
current_device_disconnected = true;
2022-12-28 13:55:26 +08:00
break;
2022-06-08 15:33:16 +08:00
}
}
2023-02-17 22:25:24 +08:00
auto connect_event = current_device_disconnected
? DeviceConnectionEvent::kDeviceDisconnected
: DeviceConnectionEvent::kOtherDeviceDisconnected;
updateConnectedDeviceCount(num_devices_connected_, connect_event);
2022-06-08 13:41:31 +08:00
}
OBLogSeverity OBCameraNodeDriver::obLogSeverityFromString(const std::string_view &log_level) {
2022-10-10 18:04:09 +08:00
if (log_level == "debug") {
return OBLogSeverity::OB_LOG_SEVERITY_DEBUG;
} else if (log_level == "info") {
return OBLogSeverity::OB_LOG_SEVERITY_INFO;
} else if (log_level == "warn") {
return OBLogSeverity::OB_LOG_SEVERITY_WARN;
} else if (log_level == "error") {
return OBLogSeverity::OB_LOG_SEVERITY_ERROR;
} else if (log_level == "fatal") {
return OBLogSeverity::OB_LOG_SEVERITY_FATAL;
} else {
2022-12-28 17:11:30 +08:00
return OBLogSeverity::OB_LOG_SEVERITY_NONE;
2022-10-10 18:04:09 +08:00
}
}
2022-12-28 13:55:26 +08:00
2023-03-01 22:01:08 +08:00
void OBCameraNodeDriver::checkConnectTimer() {
2023-02-06 17:26:10 +08:00
if (!device_connected_.load()) {
2023-02-15 21:20:02 +08:00
RCLCPP_ERROR_STREAM(logger_,
"checkConnectTimer: device " << serial_number_ << " not connected");
2022-12-28 17:11:30 +08:00
return;
2023-03-01 22:01:08 +08:00
} else if (!ob_camera_node_) {
device_connected_.store(false);
2022-12-28 17:11:30 +08:00
}
}
2023-02-06 17:26:10 +08:00
void OBCameraNodeDriver::queryDevice() {
2022-12-28 13:55:26 +08:00
while (is_alive_ && rclcpp::ok()) {
2023-02-13 14:58:51 +08:00
if (!device_connected_.load()) {
2023-02-06 17:26:10 +08:00
RCLCPP_INFO_STREAM_THROTTLE(logger_, *get_clock(), 1000, "Waiting for device connection...");
auto device_list = ctx_->queryDeviceList();
if (device_list->deviceCount() == 0) {
std::this_thread::sleep_for(std::chrono::milliseconds(10));
continue;
2022-12-28 13:55:26 +08:00
}
2023-02-06 17:26:10 +08:00
onDeviceConnected(device_list);
} else {
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
2022-12-28 13:55:26 +08:00
}
}
}
void OBCameraNodeDriver::deviceCountUpdate() {
while (is_alive_ && rclcpp::ok()) {
updateConnectedDeviceCount(num_devices_connected_, DeviceConnectionEvent::kDeviceCountUpdate);
std::this_thread::sleep_for(std::chrono::milliseconds(500));
}
}
2023-07-05 15:00:34 +08:00
void OBCameraNodeDriver::syncTime() {
while (is_alive_ && rclcpp::ok()) {
if (device_ && device_info_ && !isOpenNIDevice(device_info_->pid())) {
2023-09-05 17:59:19 +08:00
ctx_->enableDeviceClockSync(0);
}
2023-07-05 15:00:34 +08:00
std::this_thread::sleep_for(std::chrono::milliseconds(5000));
}
}
2023-07-13 17:15:48 +08:00
void OBCameraNodeDriver::resetDevice() {
while (is_alive_ && rclcpp::ok()) {
std::unique_lock<decltype(reset_device_mutex_)> lock(reset_device_mutex_);
reset_device_cond_.wait(lock,
[this]() { return !is_alive_ || !rclcpp::ok() || reset_device_flag_; });
if (!is_alive_ || !rclcpp::ok()) {
break;
}
ob_camera_node_.reset();
device_.reset();
device_info_.reset();
2023-07-13 17:15:48 +08:00
device_connected_ = false;
device_unique_id_.clear();
reset_device_flag_ = false;
}
}
void OBCameraNodeDriver::releaseDeviceSemaphore(sem_t *device_sem, int &num_devices_connected) {
2023-02-17 22:25:24 +08:00
RCLCPP_INFO_THROTTLE(logger_, *get_clock(), 1000, "Release device semaphore");
2023-02-17 20:18:55 +08:00
sem_post(device_sem);
int sem_value = 0;
sem_getvalue(device_sem, &sem_value);
2023-02-17 22:25:24 +08:00
RCLCPP_INFO_STREAM_THROTTLE(logger_, *get_clock(), 1000, "semaphore value: " << sem_value);
RCLCPP_INFO_THROTTLE(logger_, *get_clock(), 1000, "Release device semaphore done");
2023-02-17 20:18:55 +08:00
if (num_devices_connected >= device_num_) {
sem_destroy(device_sem);
sem_unlink(DEFAULT_SEM_NAME.c_str());
2022-06-06 19:00:12 +08:00
}
2023-02-17 20:18:55 +08:00
}
void OBCameraNodeDriver::updateConnectedDeviceCount(int &num_devices_connected,
DeviceConnectionEvent connection_event) {
2023-02-17 20:18:55 +08:00
// write connected device count to file
int shm_id = shmget(DEFAULT_SEM_KEY, 1, 0666 | IPC_CREAT);
if (shm_id == -1) {
RCLCPP_INFO_STREAM(logger_, "Failed to create shared memory " << strerror(errno));
2023-02-17 22:25:24 +08:00
return;
}
auto shm_ptr = (int *)shmat(shm_id, nullptr, 0);
if (shm_ptr == (void *)-1) {
RCLCPP_INFO_STREAM(logger_, "Failed to attach shared memory " << strerror(errno));
return;
}
if (connection_event == DeviceConnectionEvent::kDeviceConnected) {
num_devices_connected = *shm_ptr + 1;
} else if (connection_event == DeviceConnectionEvent::kDeviceDisconnected && *shm_ptr > 0) {
num_devices_connected = *shm_ptr - 1;
2023-02-17 20:18:55 +08:00
} else {
2023-02-17 22:25:24 +08:00
num_devices_connected = *shm_ptr;
}
RCLCPP_DEBUG_STREAM_THROTTLE(logger_, *get_clock(), 5000,
"Current connected device " << num_devices_connected);
2023-02-17 22:25:24 +08:00
*shm_ptr = static_cast<int>(num_devices_connected);
shmdt(shm_ptr);
if (connection_event == DeviceConnectionEvent::kDeviceDisconnected &&
num_devices_connected == 0) {
shmctl(shm_id, IPC_RMID, nullptr);
sem_unlink(DEFAULT_SEM_NAME.c_str());
2023-02-17 20:18:55 +08:00
}
}
std::shared_ptr<ob::Device> OBCameraNodeDriver::selectDevice(
2023-02-17 20:18:55 +08:00
const std::shared_ptr<ob::DeviceList> &list) {
2023-02-06 17:26:10 +08:00
if (device_num_ == 1) {
RCLCPP_INFO_STREAM(logger_, "Connecting to the default device");
2023-02-17 20:18:55 +08:00
return list->getDevice(0);
}
sem_t *device_sem = sem_open(DEFAULT_SEM_NAME.c_str(), O_CREAT, 0644, 1);
if (device_sem == SEM_FAILED) {
RCLCPP_INFO_STREAM(logger_, "Failed to open semaphore");
return nullptr;
}
2023-02-17 22:25:24 +08:00
RCLCPP_INFO_STREAM_THROTTLE(logger_, *get_clock(), 1000,
"Connecting to device with serial number: " << serial_number_);
2023-02-17 20:18:55 +08:00
int sem_value = 0;
sem_getvalue(device_sem, &sem_value);
2023-02-17 22:25:24 +08:00
RCLCPP_INFO_STREAM_THROTTLE(logger_, *get_clock(), 1000, "semaphore value: " << sem_value);
2023-02-17 20:18:55 +08:00
int ret = sem_wait(device_sem);
if (ret != 0) {
RCLCPP_ERROR_STREAM(logger_, "Failed to wait semaphore " << strerror(errno));
2023-02-20 12:11:12 +08:00
releaseDeviceSemaphore(device_sem, num_devices_connected_);
2023-02-17 20:18:55 +08:00
return nullptr;
}
2023-07-05 15:00:34 +08:00
std::shared_ptr<ob::Device> device = nullptr;
if (!serial_number_.empty()) {
RCLCPP_INFO_STREAM_THROTTLE(logger_, *get_clock(), 1000,
"Connecting to device with serial number: " << serial_number_);
device = selectDeviceBySerialNumber(list, serial_number_);
} else if (!usb_port_.empty()) {
RCLCPP_INFO_STREAM_THROTTLE(logger_, *get_clock(), 1000,
"Connecting to device with usb port: " << usb_port_);
device = selectDeviceByUSBPort(list, usb_port_);
}
2023-02-17 22:25:24 +08:00
std::shared_ptr<int> sem_guard(nullptr, [&, device](int const *) {
auto connect_event = device != nullptr ? DeviceConnectionEvent::kDeviceConnected
: DeviceConnectionEvent::kOtherDeviceConnected;
updateConnectedDeviceCount(num_devices_connected_, connect_event);
releaseDeviceSemaphore(device_sem, num_devices_connected_);
});
2023-02-17 20:18:55 +08:00
if (device == nullptr) {
2023-02-17 22:25:24 +08:00
RCLCPP_WARN_THROTTLE(logger_, *get_clock(), 1000, "Device with serial number %s not found",
serial_number_.c_str());
2023-02-17 20:18:55 +08:00
device_connected_ = false;
return nullptr;
}
return device;
}
2023-02-16 16:14:38 +08:00
std::shared_ptr<ob::Device> OBCameraNodeDriver::selectDeviceBySerialNumber(
2023-02-17 20:18:55 +08:00
const std::shared_ptr<ob::DeviceList> &list, const std::string &serial_number) {
std::string lower_sn;
std::transform(serial_number.begin(), serial_number.end(), std::back_inserter(lower_sn),
[](auto ch) { return isalpha(ch) ? tolower(ch) : static_cast<int>(ch); });
for (size_t i = 0; i < list->deviceCount(); i++) {
try {
auto pid = list->pid(i);
2023-03-02 20:15:01 +08:00
if (isOpenNIDevice(pid)) {
2023-02-17 20:18:55 +08:00
// openNI device
auto device = list->getDevice(i);
auto device_info = device->getDeviceInfo();
if (device_info->serialNumber() == serial_number) {
RCLCPP_INFO_STREAM(logger_,
"Device serial number " << device_info->serialNumber() << " matched");
return device;
2023-02-15 15:05:47 +08:00
}
2022-12-28 13:55:26 +08:00
} else {
2023-02-17 20:18:55 +08:00
std::string sn = list->serialNumber(i);
2023-02-17 22:25:24 +08:00
RCLCPP_INFO_STREAM_THROTTLE(logger_, *get_clock(), 1000, "Device serial number: " << sn);
2023-02-17 20:18:55 +08:00
if (sn == serial_number) {
2023-03-02 20:15:01 +08:00
RCLCPP_INFO_STREAM(logger_, "Device serial number " << sn << " matched");
2023-02-17 20:18:55 +08:00
return list->getDevice(i);
2022-12-28 13:55:26 +08:00
}
}
2023-02-17 20:18:55 +08:00
} catch (ob::Error &e) {
2023-02-17 22:25:24 +08:00
RCLCPP_ERROR_STREAM_THROTTLE(logger_, *get_clock(), 1000,
"Failed to get device info " << e.getMessage());
2023-02-17 20:18:55 +08:00
} catch (std::exception &e) {
2023-02-17 22:25:24 +08:00
RCLCPP_ERROR_STREAM(logger_, "Failed to get device info " << e.what());
2023-02-17 20:18:55 +08:00
} catch (...) {
2023-02-17 22:25:24 +08:00
RCLCPP_ERROR_STREAM(logger_, "Failed to get device info");
2022-12-28 13:55:26 +08:00
}
2022-06-06 19:00:12 +08:00
}
2023-02-17 20:18:55 +08:00
return nullptr;
}
2023-07-05 15:00:34 +08:00
std::shared_ptr<ob::Device> OBCameraNodeDriver::selectDeviceByUSBPort(
const std::shared_ptr<ob::DeviceList> &list, const std::string &usb_port) {
for (size_t i = 0; i < list->deviceCount(); i++) {
try {
auto pid = list->pid(i);
if (isOpenNIDevice(pid)) {
// openNI device
auto dev = list->getDevice(i);
auto device_info = dev->getDeviceInfo();
std::string uid = device_info->uid();
auto port_id = parseUsbPort(uid);
if (port_id == usb_port) {
2023-07-13 17:17:37 +08:00
RCLCPP_INFO_STREAM_THROTTLE(logger_, *get_clock(), 1000,
"Device port id " << port_id << " matched");
2023-07-05 15:00:34 +08:00
return dev;
}
} else {
std::string uid = list->uid(i);
auto port_id = parseUsbPort(uid);
2023-07-13 17:15:48 +08:00
RCLCPP_ERROR_STREAM_THROTTLE(logger_, *get_clock(), 1000, "Device usb port: " << uid);
2023-07-05 15:00:34 +08:00
if (port_id == usb_port) {
2023-07-13 17:17:37 +08:00
RCLCPP_INFO_STREAM_THROTTLE(logger_, *get_clock(), 1000,
"Device usb port " << uid << " matched");
2023-07-05 15:00:34 +08:00
return list->getDevice(i);
}
}
} catch (ob::Error &e) {
RCLCPP_ERROR_STREAM(logger_, "Failed to get device info " << e.getMessage());
} catch (std::exception &e) {
RCLCPP_ERROR_STREAM(logger_, "Failed to get device info " << e.what());
} catch (...) {
RCLCPP_ERROR_STREAM(logger_, "Failed to get device info");
}
}
return nullptr;
}
void OBCameraNodeDriver::initializeDevice(const std::shared_ptr<ob::Device> &device) {
2023-02-17 20:18:55 +08:00
device_ = device;
2023-02-06 17:26:10 +08:00
CHECK_NOTNULL(device_);
CHECK_NOTNULL(device_.get());
if (ob_camera_node_) {
ob_camera_node_.reset();
}
ob_camera_node_ = std::make_unique<OBCameraNode>(this, device_, parameters_);
device_connected_ = true;
device_info_ = device_->getDeviceInfo();
CHECK_NOTNULL(device_info_.get());
2023-02-15 19:50:30 +08:00
device_unique_id_ = device_info_->uid();
if (!isOpenNIDevice(device_info_->pid())) {
2023-09-05 17:59:19 +08:00
ctx_->enableDeviceClockSync(0); // sync time stamp
}
2023-02-06 17:26:10 +08:00
RCLCPP_INFO_STREAM(logger_, "Device " << device_info_->name() << " connected");
RCLCPP_INFO_STREAM(logger_, "Serial number: " << device_info_->serialNumber());
RCLCPP_INFO_STREAM(logger_, "Firmware version: " << device_info_->firmwareVersion());
RCLCPP_INFO_STREAM(logger_, "Hardware version: " << device_info_->hardwareVersion());
2023-02-15 21:20:02 +08:00
RCLCPP_INFO_STREAM(logger_, "device unique id: " << device_unique_id_);
2022-06-06 19:00:12 +08:00
}
2023-02-17 20:18:55 +08:00
void OBCameraNodeDriver::startDevice(const std::shared_ptr<ob::DeviceList> &list) {
2023-02-17 20:18:55 +08:00
std::scoped_lock<decltype(device_lock_)> lock(device_lock_);
if (device_connected_) {
return;
}
if (list->deviceCount() == 0) {
RCLCPP_WARN(logger_, "No device found");
return;
}
if (device_) {
device_.reset();
}
auto device = selectDevice(list);
if (device == nullptr) {
2023-02-17 22:25:24 +08:00
RCLCPP_WARN_THROTTLE(logger_, *get_clock(), 1000, "Device with serial number %s not found",
serial_number_.c_str());
2023-02-17 20:18:55 +08:00
device_connected_ = false;
return;
}
initializeDevice(device);
}
2022-06-06 19:00:12 +08:00
} // namespace orbbec_camera
2023-08-22 21:11:59 +08:00
RCLCPP_COMPONENTS_REGISTER_NODE(orbbec_camera::OBCameraNodeDriver)