Untitled
unknown
plain_text
a year ago
9.9 kB
19
No Index
/*
A bare-bones example node demonstrating the use of the Monocular mode in ORB-SLAM3
Author: Azmyin Md. Kamal
Date: 01/01/24
REQUIREMENTS
* Make sure to set path to your workspace in common.hpp file
*/
//* Includes
#include "ros2_orb_slam3/common.hpp"
#include <queue>
#include <mutex>
std::queue<sensor_msgs::msg::Imu> imuBuffer; // IMU message buffer
std::mutex imuMutex; // Mutex for thread safety
//* Constructor
MonocularMode::MonocularMode() :Node("mono_node_cpp")
{
// Declare parameters to be passsed from command line
// https://roboticsbackend.com/rclcpp-params-tutorial-get-set-ros2-params-with-cpp/
//* Find path to home directory
homeDir = getenv("HOME");
// std::cout<<"Home: "<<homeDir<<std::endl;
// std::cout<<"VLSAM NODE STARTED\n\n";
RCLCPP_INFO(this->get_logger(), "\nORB-SLAM3-V1 NODE STARTED");
this->declare_parameter("node_name_arg", "not_given"); // Name of this agent
this->declare_parameter("voc_file_arg", "file_not_set"); // Needs to be overriden with appropriate name
this->declare_parameter("settings_file_path_arg", "file_path_not_set"); // path to settings file
//* Watchdog, populate default values
nodeName = "not_set";
vocFilePath = "file_not_set";
settingsFilePath = "file_not_set";
//* Populate parameter values
rclcpp::Parameter param1 = this->get_parameter("node_name_arg");
nodeName = param1.as_string();
rclcpp::Parameter param2 = this->get_parameter("voc_file_arg");
vocFilePath = param2.as_string();
rclcpp::Parameter param3 = this->get_parameter("settings_file_path_arg");
settingsFilePath = param3.as_string();
// rclcpp::Parameter param4 = this->get_parameter("settings_file_name_arg");
//* HARDCODED, set paths
if (vocFilePath == "file_not_set" || settingsFilePath == "file_not_set")
{
pass;
vocFilePath = homeDir + "/" + packagePath + "orb_slam3/Vocabulary/ORBvoc.txt.bin";
settingsFilePath = homeDir + "/" + packagePath + "orb_slam3/config/Monocular-Inertial/";
}
// std::cout<<"vocFilePath: "<<vocFilePath<<std::endl;
// std::cout<<"settingsFilePath: "<<settingsFilePath<<std::endl;
//* DEBUG print
RCLCPP_INFO(this->get_logger(), "nodeName %s", nodeName.c_str());
RCLCPP_INFO(this->get_logger(), "voc_file %s", vocFilePath.c_str());
// RCLCPP_INFO(this->get_logger(), "settings_file_path %s", settingsFilePath.c_str());
subexperimentconfigName = "/mono_py_driver/experiment_settings"; // topic that sends out some configuration parameters to the cpp ndoe
pubconfigackName = "/mono_py_driver/exp_settings_ack"; // send an acknowledgement to the python node
subImgMsgName = "/mono_py_driver/img_msg"; // topic to receive RGB image messages
subTimestepMsgName = "/mono_py_driver/timestep_msg"; // topic to receive RGB image messages
subImuMsgName = "/mono_py_driver/imu_msg";
//* subscribe to python node to receive settings
expConfig_subscription_ = this->create_subscription<std_msgs::msg::String>(subexperimentconfigName, 1, std::bind(&MonocularMode::experimentSetting_callback, this, _1));
//* publisher to send out acknowledgement
configAck_publisher_ = this->create_publisher<std_msgs::msg::String>(pubconfigackName, 10);
//* subscribe to receive the timestep
subTimestepMsg_subscription_= this->create_subscription<std_msgs::msg::Float64>(subTimestepMsgName, 1, std::bind(&MonocularMode::Timestep_callback, this, _1));
subImuMsg_subscription_= this->create_subscription<sensor_msgs::msg::Imu>(subImuMsgName, 1, std::bind(&MonocularMode::Imu_callback, this, _1));
//* subscrbite to the image messages coming from the Python driver node
subImgMsg_subscription_= this->create_subscription<sensor_msgs::msg::Image>(subImgMsgName, 1, std::bind(&MonocularMode::Img_callback, this, _1));
RCLCPP_INFO(this->get_logger(), "Waiting to finish handshake ......");
}
//* Destructor
MonocularMode::~MonocularMode()
{
// Stop all threads
// Call method to write the trajectory file
// Release resources and cleanly shutdown
pAgent->Shutdown();
pass;
}
//* Callback which accepts experiment parameters from the Python node
void MonocularMode::experimentSetting_callback(const std_msgs::msg::String& msg){
// std::cout<<"experimentSetting_callback"<<std::endl;
bSettingsFromPython = true;
experimentConfig = msg.data.c_str();
// receivedConfig = experimentConfig; // Redundant
RCLCPP_INFO(this->get_logger(), "Configuration YAML file name: %s", this->receivedConfig.c_str());
//* Publish acknowledgement
auto message = std_msgs::msg::String();
message.data = "ACK";
std::cout<<"Sent response: "<<message.data.c_str()<<std::endl;
configAck_publisher_->publish(message);
//* Wait to complete VSLAM initialization
initializeVSLAM(experimentConfig);
}
//* Method to bind an initialized VSLAM framework to this node
void MonocularMode::initializeVSLAM(std::string& configString){
// Watchdog, if the paths to vocabular and settings files are still not set
if (vocFilePath == "file_not_set" || settingsFilePath == "file_not_set")
{
RCLCPP_ERROR(get_logger(), "Please provide valid voc_file and settings_file paths");
rclcpp::shutdown();
}
//* Build .yaml`s file path
std::cout<<"setting: "<<settingsFilePath<<" "<<"hi"<<std::endl;
//if (settingsFilePath == "/home/reefranger/ros2_test/src/ros2_orb_slam3/orb_slam3/config/Monocular-Inertial/")
settingsFilePath = settingsFilePath.append(configString);
settingsFilePath = settingsFilePath.append(".yaml"); // Example ros2_ws/src/orb_slam3_ros2/orb_slam3/config/Monocular/TUM2.yaml
RCLCPP_INFO(this->get_logger(), "Path to settings file: %s", settingsFilePath.c_str());
// NOTE if you plan on passing other configuration parameters to ORB SLAM3 Systems class, do it here
// NOTE you may also use a .yaml file here to set these values
sensorType = ORB_SLAM3::System::IMU_MONOCULAR;
enablePangolinWindow = true; // Shows Pangolin window output
enableOpenCVWindow = true; // Shows OpenCV window output
pAgent = new ORB_SLAM3::System(vocFilePath, settingsFilePath, sensorType, enablePangolinWindow);
std::cout << "MonocularInertialMode node initialized" << std::endl; // TODO needs a better message
}
//* Callback that processes timestep sent over ROS
void MonocularMode::Timestep_callback(const std_msgs::msg::Float64& time_msg){
// timeStep = 0; // Initialize
timeStep = time_msg.data;
}
void MonocularMode::Imu_callback(const sensor_msgs::msg::Imu& msg)
{
std::lock_guard<std::mutex> lock(imuMutex);
imuBuffer.push(msg);
// Optionally limit buffer size to prevent memory issues
if (imuBuffer.size() > 100) // Example limit
{
imuBuffer.pop();
}
}
//* Callback to process image message and run SLAM node
void MonocularMode::Img_callback(const sensor_msgs::msg::Image& msg)
{
// Initialize
cv_bridge::CvImagePtr cv_ptr; //* Does not create a copy, memory efficient
//* Convert ROS image to openCV image
try
{
//cv::Mat im = cv_bridge::toCvShare(msg.img, msg)->image;
cv_ptr = cv_bridge::toCvCopy(msg); // Local scope
// DEBUGGING, Show image
// Update GUI Window
// cv::imshow("test_window", cv_ptr->image);
// cv::waitKey(3);
}
catch (cv_bridge::Exception& e)
{
RCLCPP_ERROR(this->get_logger(),"Error reading image");
return;
}
auto imuMeasurements = RetrieveIMUData(timeStep);
// std::cout<<std::fixed<<"Timestep: "<<timeStep<<std::endl; // Debug
//* Perform all ORB-SLAM3 operations in Monocular mode
//! Pose with respect to the camera coordinate frame not the world coordinate frame
Sophus::SE3f Tcw = pAgent->TrackMonocular(cv_ptr->image, timeStep,imuMeasurements);
//* An example of what can be done after the pose w.r.t camera coordinate frame is computed by ORB SLAM3
//Sophus::SE3f Twc = Tcw.inverse(); //* Pose with respect to global image coordinate, reserved for future use
}
std::vector<ORB_SLAM3::IMU::Point> MonocularMode::RetrieveIMUData(double timeStep)
{
std::vector<ORB_SLAM3::IMU::Point> imuMeasurements;
std::lock_guard<std::mutex> lock(imuMutex);
while (!imuBuffer.empty()) //&&
//rclcpp::Time(imuBuffer.front().header.stamp).seconds() +
//imuBuffer.front().header.stamp.nanosec * 1e-9 <= timeStep)
//while (!imuBuffer.empty() && rclcpp::Time(imuBuffer.front().header.stamp).seconds() <= timeStep)
{
const auto& imuMsg = imuBuffer.front();
double timestamp_imu = imuMsg.header.stamp.sec + imuMsg.header.stamp.nanosec * 1e-9;
if (timestamp_imu > timeStep)
{
break;
}
RCLCPP_DEBUG(this->get_logger(),
"Image time: %.9f, IMU buffer size: %lu",
timeStep, imuBuffer.size());
std::cout << "Hello, World!" << timestamp_imu << " "<< timeStep << std::endl; // Convert IMU data to ORB-SLAM3 format
cv::Point3f acc(
imuMsg.linear_acceleration.x,
imuMsg.linear_acceleration.y,
imuMsg.linear_acceleration.z);
cv::Point3f gyr(
imuMsg.angular_velocity.x,
imuMsg.angular_velocity.y,
imuMsg.angular_velocity.z);
//auto imuTime = imuMsg.header.stamp;
//double timestamp_imu = imuTime.sec + imuTime.nanosec * 1e-9;
//double timestamp_imu = rclcpp::Time(imuMsg.header.stamp).seconds();
imuMeasurements.push_back(ORB_SLAM3::IMU::Point(acc, gyr, timestamp_imu));
imuBuffer.pop(); // Remove processed IMU message
}
return imuMeasurements;
}
Editor is loading...
Leave a Comment