Skip to content

Commit f0b2edd

Browse files
committed
c++ support for laser mapping
1 parent fcedf7d commit f0b2edd

19 files changed

Lines changed: 960 additions & 0 deletions

File tree

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
cmake_minimum_required(VERSION 3.10)
2+
project(VacuumCleanerLibs CXX)
3+
4+
set(CMAKE_CXX_STANDARD 17)
5+
set(CMAKE_CXX_STANDARD_REQUIRED ON)
6+
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
7+
8+
find_package(ament_cmake REQUIRED)
9+
10+
set(ROS2_PACKAGES
11+
rclcpp
12+
nav_msgs
13+
gazebo_msgs
14+
geometry_msgs
15+
sensor_msgs
16+
std_msgs
17+
tf2
18+
tf2_geometry_msgs
19+
ros_gz_interfaces
20+
)
21+
22+
foreach(pkg IN LISTS ROS2_PACKAGES)
23+
find_package(${pkg} REQUIRED)
24+
endforeach()
25+
26+
find_package(Boost REQUIRED COMPONENTS system)
27+
find_package(nlohmann_json REQUIRED)
28+
find_package(OpenCV REQUIRED)
29+
30+
set(COMMON_INTERFACES_INCLUDE "/home/ws/install/common_interfaces_cpp/include")
31+
set(COMMON_INTERFACES_LIB "/home/ws/install/common_interfaces_cpp/lib/libcommon_interfaces_cpp.so")
32+
33+
set(WEBGUI_ROS_DEPS rclcpp nav_msgs gazebo_msgs tf2 tf2_geometry_msgs sensor_msgs)
34+
set(WEBGUI_SYS_DEPS Frequency Boost::system nlohmann_json::nlohmann_json ${OpenCV_LIBS})
35+
set(HAL_ROS_DEPS rclcpp geometry_msgs sensor_msgs std_msgs ros_gz_interfaces nav_msgs)
36+
37+
# --- libFrequency.so ---
38+
add_library(Frequency SHARED src/Frequency.cpp)
39+
target_include_directories(Frequency PUBLIC include)
40+
41+
# --- libWebGUI.so ---
42+
add_library(WebGUI SHARED src/WebGUI.cpp src/Map.cpp)
43+
target_include_directories(WebGUI PUBLIC include ${OpenCV_INCLUDE_DIRS})
44+
45+
ament_target_dependencies(WebGUI ${WEBGUI_ROS_DEPS})
46+
target_link_libraries(WebGUI ${WEBGUI_SYS_DEPS})
47+
48+
# --- libHAL.so ---
49+
add_library(HAL SHARED src/HAL.cpp)
50+
target_include_directories(HAL PUBLIC include ${COMMON_INTERFACES_INCLUDE})
51+
52+
ament_target_dependencies(HAL ${HAL_ROS_DEPS})
53+
target_link_libraries(HAL ${COMMON_INTERFACES_LIB})
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
#ifndef INCLUDE_FREQUENCY_HPP_
2+
#define INCLUDE_FREQUENCY_HPP_
3+
4+
#include <chrono>
5+
#include <cmath>
6+
#include <thread>
7+
8+
class Frequency
9+
{
10+
private:
11+
std::chrono::high_resolution_clock::time_point last_time;
12+
int is_first_iteration;
13+
14+
public:
15+
Frequency();
16+
~Frequency();
17+
18+
static int rate;
19+
void tick(int ideal_cycle = 50);
20+
};
21+
22+
#endif
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
#ifndef INCLUDE_HAL_HPP_
2+
#define INCLUDE_HAL_HPP_
3+
4+
#include <vector>
5+
#include <memory>
6+
#include <thread>
7+
#include <chrono>
8+
#include "rclcpp/rclcpp.hpp"
9+
#include "common_interfaces_cpp/hal/motors.hpp"
10+
#include "common_interfaces_cpp/hal/laser.hpp"
11+
#include "common_interfaces_cpp/hal/odometry.hpp"
12+
13+
class HAL : public rclcpp::Node
14+
{
15+
public:
16+
HAL();
17+
static void setV(const float speed);
18+
static void setW(const float speed);
19+
static const LaserData *getLaserData();
20+
static const Pose3d *getPose3d();
21+
static const Pose3d *getOdom();
22+
23+
private:
24+
static std::shared_ptr<MotorsNode> motors_node_;
25+
static std::shared_ptr<LaserNode> laser_node_;
26+
static std::shared_ptr<OdometryNode> odometry_node_;
27+
static std::shared_ptr<OdometryNode> noisy_odometry_node_;
28+
std::thread spin_thread_;
29+
};
30+
31+
#endif
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
#ifndef MAP_HPP_
2+
#define MAP_HPP_
3+
4+
#include <functional>
5+
#include <vector>
6+
#include <cmath>
7+
#include <opencv2/opencv.hpp>
8+
9+
struct Pose3D {
10+
double x = 0.0;
11+
double y = 0.0;
12+
double yaw = 0.0;
13+
};
14+
15+
class Map {
16+
public:
17+
Map(std::function<Pose3D()> pose_getter, std::function<Pose3D()> noisy_pose_getter);
18+
19+
cv::Mat RTx(double angle, double tx, double ty, double tz);
20+
cv::Mat RTy(double angle, double tx, double ty, double tz);
21+
cv::Mat RTz(double angle, double tx, double ty, double tz);
22+
cv::Mat RTVacuum();
23+
24+
std::vector<double> getRobotCoordinates();
25+
std::vector<double> getRobotCoordinatesWithNoise();
26+
void reset();
27+
28+
private:
29+
std::function<Pose3D()> pose_getter_;
30+
std::function<Pose3D()> noisy_pose_getter_;
31+
};
32+
33+
#endif
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
#ifndef INCLUDE_WEBGUI_HPP_
2+
#define INCLUDE_WEBGUI_HPP_
3+
4+
#include <string>
5+
#include <vector>
6+
#include <mutex>
7+
#include <thread>
8+
#include <opencv2/opencv.hpp>
9+
#include <boost/beast/core.hpp>
10+
#include <boost/beast/websocket.hpp>
11+
#include <boost/asio/connect.hpp>
12+
#include <boost/asio/ip/tcp.hpp>
13+
#include <boost/asio/strand.hpp>
14+
#include <nlohmann/json.hpp>
15+
#include "rclcpp/rclcpp.hpp"
16+
#include "nav_msgs/msg/odometry.hpp"
17+
#include "sensor_msgs/msg/image.hpp"
18+
19+
namespace beast = boost::beast;
20+
namespace websocket = beast::websocket;
21+
namespace net = boost::asio;
22+
using tcp = net::ip::tcp;
23+
using json = nlohmann::json;
24+
25+
struct Pose3D {
26+
double x = 0.0;
27+
double y = 0.0;
28+
double yaw = 0.0;
29+
};
30+
31+
class WebGUINode : public rclcpp::Node
32+
{
33+
public:
34+
WebGUINode();
35+
static Pose3D get_pose();
36+
static Pose3D get_noisy_pose();
37+
static void set_user_map(const cv::Mat& image);
38+
static cv::Mat get_user_map();
39+
40+
private:
41+
void user_map_callback(sensor_msgs::msg::Image::SharedPtr msg);
42+
void odom_callback(nav_msgs::msg::Odometry::SharedPtr msg);
43+
void noisy_odom_callback(nav_msgs::msg::Odometry::SharedPtr msg);
44+
45+
rclcpp::Subscription<sensor_msgs::msg::Image>::SharedPtr user_map_sub_;
46+
rclcpp::Subscription<nav_msgs::msg::Odometry>::SharedPtr odom_sub_;
47+
rclcpp::Subscription<nav_msgs::msg::Odometry>::SharedPtr noisy_odom_sub_;
48+
49+
static Pose3D last_pose_;
50+
static Pose3D last_noisy_pose_;
51+
static cv::Mat user_map_;
52+
static std::mutex map_mutex_;
53+
};
54+
55+
class WebGUI
56+
{
57+
public:
58+
WebGUI();
59+
static void setUserMap(const cv::Mat& image);
60+
static std::vector<double> poseToMap(double x_prime, double y_prime, double yaw_prime);
61+
static std::string base64_encode(unsigned char const* bytes_to_encode, unsigned int in_len);
62+
};
63+
64+
#endif
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
#include "Frequency.hpp"
2+
3+
int Frequency::rate = 0;
4+
5+
Frequency::Frequency() : is_first_iteration(1) {}
6+
7+
Frequency::~Frequency() {}
8+
9+
void Frequency::tick(int ideal_cycle)
10+
{
11+
const auto ideal_ms = std::chrono::milliseconds(1000 / ideal_cycle);
12+
const auto now = std::chrono::high_resolution_clock::now();
13+
14+
if (is_first_iteration == 1)
15+
{
16+
last_time = now;
17+
is_first_iteration = 0;
18+
return;
19+
}
20+
21+
const auto iter_ms = std::chrono::duration_cast<std::chrono::milliseconds>(now - last_time);
22+
23+
if (iter_ms < ideal_ms)
24+
{
25+
rate = std::round(1000.0 / ideal_ms.count());
26+
std::this_thread::sleep_for(ideal_ms - iter_ms);
27+
}
28+
else
29+
{
30+
rate = std::round(1000.0 / iter_ms.count());
31+
}
32+
33+
last_time = now;
34+
}
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
#include "HAL.hpp"
2+
3+
using namespace std::chrono_literals;
4+
5+
std::shared_ptr<MotorsNode> HAL::motors_node_ = nullptr;
6+
std::shared_ptr<LaserNode> HAL::laser_node_ = nullptr;
7+
std::shared_ptr<OdometryNode> HAL::odometry_node_ = nullptr;
8+
std::shared_ptr<OdometryNode> HAL::noisy_odometry_node_ = nullptr;
9+
10+
HAL::HAL() : Node("hal_node")
11+
{
12+
motors_node_ = std::make_shared<MotorsNode>("/turtlebot3/cmd_vel", 4.0, 0.3);
13+
laser_node_ = std::make_shared<LaserNode>("/turtlebot3/laser/scan");
14+
odometry_node_ = std::make_shared<OdometryNode>("/turtlebot3/odom");
15+
noisy_odometry_node_ = std::make_shared<OdometryNode>("/turtlebot3/odom_noisy", "noisy_odometry_node");
16+
17+
spin_thread_ = std::thread([]() {
18+
rclcpp::executors::MultiThreadedExecutor executor;
19+
executor.add_node(HAL::motors_node_);
20+
executor.add_node(HAL::laser_node_);
21+
executor.add_node(HAL::odometry_node_);
22+
executor.add_node(HAL::noisy_odometry_node_);
23+
24+
while (rclcpp::ok()) {
25+
executor.spin_some();
26+
std::this_thread::sleep_for(std::chrono::milliseconds(11));
27+
}
28+
});
29+
spin_thread_.detach();
30+
}
31+
32+
void HAL::setV(const float speed)
33+
{
34+
if (motors_node_) {
35+
motors_node_->sendV(static_cast<double>(speed));
36+
}
37+
}
38+
39+
void HAL::setW(const float speed)
40+
{
41+
if (motors_node_) {
42+
motors_node_->sendW(static_cast<double>(speed));
43+
}
44+
}
45+
46+
const LaserData *HAL::getLaserData()
47+
{
48+
if (!laser_node_) {
49+
return nullptr;
50+
}
51+
52+
LaserData data = laser_node_->getLaserData();
53+
while (data.values.empty() && rclcpp::ok()) {
54+
std::this_thread::sleep_for(std::chrono::milliseconds(11));
55+
data = laser_node_->getLaserData();
56+
}
57+
return new LaserData(data);
58+
}
59+
60+
const Pose3d *HAL::getPose3d()
61+
{
62+
if (!odometry_node_) {
63+
return nullptr;
64+
}
65+
return new Pose3d(odometry_node_->getPose3d());
66+
}
67+
68+
const Pose3d *HAL::getOdom()
69+
{
70+
if (!noisy_odometry_node_) {
71+
return nullptr;
72+
}
73+
return new Pose3d(noisy_odometry_node_->getPose3d());
74+
}
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
#include "Map.hpp"
2+
3+
Map::Map(std::function<Pose3D()> pose_getter, std::function<Pose3D()> noisy_pose_getter)
4+
: pose_getter_(pose_getter), noisy_pose_getter_(noisy_pose_getter) {}
5+
6+
cv::Mat Map::RTx(double angle, double tx, double ty, double tz) {
7+
cv::Mat RT = (cv::Mat_<double>(4, 4) <<
8+
1, 0, 0, tx,
9+
0, std::cos(angle), -std::sin(angle), ty,
10+
0, std::sin(angle), std::cos(angle), tz,
11+
0, 0, 0, 1);
12+
return RT;
13+
}
14+
15+
cv::Mat Map::RTy(double angle, double tx, double ty, double tz) {
16+
cv::Mat RT = (cv::Mat_<double>(4, 4) <<
17+
std::cos(angle), 0, std::sin(angle), tx,
18+
0, 1, 0, ty,
19+
-std::sin(angle), 0, std::cos(angle), tz,
20+
0, 0, 0, 1);
21+
return RT;
22+
}
23+
24+
cv::Mat Map::RTz(double angle, double tx, double ty, double tz) {
25+
cv::Mat RT = (cv::Mat_<double>(4, 4) <<
26+
std::cos(angle), -std::sin(angle), 0, tx,
27+
std::sin(angle), std::cos(angle), 0, ty,
28+
0, 0, 1, tz,
29+
0, 0, 0, 1);
30+
return RT;
31+
}
32+
33+
cv::Mat Map::RTVacuum() {
34+
return RTz(M_PI / 2.0, 50, 70, 0);
35+
}
36+
37+
std::vector<double> Map::getRobotCoordinates() {
38+
Pose3D pose = pose_getter_();
39+
double x = pose.x;
40+
double y = pose.y;
41+
42+
double scale_y = -23.53;
43+
double offset_y = -31.95;
44+
y = scale_y * (offset_y - y);
45+
46+
double scale_x = -23.58;
47+
double offset_x = -20.36;
48+
x = scale_x * (offset_x - x);
49+
50+
return {x, y, pose.yaw};
51+
}
52+
53+
std::vector<double> Map::getRobotCoordinatesWithNoise() {
54+
Pose3D pose = noisy_pose_getter_();
55+
double x = pose.x;
56+
double y = pose.y;
57+
58+
double scale_y = -23.53;
59+
double offset_y = -31.95;
60+
y = scale_y * (offset_y - y);
61+
62+
double scale_x = -23.58;
63+
double offset_x = -20.36;
64+
x = scale_x * (offset_x - x);
65+
66+
return {x, y, pose.yaw};
67+
}
68+
69+
void Map::reset() {
70+
}

0 commit comments

Comments
 (0)