@@ -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