Skip to content

Commit ebc9bbc

Browse files
committed
Update gitignore
1 parent f8ec713 commit ebc9bbc

File tree

4 files changed

+203
-1
lines changed

4 files changed

+203
-1
lines changed

.gitignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,7 @@ webpack-stats.json
118118
*.DS_Store
119119
react_frontend/static
120120
developer_scripts
121-
src
121+
# src
122122
!/react_frontend/src
123123

124124
# Intermediate file created in root during development
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: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
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<BumperNode> HAL::bumper_node_ = nullptr;
8+
9+
HAL::HAL() : Node("hal_node")
10+
{
11+
std::vector<std::string> bumper_topics = {
12+
"/roombaROS/events/right_bumper",
13+
"/roombaROS/events/center_bumper",
14+
"/roombaROS/events/left_bumper"
15+
};
16+
17+
motors_node_ = std::make_shared<MotorsNode>("/cmd_vel", 1.0, 1.0);
18+
laser_node_ = std::make_shared<LaserNode>("/roombaROS/laser/scan");
19+
bumper_node_ = std::make_shared<BumperNode>(bumper_topics);
20+
21+
spin_thread_ = std::thread([]() {
22+
rclcpp::executors::SingleThreadedExecutor executor;
23+
executor.add_node(HAL::motors_node_);
24+
executor.add_node(HAL::laser_node_);
25+
executor.add_node(HAL::bumper_node_);
26+
27+
while (rclcpp::ok()) {
28+
executor.spin_some();
29+
std::this_thread::sleep_for(std::chrono::milliseconds(10));
30+
}
31+
});
32+
spin_thread_.detach();
33+
}
34+
35+
void HAL::set_v(const float speed)
36+
{
37+
if (motors_node_) motors_node_->sendV(static_cast<double>(speed));
38+
}
39+
40+
void HAL::set_w(const float speed)
41+
{
42+
if (motors_node_) motors_node_->sendW(static_cast<double>(speed));
43+
}
44+
45+
const LaserData *HAL::get_laser_data()
46+
{
47+
if (!laser_node_) return nullptr;
48+
return new LaserData(laser_node_->getLaserData());
49+
}
50+
51+
std::vector<bool> HAL::get_bumper_data()
52+
{
53+
std::vector<bool> v = {false, false, false};
54+
if (bumper_node_) {
55+
BumperData b_data = bumper_node_->getBumperData();
56+
if (b_data.state == 1 && b_data.bumper >= 0 && b_data.bumper < 3) {
57+
v[b_data.bumper] = true;
58+
}
59+
}
60+
return v;
61+
}
Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
#include "WebGUI.hpp"
2+
#include <tf2/LinearMath/Quaternion.h>
3+
#include <tf2_geometry_msgs/tf2_geometry_msgs.hpp>
4+
#include <iomanip>
5+
#include <sstream>
6+
7+
using namespace std::chrono_literals;
8+
using std::placeholders::_1;
9+
10+
// Statics
11+
std::string WebGUI::img_payload = "";
12+
nav_msgs::msg::Odometry WebGUINode::last_odom = nav_msgs::msg::Odometry();
13+
gazebo_msgs::msg::PerformanceMetrics WebGUINode::last_perf = gazebo_msgs::msg::PerformanceMetrics();
14+
15+
// WebGUINode Implementation
16+
WebGUINode::WebGUINode() : Node("webgui_node")
17+
{
18+
odom_sub_ = create_subscription<nav_msgs::msg::Odometry>(
19+
"/odom", 10, std::bind(&WebGUINode::pose_callback, this, _1));
20+
perf_sub_ = create_subscription<gazebo_msgs::msg::PerformanceMetrics>(
21+
"/performance_metrics", 10, std::bind(&WebGUINode::performance_callback, this, _1));
22+
}
23+
24+
std::vector<double> WebGUINode::get_pose()
25+
{
26+
tf2::Quaternion tf_quat;
27+
tf2::fromMsg(last_odom.pose.pose.orientation, tf_quat);
28+
tf2::Matrix3x3 m(tf_quat);
29+
double roll, pitch, yaw;
30+
m.getRPY(roll, pitch, yaw);
31+
32+
const double x = -30.0 * last_odom.pose.pose.position.x + 171.0;
33+
const double y = 15.0 * last_odom.pose.pose.position.y + 63.0;
34+
return {x, y, yaw};
35+
}
36+
37+
double WebGUINode::get_performance() { return last_perf.real_time_factor; }
38+
39+
void WebGUINode::pose_callback(nav_msgs::msg::Odometry::UniquePtr msg) { last_odom = *msg; }
40+
void WebGUINode::performance_callback(gazebo_msgs::msg::PerformanceMetrics::UniquePtr msg) { last_perf = *msg; }
41+
42+
// WebSocket Session Helper
43+
class session : public std::enable_shared_from_this<session>
44+
{
45+
tcp::resolver resolver_;
46+
websocket::stream<beast::tcp_stream> ws_;
47+
beast::flat_buffer buffer_;
48+
std::string host_, text_;
49+
50+
public:
51+
explicit session(net::io_context &ioc) : resolver_(net::make_strand(ioc)), ws_(net::make_strand(ioc)) {}
52+
53+
void run(char const *host, char const *port, char const *text) {
54+
host_ = host; text_ = text;
55+
buffer_.max_size(1024 * 1024);
56+
resolver_.async_resolve(host, port, beast::bind_front_handler(&session::on_resolve, shared_from_this()));
57+
}
58+
59+
void on_resolve(beast::error_code ec, tcp::resolver::results_type results) {
60+
if (ec) return;
61+
beast::get_lowest_layer(ws_).expires_after(std::chrono::seconds(30));
62+
beast::get_lowest_layer(ws_).async_connect(results, beast::bind_front_handler(&session::on_connect, shared_from_this()));
63+
}
64+
65+
void on_connect(beast::error_code ec, tcp::resolver::results_type::endpoint_type ep) {
66+
if (ec) return;
67+
beast::get_lowest_layer(ws_).expires_never();
68+
ws_.set_option(websocket::stream_base::timeout::suggested(beast::role_type::client));
69+
ws_.read_message_max(1024 * 1024);
70+
ws_.auto_fragment(false);
71+
host_ += ':' + std::to_string(ep.port());
72+
ws_.async_handshake(host_, "", beast::bind_front_handler(&session::on_handshake, shared_from_this()));
73+
}
74+
75+
void on_handshake(beast::error_code ec) {
76+
if (ec) return;
77+
ws_.async_write(net::buffer(text_), beast::bind_front_handler(&session::on_write, shared_from_this()));
78+
}
79+
80+
void on_write(beast::error_code ec, std::size_t) {
81+
if (ec) return;
82+
ws_.async_read(buffer_, beast::bind_front_handler(&session::on_read, shared_from_this()));
83+
}
84+
85+
void on_read(beast::error_code ec, std::size_t) {
86+
if (ec) return;
87+
unsigned char *cp = (unsigned char *)buffer_.data().data();
88+
std::string msg(reinterpret_cast<char const *>(cp));
89+
buffer_.consume(buffer_.size());
90+
91+
auto pose = WebGUINode::get_pose();
92+
json map_j = {pose.at(0), pose.at(1), pose.at(2)};
93+
std::stringstream ss;
94+
ss << std::fixed << std::setprecision(2) << WebGUINode::get_performance();
95+
96+
json j = {{"map", map_j.dump()}, {"brain", Frequency::rate}, {"gui", 20}, {"rtf", ss.str()}, {"fps", -1}, {"lat", -1}};
97+
std::string out = j.dump();
98+
ws_.async_write(net::buffer(out), beast::bind_front_handler(&session::on_write, shared_from_this()));
99+
}
100+
};
101+
102+
WebGUI::WebGUI()
103+
{
104+
net::io_context ioc;
105+
std::make_shared<session>(ioc)->run("127.0.0.1", "2303", "{\"map\":\"(201,85.5,0)\"}");
106+
ioc.run();
107+
}

0 commit comments

Comments
 (0)