Skip to content

Commit e1d61d6

Browse files
committed
Swarm: add standalone ArduPilot Gazebo bridge (C++)
Signed-off-by: Rhys Mainwaring <rhys.mainwaring@me.com>
1 parent b66e489 commit e1d61d6

2 files changed

Lines changed: 205 additions & 0 deletions

File tree

CMakeLists.txt

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,18 @@ find_package(OpenCV REQUIRED)
8787

8888
pkg_check_modules(GST REQUIRED gstreamer-1.0 gstreamer-app-1.0)
8989

90+
# --------------------------------------------------------------------------- #
91+
# Build executable.
92+
93+
add_executable(ArduPilotGazeboBridge
94+
src/ArduPilotGazeboBridge.cc
95+
)
96+
target_include_directories(ArduPilotGazeboBridge PRIVATE
97+
include
98+
)
99+
target_link_libraries(ArduPilotGazeboBridge PRIVATE
100+
gz-sim${GZ_SIM_VER}::gz-sim${GZ_SIM_VER}
101+
)
90102

91103
# --------------------------------------------------------------------------- #
92104
# Build plugin.
@@ -148,6 +160,7 @@ target_link_libraries(GstCameraPlugin PRIVATE
148160

149161
install(
150162
TARGETS
163+
ArduPilotGazeboBridge
151164
ArduPilotPlugin
152165
ParachutePlugin
153166
CameraZoomPlugin

src/ArduPilotGazeboBridge.cc

Lines changed: 192 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,192 @@
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

Comments
 (0)