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