38{
40 {
41 RCLCPP_ERROR(
getLogger(),
"CbWaitForHeadingStable: no CpVehicleLocalPosition");
43 return;
44 }
46 RCLCPP_INFO(
48 "CbWaitForHeadingStable: waiting for the heading to hold within %.2f deg/s over %.0f s%s "
49 "(timeout %.0f s)",
51 checkExpected ?
" and match the parked heading" :
"",
params_.
timeoutS);
52
53 using clock = std::chrono::steady_clock;
54 const auto start = clock::now();
55 std::deque<std::pair<double, float>> samples;
56 rclcpp::Rate rate(10.0);
57 double lastReport = -10.0;
58
60 {
61 const double t = std::chrono::duration<double>(clock::now() - start).count();
63 {
65 }
66 while (!samples.empty() && t - samples.front().first >
params_.
windowS)
67 {
68 samples.pop_front();
69 }
70
71 bool windowFull =
72 !samples.empty() && samples.back().first - samples.front().first >= 0.9 *
params_.
windowS;
73 float drift = 0.0f, offset = 0.0f;
74 bool stable = false, aligned = true;
75 if (windowFull)
76 {
77
78 float lo = 0.0f, hi = 0.0f;
79 for (const auto & s : samples)
80 {
81 const float d =
wrapPi(s.second - samples.front().second);
82 lo = std::min(lo, d);
83 hi = std::max(hi, d);
84 }
85 drift = hi - lo;
87 if (checkExpected)
88 {
91 }
92 }
93
94 if (windowFull && stable && aligned)
95 {
96 RCLCPP_INFO(
98 "CbWaitForHeadingStable: heading %.1f deg stable (%.2f deg over %.0f s%s) - posting "
99 "success",
100 samples.back().second * 180.0 / M_PI, drift * 180.0 / M_PI,
params_.
windowS,
101 checkExpected ? (", offset " + std::to_string(offset * 180.0 / M_PI) + " deg").c_str()
102 : "");
104 return;
105 }
106
107 if (t - lastReport >= 2.0)
108 {
109 lastReport = t;
110 if (!windowFull)
111 {
112 RCLCPP_INFO(
113 getLogger(),
"CbWaitForHeadingStable: collecting (%zu samples, position valid=%d)",
115 }
116 else
117 {
118 RCLCPP_WARN(
120 "CbWaitForHeadingStable: heading %.1f deg NOT ready: drift %.2f deg/s%s - the EKF "
121 "yaw is not trustworthy for takeoff",
122 samples.back().second * 180.0 / M_PI, drift /
params_.
windowS * 180.0 / M_PI,
123 checkExpected
124 ? (", offset from parked heading " + std::to_string(offset * 180.0 / M_PI) + " deg")
125 .c_str()
126 : "");
127 }
128 }
129
131 {
132 RCLCPP_ERROR(
134 "CbWaitForHeadingStable: timeout (%.0f s): heading %.1f deg, drift %.2f deg/s. "
135 "Refusing to arm; restart the estimator / SITL",
136 params_.
timeoutS, samples.empty() ? 0.0 : samples.back().second * 180.0 / M_PI,
139 return;
140 }
141 rate.sleep();
142 }
143 RCLCPP_WARN(
getLogger(),
"CbWaitForHeadingStable: shutdown requested");
145}
CpVehicleLocalPosition * localPosition_
virtual rclcpp::Logger getLogger() const
bool isShutdownRequested()
onEntry is executed in a new thread. However the current state cannot be left until the onEntry threa...
float wrapPi(float angle)