rm_vision/io/mindvision/mindvision.cpp
2025-12-15 02:33:20 +08:00

172 lines
4.1 KiB
C++

#include "mindvision.hpp"
#include <libusb-1.0/libusb.h>
#include <stdexcept>
#include "tools/logger.hpp"
using namespace std::chrono_literals;
namespace io
{
MindVision::MindVision(double exposure_ms, double gamma, const std::string & vid_pid)
: exposure_ms_(exposure_ms),
gamma_(gamma),
handle_(-1),
quit_(false),
ok_(false),
queue_(1),
vid_(-1),
pid_(-1)
{
set_vid_pid(vid_pid);
if (libusb_init(NULL)) tools::logger()->warn("Unable to init libusb!");
try_open();
// 守护线程
daemon_thread_ = std::thread{[this] {
while (!quit_) {
std::this_thread::sleep_for(100ms);
if (ok_) continue;
if (capture_thread_.joinable()) capture_thread_.join();
close();
reset_usb();
try_open();
}
}};
}
MindVision::~MindVision()
{
quit_ = true;
if (daemon_thread_.joinable()) daemon_thread_.join();
if (capture_thread_.joinable()) capture_thread_.join();
close();
tools::logger()->info("Mindvision destructed.");
}
void MindVision::read(cv::Mat & img, std::chrono::steady_clock::time_point & timestamp)
{
CameraData data;
queue_.pop(data);
img = data.img;
timestamp = data.timestamp;
}
void MindVision::open()
{
int camera_num = 1;
tSdkCameraDevInfo camera_info_list;
tSdkCameraCapbility camera_capbility;
CameraSdkInit(1);
CameraEnumerateDevice(&camera_info_list, &camera_num);
if (camera_num == 0) throw std::runtime_error("Not found camera!");
if (CameraInit(&camera_info_list, -1, -1, &handle_) != CAMERA_STATUS_SUCCESS)
throw std::runtime_error("Failed to init camera!");
CameraGetCapability(handle_, &camera_capbility);
width_ = camera_capbility.sResolutionRange.iWidthMax;
height_ = camera_capbility.sResolutionRange.iHeightMax;
CameraSetAeState(handle_, FALSE); // 关闭自动曝光
CameraSetExposureTime(handle_, exposure_ms_ * 1e3); // 设置曝光
CameraSetGamma(handle_, gamma_ * 1e2); // 设置伽马
CameraSetIspOutFormat(handle_, CAMERA_MEDIA_TYPE_BGR8); // 设置输出格式为BGR
CameraSetTriggerMode(handle_, 0); // 设置为连续采集模式
CameraSetFrameSpeed(handle_, 1); // 设置为低帧率模式
CameraPlay(handle_);
// 取图线程
capture_thread_ = std::thread{[this] {
tSdkFrameHead head;
BYTE * raw;
ok_ = true;
while (!quit_) {
std::this_thread::sleep_for(1ms);
auto img = cv::Mat(height_, width_, CV_8UC3);
auto status = CameraGetImageBuffer(handle_, &head, &raw, 100);
auto timestamp = std::chrono::steady_clock::now();
if (status != CAMERA_STATUS_SUCCESS) {
tools::logger()->warn("Camera dropped!");
ok_ = false;
break;
}
CameraImageProcess(handle_, raw, img.data, &head);
CameraReleaseImageBuffer(handle_, raw);
queue_.push({img, timestamp});
}
}};
tools::logger()->info("Mindvision opened.");
}
void MindVision::try_open()
{
try {
open();
} catch (const std::exception & e) {
tools::logger()->warn("{}", e.what());
}
}
void MindVision::close()
{
if (handle_ == -1) return;
CameraUnInit(handle_);
}
void MindVision::set_vid_pid(const std::string & vid_pid)
{
auto index = vid_pid.find(':');
if (index == std::string::npos) {
tools::logger()->warn("Invalid vid_pid: \"{}\"", vid_pid);
return;
}
auto vid_str = vid_pid.substr(0, index);
auto pid_str = vid_pid.substr(index + 1);
try {
vid_ = std::stoi(vid_str, 0, 16);
pid_ = std::stoi(pid_str, 0, 16);
} catch (const std::exception &) {
tools::logger()->warn("Invalid vid_pid: \"{}\"", vid_pid);
}
}
void MindVision::reset_usb() const
{
if (vid_ == -1 || pid_ == -1) return;
// https://github.com/ralight/usb-reset/blob/master/usb-reset.c
auto handle = libusb_open_device_with_vid_pid(NULL, vid_, pid_);
if (!handle) {
tools::logger()->warn("Unable to open usb!");
return;
}
if (libusb_reset_device(handle))
tools::logger()->warn("Unable to reset usb!");
else
tools::logger()->info("Reset usb successfully :)");
libusb_close(handle);
}
} // namespace io