Skip to content

Commit e201f30

Browse files
committed
Swarm: update ArduPilot Gazebo bridge
- Populate default JSON message. - Wait 100ms for topics to advertise before publishing. - Enable lock-step Signed-off-by: Rhys Mainwaring <rhys.mainwaring@me.com>
1 parent 1c15547 commit e201f30

1 file changed

Lines changed: 176 additions & 45 deletions

File tree

src/ArduPilotGazeboBridge.cc

Lines changed: 176 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -154,28 +154,27 @@ class ArduPilotGazeboBridge
154154

155155
// Setup SITL connections
156156
this->_init_sockets();
157+
158+
// fill json data with default
159+
this->_create_default_json();
157160
}
158161

159162
void run()
160163
{
161164
using namespace std::chrono_literals;
162165

166+
// wait for topics to register
167+
std::this_thread::sleep_for(100ms);
168+
169+
// Enable lock step
170+
gz::msgs::Boolean enable_lock_step_msg;
171+
enable_lock_step_msg.set_data(true);
172+
this->enable_lock_step_pub.Publish(enable_lock_step_msg);
173+
std::cout << "Send Lock Step Enable" << std::endl;
174+
163175
uint64_t count = 0;
164176
while (true)
165177
{
166-
// Has the clock updated?
167-
{
168-
std::lock_guard<std::mutex> lock(this->clock_mutex);
169-
this->timestamp = this->clock_msg.sim().sec()
170-
+ 1.0e-9 * this->clock_msg.sim().nsec();
171-
}
172-
if (this->prev_timestamp >= this->timestamp)
173-
{
174-
std::this_thread::sleep_for(100us);
175-
continue;
176-
}
177-
this->prev_timestamp = this->timestamp;
178-
179178
// Pre-update
180179
if (this->update_state == UpdateState::PREUPDATE)
181180
{
@@ -184,7 +183,25 @@ class ArduPilotGazeboBridge
184183
if (result)
185184
{
186185
this->_send_commands();
187-
this->update_state = UpdateState::POSTUPDATE;
186+
// this->update_state = UpdateState::POSTUPDATE;
187+
188+
// Step
189+
// this->start_lock_step_pub.Publish(this->clock_msg.sim());
190+
auto sim_time_sec_nsec =
191+
gz::math::durationToSecNsec(this->last_update_sim_time);
192+
gz::msgs::Time msg;
193+
msg.set_sec(sim_time_sec_nsec.first);
194+
msg.set_nsec(sim_time_sec_nsec.second);
195+
this->start_lock_step_pub.Publish(msg);
196+
std::cout << "Send Lock Step Start: "
197+
<< "["
198+
<< msg.sec() << "s, "
199+
<< msg.nsec() << "ns"
200+
<< "]"
201+
<< std::endl;
202+
203+
this->update_state = UpdateState::WAIT;
204+
std::cout << "Complete PreUpdate [" << count << "]"<< std::endl;
188205
}
189206
}
190207

@@ -196,10 +213,12 @@ class ArduPilotGazeboBridge
196213
this->_send_state();
197214

198215
this->update_state = UpdateState::PREUPDATE;
216+
std::cout << "Complete PostUpdate [" << count << "]"<< std::endl;
217+
218+
count++;
199219
}
200220

201-
// std::cout << "Step: " << count << std::endl;
202-
count++;
221+
// std::this_thread::sleep_for(1us);
203222
}
204223
}
205224

@@ -370,6 +389,12 @@ class ArduPilotGazeboBridge
370389
this->node.Subscribe(this->pose_topic, &ArduPilotGazeboBridge::_pose_cb, this);
371390
std::cout << "Subscribing to Pose_V on: " << this->pose_topic << std::endl;
372391

392+
// gz.msgs.Time
393+
// /model/iris_with_ardupilot_1/lock_step/complete
394+
this->complete_lock_step_topic = std::string("/model/").append(this->model_name).append("/lock_step/complete");
395+
this->node.Subscribe(this->complete_lock_step_topic, &ArduPilotGazeboBridge::_complete_lock_step_cb, this);
396+
std::cout << "Subscribing to Time on: " << this->complete_lock_step_topic << std::endl;
397+
373398
// gz.msgs.IMU
374399
// /world/runway/model/r1_rover/link/imu_link/sensor/imu_sensor/imu
375400
auto imu_split = gz::common::split(this->plugin.imu_name, "::");
@@ -399,12 +424,23 @@ class ArduPilotGazeboBridge
399424
this->node.Subscribe(this->imu_topic, &ArduPilotGazeboBridge::_imu_cb, this);
400425
std::cout << "Subscribing to IMU on: " << this->imu_topic << std::endl;
401426

402-
// Commands
427+
// Lock-step publishers
428+
this->enable_lock_step_topic = std::string("/model/").append(this->model_name).append("/lock_step/enable");
429+
this->enable_lock_step_pub = this->node.Advertise<gz::msgs::Boolean>(this->enable_lock_step_topic);
430+
std::cout << "Advertising messages on "
431+
<< this->enable_lock_step_topic << std::endl;
432+
433+
this->start_lock_step_topic = std::string("/model/").append(this->model_name).append("/lock_step/start");
434+
this->start_lock_step_pub = this->node.Advertise<gz::msgs::Time>(this->start_lock_step_topic);
435+
std::cout << "Advertising messages on "
436+
<< this->start_lock_step_topic << std::endl;
437+
438+
// Command publishers
403439
for (const auto &control : this->controls)
404440
{
405441
this->command_pubs.emplace_back(this->node.Advertise<gz::msgs::Double>(control.cmd_topic));
406442
std::cout << "Advertising command for channel " << control.channel
407-
<< " on: " << control.cmd_topic << std::endl;
443+
<< " on: " << control.cmd_topic << std::endl;
408444
}
409445
}
410446

@@ -525,8 +561,8 @@ class ArduPilotGazeboBridge
525561
{
526562
this->ardupilot_online = false;
527563
std::cout << "[" << this->model_name << "] "
528-
<< "Broken ArduPilot connection,"
529-
<< " resetting motor control.\n";
564+
<< "Broken ArduPilot connection,"
565+
<< " resetting motor control.\n";
530566
//! @todo implement reset
531567
// this->ResetPIDs();
532568
}
@@ -606,8 +642,8 @@ class ArduPilotGazeboBridge
606642
&& this->ardupilot_online)
607643
{
608644
std::cout << "Missed "
609-
<< pkt_frame_count - this->fcu_frame_count
610-
<< " input frames" << std::endl;
645+
<< pkt_frame_count - this->fcu_frame_count
646+
<< " input frames" << std::endl;
611647
}
612648

613649
// update frame count
@@ -658,15 +694,76 @@ class ArduPilotGazeboBridge
658694
}
659695
}
660696

661-
void _create_state_json()
697+
void _create_default_json()
698+
{
699+
// Build JSON document
700+
rapidjson::StringBuffer string_buf;
701+
rapidjson::Writer<rapidjson::StringBuffer> writer(string_buf);
702+
703+
writer.StartObject();
704+
705+
writer.Key("timestamp");
706+
writer.Double(0.0);
707+
708+
writer.Key("imu");
709+
writer.StartObject();
710+
writer.Key("gyro");
711+
writer.StartArray();
712+
writer.Double(0.0);
713+
writer.Double(0.0);
714+
writer.Double(0.0);
715+
writer.EndArray();
716+
writer.Key("accel_body");
717+
writer.StartArray();
718+
writer.Double(0.0);
719+
writer.Double(0.0);
720+
writer.Double(0.0);
721+
writer.EndArray();
722+
writer.EndObject();
723+
724+
writer.Key("position");
725+
writer.StartArray();
726+
writer.Double(0.0);
727+
writer.Double(0.0);
728+
writer.Double(0.0);
729+
writer.EndArray();
730+
731+
// ArduPilot quaternion convention: q[0] = 1 for identity.
732+
writer.Key("quaternion");
733+
writer.StartArray();
734+
writer.Double(1.0);
735+
writer.Double(0.0);
736+
writer.Double(0.0);
737+
writer.Double(0.0);
738+
writer.EndArray();
739+
740+
writer.Key("velocity");
741+
writer.StartArray();
742+
writer.Double(0.0);
743+
writer.Double(0.0);
744+
writer.Double(0.0);
745+
writer.EndArray();
746+
747+
writer.EndObject();
748+
749+
// Get JSON string
750+
this->json_data = "\n" + std::string(string_buf.GetString()) + "\n";
751+
}
752+
753+
bool _create_state_json()
662754
{
755+
// Convert timestamp to double
756+
double timestamp =
757+
std::chrono::duration_cast<std::chrono::duration<double>>(
758+
this->last_update_sim_time).count();
759+
663760
gz::msgs::IMU imu_msg_;
664761
{
665762
std::lock_guard<std::mutex> lock(this->imu_mutex);
666763
// Wait until we've received a valid message.
667764
if (!this->imu_msg_valid)
668765
{
669-
return;
766+
return false;
670767
}
671768
imu_msg_ = this->imu_msg;
672769
}
@@ -714,7 +811,7 @@ class ArduPilotGazeboBridge
714811

715812
gz::math::Vector3d world_pos;
716813
gz::math::Quaterniond world_rot;
717-
double world_pos_timestamp{0.0};
814+
double world_pos_timestamp{};
718815
for (const auto &pose : pose_msg_.pose())
719816
{
720817
// Filter for the model
@@ -729,9 +826,13 @@ class ArduPilotGazeboBridge
729826
pose.orientation().x(),
730827
pose.orientation().y(),
731828
pose.orientation().z());
732-
world_pos_timestamp = pose.header().stamp().sec()
733-
+ 1.0e-9 * pose.header().stamp().nsec();
734-
}
829+
830+
auto world_pos_duration = gz::math::secNsecToDuration(
831+
pose.header().stamp().sec(), pose.header().stamp().nsec());
832+
world_pos_timestamp =
833+
std::chrono::duration_cast<std::chrono::duration<double>>(
834+
world_pos_duration).count();
835+
}
735836
}
736837
gz::math::Pose3d worldPose(world_pos, world_rot);
737838
gz::math::Vector3d worldLinearVel;
@@ -745,20 +846,29 @@ class ArduPilotGazeboBridge
745846
pose.position().x(),
746847
pose.position().y(),
747848
pose.position().z());
748-
double prev_world_pos_timestamp = pose.header().stamp().sec()
749-
+ 1.0e-9 * pose.header().stamp().nsec();
849+
850+
auto prev_world_pos_duration = gz::math::secNsecToDuration(
851+
pose.header().stamp().sec(), pose.header().stamp().nsec());
852+
double prev_world_pos_timestamp =
853+
std::chrono::duration_cast<std::chrono::duration<double>>(
854+
prev_world_pos_duration).count();
855+
750856
double dt = world_pos_timestamp - prev_world_pos_timestamp;
751857
double dx = world_pos.X() - prev_world_pos.X();
752858
double dy = world_pos.Y() - prev_world_pos.Y();
753859
double dz = world_pos.Z() - prev_world_pos.Z();
754860
worldLinearVel = gz::math::Vector3d(dx/dt, dy/dt, dz/dt);
755861

756862
std::cout << "worldLinearVel: dt: " << dt
757-
<< " dx: " << dx
758-
<< " dy: " << dy
759-
<< " dz: " << dz
760-
<< " v: " << worldLinearVel
761-
<< std::endl;
863+
<< " dx: " << dx
864+
<< " dy: " << dy
865+
<< " dz: " << dz
866+
<< " v: " << worldLinearVel
867+
<< std::endl;
868+
if (dt < 0.001)
869+
{
870+
return false;
871+
}
762872
}
763873
}
764874

@@ -786,7 +896,7 @@ class ArduPilotGazeboBridge
786896
writer.StartObject();
787897

788898
writer.Key("timestamp");
789-
writer.Double(this->timestamp);
899+
writer.Double(timestamp);
790900

791901
writer.Key("imu");
792902
writer.StartObject();
@@ -840,6 +950,7 @@ class ArduPilotGazeboBridge
840950
// << ", pitch: " << wldAToBdyA.Rot().Pitch()
841951
// << ", yaw: " << wldAToBdyA.Rot().Pitch()
842952
// << std::endl;
953+
return true;
843954
}
844955

845956
void _send_state()
@@ -892,10 +1003,26 @@ class ArduPilotGazeboBridge
8921003
// std::cout << this->pose_msg.DebugString() << std::endl;
8931004
}
8941005

1006+
void _complete_lock_step_cb(const gz::msgs::Time &_msg)
1007+
{
1008+
std::lock_guard<std::mutex> lock(this->complete_lock_step_mutex);
1009+
this->last_update_sim_time = gz::math::secNsecToDuration(
1010+
_msg.sec(), _msg.nsec());
1011+
this->update_state = UpdateState::POSTUPDATE;
1012+
// std::cout << _msg.DebugString() << std::endl;
1013+
std::cout << "Received Lock Step Complete"
1014+
<< "["
1015+
<< _msg.sec() << "s, "
1016+
<< _msg.nsec() << "ns"
1017+
<< "]"
1018+
<< std::endl;
1019+
}
1020+
8951021
enum class UpdateState
8961022
{
897-
PREUPDATE = 0,
898-
POSTUPDATE = 1
1023+
WAIT = 0,
1024+
PREUPDATE = 1,
1025+
POSTUPDATE = 2
8991026
};
9001027

9011028
// Configuration
@@ -933,11 +1060,8 @@ class ArduPilotGazeboBridge
9331060
// Stats
9341061
uint32_t frame_count{0};
9351062
uint32_t print_frame_count{0};
936-
double pre_update_prev_time;
937-
double post_update_prev_time;
9381063

939-
double timestamp{0.0};
940-
double prev_timestamp{0.0};
1064+
std::chrono::steady_clock::duration last_update_sim_time{};
9411065

9421066
// Payload
9431067
std::string json_data;
@@ -948,6 +1072,12 @@ class ArduPilotGazeboBridge
9481072
std::vector<Control> controls;
9491073
std::vector<gz::transport::Node::Publisher> command_pubs;
9501074

1075+
gz::transport::Node::Publisher enable_lock_step_pub;
1076+
std::string enable_lock_step_topic;
1077+
1078+
gz::transport::Node::Publisher start_lock_step_pub;
1079+
std::string start_lock_step_topic;
1080+
9511081
gz::msgs::Clock clock_msg;
9521082
std::string clock_topic;
9531083
std::mutex clock_mutex;
@@ -957,18 +1087,19 @@ class ArduPilotGazeboBridge
9571087
gz::msgs::IMU imu_msg;
9581088
std::string imu_topic;
9591089
std::mutex imu_mutex;
960-
// std::chrono::steady_clock::duration imu_prev_recv_time{0};
9611090

9621091
gz::msgs::Odometry odometry_msg;
9631092
std::string odometry_topic;
9641093
std::mutex odometry_mutex;
965-
// std::chrono::steady_clock::duration odometry_prev_recv_time{0};
9661094

9671095
gz::msgs::Pose_V pose_msg;
9681096
gz::msgs::Pose_V prev_pose_msg;
9691097
std::string pose_topic;
9701098
std::mutex pose_mutex;
971-
// std::chrono::steady_clock::duration pose_prev_recv_time{0};
1099+
1100+
gz::msgs::Time complete_lock_step_msg;
1101+
std::string complete_lock_step_topic;
1102+
std::mutex complete_lock_step_mutex;
9721103

9731104
// Track update state
9741105
UpdateState update_state{UpdateState::PREUPDATE};

0 commit comments

Comments
 (0)