SMACC2
Loading...
Searching...
No Matches
cb_px4_path_follower_base.hpp
Go to the documentation of this file.
1// Copyright 2026 RobosoftAI Inc.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15/*****************************************************************************************************************
16 *
17 * Authors: Brett Aldrich
18 *
19 ******************************************************************************************************************/
20
21#pragma once
22
25
26#include <atomic>
27#include <chrono>
28#include <limits>
29#include <vector>
30
31namespace cl_px4_mr
32{
33
34enum class YawMode
35{
36 TANGENT, // along the current path segment
37 FIXED, // PathFollowerParams::fixedYaw
38 PER_VERTEX, // NedPoint::yaw of the segment start (NaN -> tangent)
39 HOLD_ENTRY // heading at entry
40};
41
43{
44 float groundSpeed = 3.0f; // m/s, carrot advance rate along the polyline
45 // Max 3D distance the carrot may lead the vehicle. PX4 offboard position
46 // mode flies at vel = MPC_XY_P (0.95) * (setpoint - position), saturated at
47 // MPC_XY_VEL_MAX, so the steady-state lag is groundSpeed / 0.95 and the leash
48 // must exceed that or it throttles the effective speed to ~0.95 * leash.
49 float leash = 6.0f;
50 float arrivalXyTol = 1.0f; // final-vertex acceptance, metres
51 float arrivalZTol = 0.5f;
53 float fixedYaw = std::numeric_limits<float>::quiet_NaN();
54 bool prependCurrentPosition = true; // insert the entry position as vertex 0
55 float minSegmentLength = 0.05f; // drop degenerate segments
56 // If the state machine armed no timeout: timeout = max(30 s, factor * length / speed).
57 // 0 disables the auto-timeout.
58 float autoTimeoutFactor = 2.5f;
59};
60
61// Streaming polyline follower. A derived behavior supplies buildPath() (a pure
62// function of its params and the entry point); this base streams a moving
63// position setpoint ("carrot") along that polyline at a commanded ground
64// speed, throttled by a leash so the carrot never runs away from a lagging
65// vehicle, and posts success once the carrot has reached the end AND the
66// vehicle is within the arrival tolerances of the last vertex.
67//
68// It never uses CpGoalChecker (one global goal per client; closed paths would
69// self-trigger it at entry). Completion is an update() predicate.
70//
71// Threading: components come from the inherited allocation (state machine
72// thread). onEntry() (async thread) builds the path, arms the auto-timeout and
73// commands vertex 0, then sets active_. update() (SignalDetector thread,
74// ~20 Hz) only touches the path after observing active_. onExit() re-issues
75// the last carrot so the offboard keep-alive holds there.
77{
78public:
79 explicit CbPx4PathFollowerBase(PathFollowerParams params = {});
81
82 void setFollowerParams(const PathFollowerParams & params) { followerParams_ = params; }
84
85 void onEntry() override;
86 void onExit() override;
87 void update() override;
88
89protected:
90 // Called once from onEntry (async thread). Must depend only on params and
91 // `current` (x, y, z, yaw = heading at entry). May adjust followerParams_
92 // (e.g. yaw mode). Empty -> failure.
93 virtual std::vector<NedPoint> buildPath(const NedPoint & current) = 0;
94
95 // logging hooks
96 virtual const char * behaviorName() const { return "CbPx4PathFollowerBase"; }
97 virtual void onPathStarted(const std::vector<NedPoint> & /*path*/) {}
98 virtual void onPathCompleted() {}
99
100 float totalLength() const { return totalLen_; }
101 float progressFraction() const { return totalLen_ > 0.0f ? sCarrot_ / totalLen_ : 1.0f; }
102
104
105private:
106 NedPoint commandFor(float s);
107 float tangentYawAt(size_t segmentIndex) const;
108
109 std::vector<NedPoint> path_;
110 std::vector<float> cumLen_;
111 float totalLen_ = 0.0f;
112 float sCarrot_ = 0.0f;
113 float entryHeading_ = 0.0f;
116 std::atomic<bool> active_{false};
117 std::chrono::steady_clock::time_point lastUpdateTime_;
118};
119
120} // namespace cl_px4_mr
std::chrono::steady_clock::time_point lastUpdateTime_
CbPx4PathFollowerBase(PathFollowerParams params={})
virtual std::vector< NedPoint > buildPath(const NedPoint &current)=0
virtual void onPathStarted(const std::vector< NedPoint > &)
float tangentYawAt(size_t segmentIndex) const
virtual const char * behaviorName() const
void setFollowerParams(const PathFollowerParams &params)
const PathFollowerParams & followerParams() const