diff --git a/msg/vehicle_local_position_setpoint.msg b/msg/vehicle_local_position_setpoint.msg index 3932edb72a8959ab2993031f6cc2b59617652f5f..dc60f203841adf3a23cb0224ae620c6486a1ce91 100644 --- a/msg/vehicle_local_position_setpoint.msg +++ b/msg/vehicle_local_position_setpoint.msg @@ -14,4 +14,9 @@ float32 vz # in meters/sec float32 acc_x # in meters/(sec*sec) float32 acc_y # in meters/(sec*sec) float32 acc_z # in meters/(sec*sec) +float32 jerk_x # in meters/(sec*sec*sec) +float32 jerk_y # in meters/(sec*sec*sec) +float32 jerk_z # in meters/(sec*sec*sec) float32[3] thrust # normalized thrust vector in NED + +# TOPICS vehicle_local_position_setpoint trajectory_setpoint diff --git a/src/lib/FlightTasks/tasks/AutoLineSmoothVel/FlightTaskAutoLineSmoothVel.cpp b/src/lib/FlightTasks/tasks/AutoLineSmoothVel/FlightTaskAutoLineSmoothVel.cpp index 3bb4ab4719b4c2193fed636a46ebe42b70776492..7099aff6268236bf65a838691b24a4b361e54660 100644 --- a/src/lib/FlightTasks/tasks/AutoLineSmoothVel/FlightTaskAutoLineSmoothVel.cpp +++ b/src/lib/FlightTasks/tasks/AutoLineSmoothVel/FlightTaskAutoLineSmoothVel.cpp @@ -49,6 +49,8 @@ bool FlightTaskAutoLineSmoothVel::activate() _trajectory[i].reset(0.f, _velocity(i), _position(i)); } + _updateTrajConstraints(); + return ret; } @@ -121,15 +123,15 @@ void FlightTaskAutoLineSmoothVel::_prepareSetpoints() float speed_sp_track = Vector2f(pos_traj_to_dest).length() * MPC_XY_TRAJ_P.get(); speed_sp_track = math::constrain(speed_sp_track, 0.0f, MPC_XY_CRUISE.get()); - Vector2f velocity_sp_xy = u_pos_traj_to_dest_xy * speed_sp_track; + Vector2f vel_sp_xy = u_pos_traj_to_dest_xy * speed_sp_track; for (int i = 0; i < 2; i++) { // If available, constrain the velocity using _velocity_setpoint(.) if (PX4_ISFINITE(_velocity_setpoint(i))) { - _velocity_setpoint(i) = constrain_one_side(velocity_sp_xy(i), _velocity_setpoint(i)); + _velocity_setpoint(i) = constrain_one_side(vel_sp_xy(i), _velocity_setpoint(i)); } else { - _velocity_setpoint(i) = velocity_sp_xy(i); + _velocity_setpoint(i) = vel_sp_xy(i); } _velocity_setpoint(i) += (closest_pt(i) - _trajectory[i].getCurrentPosition()) * @@ -145,15 +147,15 @@ void FlightTaskAutoLineSmoothVel::_prepareSetpoints() } if (PX4_ISFINITE(_position_setpoint(2))) { - const float velocity_sp_z = (_position_setpoint(2) - _trajectory[2].getCurrentPosition()) * + const float vel_sp_z = (_position_setpoint(2) - _trajectory[2].getCurrentPosition()) * MPC_Z_TRAJ_P.get(); // Generate a velocity target for the trajectory using a simple P loop // If available, constrain the velocity using _velocity_setpoint(.) if (PX4_ISFINITE(_velocity_setpoint(2))) { - _velocity_setpoint(2) = constrain_one_side(velocity_sp_z, _velocity_setpoint(2)); + _velocity_setpoint(2) = constrain_one_side(vel_sp_z, _velocity_setpoint(2)); } else { - _velocity_setpoint(2) = velocity_sp_z; + _velocity_setpoint(2) = vel_sp_z; } } else if (!PX4_ISFINITE(_velocity_setpoint(2))) { @@ -162,7 +164,7 @@ void FlightTaskAutoLineSmoothVel::_prepareSetpoints() } } -void FlightTaskAutoLineSmoothVel::_generateTrajectory() +void FlightTaskAutoLineSmoothVel::_updateTrajConstraints() { // Update the constraints of the trajectories _trajectory[0].setMaxAccel(MPC_ACC_HOR_MAX.get()); // TODO : Should be computed using heading @@ -181,13 +183,10 @@ void FlightTaskAutoLineSmoothVel::_generateTrajectory() _trajectory[2].setMaxAccel(MPC_ACC_DOWN_MAX.get()); _trajectory[2].setMaxVel(MPC_Z_VEL_MAX_DN.get()); } +} - for (int i = 0; i < 3; ++i) { - _trajectory[i].updateDurations(_deltatime, _velocity_setpoint(i)); - } - - VelocitySmoothing::timeSynchronization(_trajectory, 2); // Synchronize x and y only - +void FlightTaskAutoLineSmoothVel::_generateTrajectory() +{ /* Slow down the trajectory by decreasing the integration time based on the position error. * This is only performed when the drone is behind the trajectory */ @@ -204,9 +203,26 @@ void FlightTaskAutoLineSmoothVel::_generateTrajectory() time_stretch = 1.f; } - Vector3f accel_sp_smooth; // Dummy variable + Vector3f jerk_sp_smooth; + Vector3f accel_sp_smooth; + Vector3f vel_sp_smooth; + Vector3f pos_sp_smooth; for (int i = 0; i < 3; ++i) { - _trajectory[i].integrate(_deltatime * time_stretch, accel_sp_smooth(i), _velocity_setpoint(i), _position_setpoint(i)); + _trajectory[i].integrate(_deltatime, time_stretch, accel_sp_smooth(i), vel_sp_smooth(i), pos_sp_smooth(i)); + jerk_sp_smooth(i) = _trajectory[i].getCurrentJerk(); } + + _updateTrajConstraints(); + + for (int i = 0; i < 3; ++i) { + _trajectory[i].updateDurations(_deltatime, _velocity_setpoint(i)); + } + + VelocitySmoothing::timeSynchronization(_trajectory, 2); // Synchronize x and y only + + _jerk_setpoint = jerk_sp_smooth; + _acceleration_setpoint = accel_sp_smooth; + _velocity_setpoint = vel_sp_smooth; + _position_setpoint = pos_sp_smooth; } diff --git a/src/lib/FlightTasks/tasks/AutoLineSmoothVel/FlightTaskAutoLineSmoothVel.hpp b/src/lib/FlightTasks/tasks/AutoLineSmoothVel/FlightTaskAutoLineSmoothVel.hpp index cea5b5560cc6c6902d2aa251e9a68ab48c80c444..aaa4e1f05d37b809d640770ac7926ad1f328c732 100644 --- a/src/lib/FlightTasks/tasks/AutoLineSmoothVel/FlightTaskAutoLineSmoothVel.hpp +++ b/src/lib/FlightTasks/tasks/AutoLineSmoothVel/FlightTaskAutoLineSmoothVel.hpp @@ -70,6 +70,7 @@ protected: inline float constrain_one_side(float val, float constrain); void _generateHeadingAlongTrack(); /**< Generates heading along track. */ + void _updateTrajConstraints(); void _prepareSetpoints(); /**< Generate velocity target points for the trajectory generator. */ void _generateTrajectory(); VelocitySmoothing _trajectory[3]; ///< Trajectories in x, y and z directions diff --git a/src/lib/FlightTasks/tasks/FlightTask/FlightTask.cpp b/src/lib/FlightTasks/tasks/FlightTask/FlightTask.cpp index b314ae0b9507272f0375e0d1beed088a78cc3b53..1693c4ab003b3cffc61c20435ea0120d8382d501 100644 --- a/src/lib/FlightTasks/tasks/FlightTask/FlightTask.cpp +++ b/src/lib/FlightTasks/tasks/FlightTask/FlightTask.cpp @@ -4,7 +4,7 @@ constexpr uint64_t FlightTask::_timeout; // First index of empty_setpoint corresponds to time-stamp and requires a finite number. -const vehicle_local_position_setpoint_s FlightTask::empty_setpoint = {0, NAN, NAN, NAN, NAN, NAN, NAN, NAN, NAN, NAN, NAN, NAN, {NAN, NAN, NAN}}; +const vehicle_local_position_setpoint_s FlightTask::empty_setpoint = {0, NAN, NAN, NAN, NAN, NAN, NAN, NAN, NAN, NAN, NAN, NAN, NAN, NAN, NAN, {NAN, NAN, NAN}}; const vehicle_constraints_s FlightTask::empty_constraints = {0, NAN, NAN, NAN, NAN, NAN, NAN, NAN, vehicle_constraints_s::GEAR_KEEP, {}}; const vehicle_trajectory_waypoint_s FlightTask::empty_trajectory_waypoint = {0, 0, {0, 0, 0, 0, 0, 0, 0}, @@ -71,6 +71,10 @@ const vehicle_local_position_setpoint_s FlightTask::getPositionSetpoint() vehicle_local_position_setpoint.acc_y = _acceleration_setpoint(1); vehicle_local_position_setpoint.acc_z = _acceleration_setpoint(2); + vehicle_local_position_setpoint.jerk_x = _jerk_setpoint(0); + vehicle_local_position_setpoint.jerk_y = _jerk_setpoint(1); + vehicle_local_position_setpoint.jerk_z = _jerk_setpoint(2); + _thrust_setpoint.copyTo(vehicle_local_position_setpoint.thrust); vehicle_local_position_setpoint.yaw = _yaw_setpoint; vehicle_local_position_setpoint.yawspeed = _yawspeed_setpoint; @@ -83,6 +87,7 @@ void FlightTask::_resetSetpoints() _position_setpoint.setAll(NAN); _velocity_setpoint.setAll(NAN); _acceleration_setpoint.setAll(NAN); + _jerk_setpoint.setAll(NAN); _thrust_setpoint.setAll(NAN); _yaw_setpoint = _yawspeed_setpoint = NAN; _desired_waypoint = FlightTask::empty_trajectory_waypoint; diff --git a/src/lib/FlightTasks/tasks/FlightTask/FlightTask.hpp b/src/lib/FlightTasks/tasks/FlightTask/FlightTask.hpp index aa3e68951b6ccda9128beb2a84901e90d46ea038..759a0b70d3b393f628a9d4346f5f65dc0c10caa5 100644 --- a/src/lib/FlightTasks/tasks/FlightTask/FlightTask.hpp +++ b/src/lib/FlightTasks/tasks/FlightTask/FlightTask.hpp @@ -196,11 +196,12 @@ protected: * If more than one type of setpoint is set, then order of control is a as follow: position, velocity, * acceleration, thrust. The exception is _position_setpoint together with _velocity_setpoint, where the * _velocity_setpoint is used as feedforward. - * _acceleration_setpoint is currently not supported. + * _acceleration_setpoint and _jerk_setpoint are currently not supported. */ matrix::Vector3f _position_setpoint; matrix::Vector3f _velocity_setpoint; matrix::Vector3f _acceleration_setpoint; + matrix::Vector3f _jerk_setpoint; matrix::Vector3f _thrust_setpoint; float _yaw_setpoint; float _yawspeed_setpoint; diff --git a/src/lib/FlightTasks/tasks/Utility/VelocitySmoothing.cpp b/src/lib/FlightTasks/tasks/Utility/VelocitySmoothing.cpp index b3e2e329a37226331bd56fcf9b52ecf73432da7e..d65ec361532385aa9eb2c19f99e17c682424a9ab 100644 --- a/src/lib/FlightTasks/tasks/Utility/VelocitySmoothing.cpp +++ b/src/lib/FlightTasks/tasks/Utility/VelocitySmoothing.cpp @@ -52,6 +52,31 @@ void VelocitySmoothing::reset(float accel, float vel, float pos) _pos = pos; } +float VelocitySmoothing::saturateT1ForAccel(float accel_prev, float max_jerk, float T1) +{ + /* Check maximum acceleration, saturate and recompute T1 if needed */ + float accel_T1 = accel_prev + max_jerk * T1; + float T1_new = T1; + + if (accel_T1 > _max_accel) { + T1_new = (_max_accel - accel_prev) / max_jerk; + + } else if (accel_T1 < -_max_accel) { + T1_new = (-_max_accel - accel_prev) / max_jerk; + } + + return T1_new; +} + +float VelocitySmoothing::recomputeMaxJerk(float accel_prev, float max_jerk, float T1) +{ + /* If T1 is smaller than dt, it means that the jerk is too large to reach the + * desired acceleration with a bang-bang signal => recompute the maximum jerk + */ + float accel_T1 = accel_prev + max_jerk * T1; + return (accel_T1 - accel_prev) / T1; +} + float VelocitySmoothing::computeT1(float accel_prev, float vel_prev, float vel_setpoint, float max_jerk) { float b = 2.f * accel_prev / max_jerk; @@ -59,6 +84,7 @@ float VelocitySmoothing::computeT1(float accel_prev, float vel_prev, float vel_s float delta = b * b - 4.f * c; if (delta < 0.f) { + // Solution is not real return 0.f; } @@ -68,20 +94,12 @@ float VelocitySmoothing::computeT1(float accel_prev, float vel_prev, float vel_s float T1 = math::max(math::max(T1_plus, T1_minus), 0.f); -// if (T1 < FLT_EPSILON) { -// // debug -// printf("No feasible solution found, set T1 = 0\n"); -// printf("T1_plus = %.3f T1_minus = %.3f\n", (double) T1_plus, (double) T1_minus); -// } - - /* Check maximum acceleration, saturate and recompute T1 if needed */ - float a1 = accel_prev + max_jerk * T1; - - if (a1 > _max_accel) { - T1 = (_max_accel - accel_prev) / max_jerk; + T1 = saturateT1ForAccel(accel_prev, max_jerk, T1); - } else if (a1 < -_max_accel) { - T1 = (-_max_accel - accel_prev) / max_jerk; + if ((T1 > FLT_EPSILON) && + (T1 < _dt)) { + _max_jerk_T1 = recomputeMaxJerk(accel_prev, max_jerk, T1); + T1 = _dt; } return math::max(T1, 0.f); @@ -114,6 +132,14 @@ float VelocitySmoothing::computeT1(float T123, float accel_prev, float vel_prev, T1 = T1_plus; } + T1 = saturateT1ForAccel(accel_prev, max_jerk, T1); + + if ((T1 > FLT_EPSILON) && + (T1 < _dt)) { + _max_jerk_T1 = recomputeMaxJerk(accel_prev, max_jerk, T1); + T1 = _dt; + } + return T1; } @@ -144,6 +170,7 @@ void VelocitySmoothing::integrateT(float dt, float jerk, float accel_prev, float { accel_out = jerk * dt + accel_prev; + // Paranoid check, should never be outside the saturations if (accel_out > _max_accel) { accel_out = _max_accel; @@ -153,6 +180,7 @@ void VelocitySmoothing::integrateT(float dt, float jerk, float accel_prev, float vel_out = dt * 0.5f * (accel_out + accel_prev) + vel_prev; + // Paranoid check, should never be outside the saturations if (vel_out > _max_vel) { vel_out = _max_vel; @@ -217,30 +245,41 @@ void VelocitySmoothing::updateDurations(float T123) void VelocitySmoothing::integrate(float &accel_setpoint_smooth, float &vel_setpoint_smooth, float &pos_setpoint_smooth) { - integrate(_dt, accel_setpoint_smooth, vel_setpoint_smooth, pos_setpoint_smooth); + integrate(_dt, 1.f, accel_setpoint_smooth, vel_setpoint_smooth, pos_setpoint_smooth); } -void VelocitySmoothing::integrate(float dt, float &accel_setpoint_smooth, float &vel_setpoint_smooth, +void VelocitySmoothing::integrate(float dt, float integration_scale_factor, float &accel_setpoint_smooth, + float &vel_setpoint_smooth, float &pos_setpoint_smooth) { - /* Integrate the trajectory */ - float accel_new, vel_new, pos_new; - integrateT(dt, _jerk, _accel, _vel, _pos, accel_new, vel_new, pos_new); - /* Apply correct jerk (min, max or zero) */ - if (_T1 > 0.f) { + if (_T1 > FLT_EPSILON) { _jerk = _max_jerk_T1; - } else if (_T2 > 0.f) { + if (_T1 < dt) { + // _T1 was supposed to be _dt, however, now, dt is bogger than _dt. We have to reduce the jerk to avoid an acceleration overshoot. + _jerk *= _dt / dt; // Keep the same area _dt * _jerk = dt * jerk_new + } + + } else if (_T2 > FLT_EPSILON) { _jerk = 0.f; - } else if (_T3 > 0.f) { + } else if (_T3 > FLT_EPSILON) { _jerk = -_max_jerk_T1; + if (_T3 < dt) { + // Same as for _T1 < dt above + _jerk *= _dt / dt; + } + } else { _jerk = 0.f; } + /* Integrate the trajectory */ + float accel_new, vel_new, pos_new; + integrateT(dt * integration_scale_factor, _jerk, _accel, _vel, _pos, accel_new, vel_new, pos_new); + _accel = accel_new; _vel = vel_new; _pos = pos_new; diff --git a/src/lib/FlightTasks/tasks/Utility/VelocitySmoothing.hpp b/src/lib/FlightTasks/tasks/Utility/VelocitySmoothing.hpp index ec035d4924896fcd5876bfba9fd70a4f66ef1a52..aada8e285241f3d848372406fb45029d11a2767f 100644 --- a/src/lib/FlightTasks/tasks/Utility/VelocitySmoothing.hpp +++ b/src/lib/FlightTasks/tasks/Utility/VelocitySmoothing.hpp @@ -84,7 +84,8 @@ public: * @param pos_setpoint_smooth returned smoothed position setpoint */ void integrate(float &accel_setpoint_smooth, float &vel_setpoint_smooth, float &pos_setpoint_smooth); - void integrate(float dt, float &accel_setpoint_smooth, float &vel_setpoint_smooth, float &pos_setpoint_smooth); + void integrate(float dt, float integration_scale_factor, float &accel_setpoint_smooth, float &vel_setpoint_smooth, + float &pos_setpoint_smooth); /* Get / Set constraints (constraints can be updated at any time) */ float getMaxJerk() const { return _max_jerk; } @@ -96,6 +97,9 @@ public: float getMaxVel() const { return _max_vel; } void setMaxVel(float max_vel) { _max_vel = max_vel; } + float getCurrentJerk() const { return _jerk; } + void setCurrentAcceleration(const float accel) { _accel = accel; } + float getCurrentAcceleration() const { return _accel; } void setCurrentVelocity(const float vel) { _vel = vel; } float getCurrentVelocity() const { return _vel; } void setCurrentPosition(const float pos) { _pos = pos; } @@ -129,6 +133,8 @@ private: * Compute increasing acceleration time using total time constraint */ inline float computeT1(float T123, float accel_prev, float vel_prev, float vel_setpoint, float max_jerk); + inline float saturateT1ForAccel(float accel_prev, float max_jerk, float T1); + inline float recomputeMaxJerk(float accel_prev, float max_jerk, float T1); /** * Compute constant acceleration time */ @@ -150,7 +156,7 @@ private: /* Inputs */ float _vel_sp; - float _dt = 0.f; + float _dt = 1.f; /* Constraints */ float _max_jerk = 22.f; @@ -158,10 +164,10 @@ private: float _max_vel = 6.f; /* State (previous setpoints) */ - float _jerk; - float _accel; - float _vel; - float _pos; + float _jerk = 0.f; + float _accel = 0.f; + float _vel = 0.f; + float _pos = 0.f; float _max_jerk_T1 = 0.f; ///< jerk during phase T1 (with correct sign) diff --git a/src/modules/logger/logger.cpp b/src/modules/logger/logger.cpp index f3240c6bf073109fec18398e2d5ad51aaf904cd8..a5f4c93e5199f39ab408f9f9e1219ec8d1c4464a 100644 --- a/src/modules/logger/logger.cpp +++ b/src/modules/logger/logger.cpp @@ -641,6 +641,7 @@ void Logger::add_default_topics() add_topic("sensor_preflight", 200); add_topic("system_power", 500); add_topic("tecs_status", 200); + add_topic("trajectory_setpoint"); add_topic("telemetry_status"); add_topic("vehicle_air_data", 200); add_topic("vehicle_attitude", 30); diff --git a/src/modules/mc_pos_control/mc_pos_control_main.cpp b/src/modules/mc_pos_control/mc_pos_control_main.cpp index 65c30f1338958ce8569be38a7b9f1c36d541003e..3118f2b9dfbdac8a5700ecdf9b305b896baf9764 100644 --- a/src/modules/mc_pos_control/mc_pos_control_main.cpp +++ b/src/modules/mc_pos_control/mc_pos_control_main.cpp @@ -100,6 +100,7 @@ private: bool _in_smooth_takeoff = false; /**<true if takeoff ramp is applied */ orb_advert_t _att_sp_pub{nullptr}; /**< attitude setpoint publication */ + orb_advert_t _traj_sp_pub{nullptr}; /**< trajectory setpoints publication */ orb_advert_t _local_pos_sp_pub{nullptr}; /**< vehicle local position setpoint publication */ orb_advert_t _traj_wp_avoidance_desired_pub{nullptr}; /**< trajectory waypoint desired publication */ orb_advert_t _pub_vehicle_command{nullptr}; /**< vehicle command publication */ @@ -218,6 +219,12 @@ private: */ void publish_local_pos_sp(const vehicle_local_position_setpoint_s &local_pos_sp); + /** + * Publish local position setpoint. + * This is only required for logging. + */ + void publish_trajectory_sp(const vehicle_local_position_setpoint_s &traj); + /** * Checks if smooth takeoff is initiated. * @param position_setpoint_z the position setpoint in the z-Direction @@ -751,6 +758,8 @@ MulticopterPositionControl::run() limit_thrust_during_landing(thr_sp); } + publish_trajectory_sp(setpoint); + // Fill local position, velocity and thrust setpoint. vehicle_local_position_setpoint_s local_pos_sp{}; local_pos_sp.timestamp = hrt_absolute_time(); @@ -1204,6 +1213,18 @@ MulticopterPositionControl::publish_attitude() } } +void +MulticopterPositionControl::publish_trajectory_sp(const vehicle_local_position_setpoint_s &traj) +{ + // publish trajectory + if (_traj_sp_pub != nullptr) { + orb_publish(ORB_ID(trajectory_setpoint), _traj_sp_pub, &traj); + + } else { + _traj_sp_pub = orb_advertise(ORB_ID(trajectory_setpoint), &traj); + } +} + void MulticopterPositionControl::publish_local_pos_sp(const vehicle_local_position_setpoint_s &local_pos_sp) {