1+ /*
2+ Copyright (C) 2025 ardupilot.org
3+
4+ This program is free software: you can redistribute it and/or modify
5+ it under the terms of the GNU Lesser General Public License as published by
6+ the Free Software Foundation, either version 3 of the License, or
7+ (at your option) any later version.
8+
9+ This program is distributed in the hope that it will be useful,
10+ but WITHOUT ANY WARRANTY; without even the implied warranty of
11+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+ GNU General Public License for more details.
13+
14+ You should have received a copy of the GNU Lesser General Public License
15+ along with this program. If not, see <http://www.gnu.org/licenses/>.
16+ */
17+
18+ #include < rapidjson/stringbuffer.h>
19+ #include < rapidjson/writer.h>
20+
21+ #include < gz/msgs/boolean.pb.h>
22+ #include < gz/msgs/clock.pb.h>
23+ #include < gz/msgs/double.pb.h>
24+ #include < gz/msgs/imu.pb.h>
25+ #include < gz/msgs/model.pb.h>
26+ #include < gz/msgs/odometry.pb.h>
27+ #include < gz/msgs/pose.pb.h>
28+ #include < gz/msgs/pose_v.pb.h>
29+ #include < gz/msgs/stringmsg.pb.h>
30+
31+ #include < cstdint>
32+ #include < chrono>
33+ #include < memory>
34+ #include < mutex>
35+ #include < string>
36+ #include < vector>
37+
38+ #include < gz/math/Pose3.hh>
39+ #include < gz/math/Vector3.hh>
40+
41+ #include < gz/msgs/Utility.hh>
42+
43+ #include < gz/transport/Node.hh>
44+
45+ #include " SocketUDP.hh"
46+ #include " Util.hh"
47+
48+ struct servo_packet_16 {
49+ uint16_t magic; // 18458 expected magic value
50+ uint16_t frame_rate;
51+ uint32_t frame_count;
52+ uint16_t pwm[16 ];
53+ };
54+
55+ struct servo_packet_32 {
56+ uint16_t magic; // 29569 expected magic value
57+ uint16_t frame_rate;
58+ uint32_t frame_count;
59+ uint16_t pwm[32 ];
60+ };
61+
62+ struct Control
63+ {
64+ uint16_t channel{0 };
65+ std::string type{" COMMAND" };
66+ bool use_force{true };
67+ std::string joint_name;
68+ std::string cmd_topic;
69+ double mutliplier{1.0 };
70+ double offset{0.0 };
71+ double servo_max{2000.0 };
72+ double servo_min{1000.0 };
73+ };
74+
75+ struct ArduPilotPlugin
76+ {
77+ std::string address{" 127.0.0.1" };
78+ uint16_t port{9002 };
79+ uint16_t connection_timeout_max_count{5 };
80+ bool lock_step{true };
81+ bool have_32_channels{false };
82+ gz::math::Pose3d pose_flu_to_frd = gz::math::Pose3d(0 , 0 , 0 , 0 , 0 , 0 );
83+ gz::math::Pose3d pose_enu_to_ned = gz::math::Pose3d(0 , 0 , 0 , 0 , 0 , 0 );
84+ std::string imu_name;
85+ };
86+
87+
88+ class ArduPilotGazeboBridge
89+ {
90+ public:
91+ ArduPilotGazeboBridge () {}
92+
93+
94+ private:
95+ void _clock_cb (const gz::msgs::Clock &_msg)
96+ {
97+ std::lock_guard<std::mutex> lock (this ->clock_mutex );
98+ this ->clock_msg = _msg;
99+ }
100+
101+ void _imu_cb (const gz::msgs::IMU &_msg)
102+ {
103+ std::lock_guard<std::mutex> lock (this ->imu_mutex );
104+ this ->imu_msg = _msg;
105+ }
106+
107+ void _odometry_cb (const gz::msgs::Odometry &_msg)
108+ {
109+ std::lock_guard<std::mutex> lock (this ->odometry_mutex );
110+ this ->odometry_msg = _msg;
111+ }
112+
113+ void _pose_info_cb (const gz::msgs::Pose_V &_msg)
114+ {
115+ std::lock_guard<std::mutex> lock (this ->pose_info_mutex );
116+ this ->pose_info_msg = _msg;
117+ }
118+
119+ // Configuration
120+ std::string world_name;
121+ std::string model_name;
122+
123+ // Socket settings
124+ std::string address;
125+ uint16_t port;
126+
127+ // Service call timeout
128+ uint32_t timeout;
129+
130+ // Connection
131+ SocketUDP sock = SocketUDP(true , true );
132+ bool connected = false ;
133+ uint32_t last_sitl_frame;
134+
135+ // Packet
136+ servo_packet_16 servo_packet;
137+
138+ // Stats
139+ uint32_t frame_count{0 };
140+ uint32_t print_frame_count{0 };
141+ double pre_update_prev_time;
142+ double post_update_prev_time;
143+
144+ // Payload
145+ std::string json_data;
146+
147+ // Transport
148+ gz::transport::Node node;
149+ ArduPilotPlugin plugin;
150+ std::vector<Control> controls;
151+ std::vector<gz::transport::Node::Publisher> command_pubs;
152+
153+ gz::msgs::Clock clock_msg;
154+ std::string clock_topic;
155+ std::mutex clock_mutex;
156+ std::chrono::steady_clock::duration clock_prev_recv_time{0 };
157+ std::string clock_sub;
158+
159+ gz::msgs::IMU imu_msg;
160+ std::string imu_topic;
161+ std::mutex imu_mutex;
162+ std::chrono::steady_clock::duration imu_prev_recv_time{0 };
163+
164+ gz::msgs::Odometry odometry_msg;
165+ std::string odometry_topic;
166+ std::mutex odometry_mutex;
167+ std::chrono::steady_clock::duration odometry_prev_recv_time{0 };
168+
169+ gz::msgs::Pose_V pose_info_msg;
170+ std::string pose_info_topic;
171+ std::mutex pose_info_mutex;
172+ std::chrono::steady_clock::duration pose_info_prev_recv_time{0 };
173+ };
174+
175+
176+ int main (int argc, char ** argv)
177+ {
178+ std::cout << " ArduPilot Gazebo Bridge" << std::endl;
179+
180+ // ! @todo replace hardcoded configuration
181+ std::string model_name = " r1_rover" ;
182+ std::string world_name = " runway" ;
183+ std::string address = " 127.0.0.1" ;
184+ uint16_t port = 9002 ;
185+ uint32_t timeout = 500 ;
186+
187+
188+ gz::transport::Node node;
189+
190+
191+ return 0 ;
192+ }
0 commit comments