Initial commit - test serial
This commit is contained in:
		
							
								
								
									
										65
									
								
								SerialTest/include/okapi/squiggles/constraints.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										65
									
								
								SerialTest/include/okapi/squiggles/constraints.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,65 @@ | ||||
| /** | ||||
|  * Copyright 2020 Jonathan Bayless | ||||
|  * | ||||
|  * Use of this source code is governed by an MIT-style license that can be found | ||||
|  * in the LICENSE file or at https://opensource.org/licenses/MIT. | ||||
|  */ | ||||
| #ifndef _SQUIGGLES_CONSTRAINTS_HPP_ | ||||
| #define _SQUIGGLES_CONSTRAINTS_HPP_ | ||||
|  | ||||
| #include <cmath> | ||||
| #include <string> | ||||
|  | ||||
| namespace squiggles { | ||||
| struct Constraints { | ||||
|   /** | ||||
|    * Defines the motion constraints for a path. | ||||
|    * | ||||
|    * @param imax_vel The maximum allowable velocity for the robot in meters per | ||||
|    *                 second. | ||||
|    * @param imax_accel The maximum allowable acceleration for the robot in | ||||
|    *                   meters per second per second. | ||||
|    * @param imax_jerk The maximum allowable jerk for the robot in meters per | ||||
|    *                  second per second per second (m/s^3). | ||||
|    * @param imax_curvature The maximum allowable change in heading in radians | ||||
|    *                       per second. This is not set to the numeric limits by | ||||
|    *                       default as that will allow for wild paths. | ||||
|    * @param imin_accel The minimum allowable acceleration for the robot in | ||||
|    *                   meters per second per second. | ||||
|    */ | ||||
|   Constraints(double imax_vel, | ||||
|               double imax_accel = std::numeric_limits<double>::max(), | ||||
|               double imax_jerk = std::numeric_limits<double>::max(), | ||||
|               double imax_curvature = 1000, | ||||
|               double imin_accel = std::nan("")) | ||||
|     : max_vel(imax_vel), | ||||
|       max_accel(imax_accel), | ||||
|       max_jerk(imax_jerk), | ||||
|       max_curvature(imax_curvature) { | ||||
|     if (imax_accel == std::numeric_limits<double>::max()) { | ||||
|       min_accel = std::numeric_limits<double>::lowest(); | ||||
|     } else { | ||||
|       min_accel = std::isnan(imin_accel) ? -imax_accel : imin_accel; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * Serializes the Constraints data for debugging. | ||||
|    * | ||||
|    * @return The Constraints data. | ||||
|    */ | ||||
|   std::string to_string() const { | ||||
|     return "Constraints: {max_vel: " + std::to_string(max_vel) + | ||||
|            ", max_accel: " + std::to_string(max_accel) + | ||||
|            ", max_jerk: " + std::to_string(max_jerk) + | ||||
|            ", min_accel: " + std::to_string(min_accel) + "}"; | ||||
|   } | ||||
|  | ||||
|   double max_vel; | ||||
|   double max_accel; | ||||
|   double max_jerk; | ||||
|   double min_accel; | ||||
|   double max_curvature; | ||||
| }; | ||||
| } // namespace squiggles | ||||
| #endif | ||||
| @@ -0,0 +1,62 @@ | ||||
| /** | ||||
|  * Copyright 2020 Jonathan Bayless | ||||
|  * | ||||
|  * Use of this source code is governed by an MIT-style license that can be found | ||||
|  * in the LICENSE file or at https://opensource.org/licenses/MIT. | ||||
|  */ | ||||
| #ifndef _GEOMETRY_CONTROL_VECTOR_HPP_ | ||||
| #define _GEOMETRY_CONTROL_VECTOR_HPP_ | ||||
|  | ||||
| #include <cmath> | ||||
| #include <string> | ||||
|  | ||||
| #include "pose.hpp" | ||||
|  | ||||
| namespace squiggles { | ||||
| class ControlVector { | ||||
|   public: | ||||
|   /** | ||||
|    * A vector used to specify a state along a hermite spline. | ||||
|    * | ||||
|    * @param ipose The 2D position and heading. | ||||
|    * @param ivel The velocity component of the vector. | ||||
|    * @param iaccel The acceleration component of the vector. | ||||
|    * @param ijerk The jerk component of the vector. | ||||
|    */ | ||||
|   ControlVector(Pose ipose, | ||||
|                 double ivel = std::nan(""), | ||||
|                 double iaccel = 0.0, | ||||
|                 double ijerk = 0.0) | ||||
|     : pose(ipose), vel(ivel), accel(iaccel), jerk(ijerk) {} | ||||
|  | ||||
|   ControlVector() = default; | ||||
|  | ||||
|   /** | ||||
|    * Serializes the Control Vector data for debugging. | ||||
|    * | ||||
|    * @return The Control Vector data. | ||||
|    */ | ||||
|   std::string to_string() const { | ||||
|     return "ControlVector: {" + pose.to_string() + | ||||
|            ", v: " + std::to_string(vel) + ", a: " + std::to_string(accel) + | ||||
|            ", j: " + std::to_string(jerk) + "}"; | ||||
|   } | ||||
|  | ||||
|   std::string to_csv() const { | ||||
|     return pose.to_csv() + "," + std::to_string(vel) + "," + | ||||
|            std::to_string(accel) + "," + std::to_string(jerk); | ||||
|   } | ||||
|  | ||||
|   bool operator==(const ControlVector& other) const { | ||||
|     return pose == other.pose && nearly_equal(vel, other.vel) && | ||||
|            nearly_equal(accel, other.accel) && nearly_equal(jerk, other.jerk); | ||||
|   } | ||||
|  | ||||
|   Pose pose; | ||||
|   double vel; | ||||
|   double accel; | ||||
|   double jerk; | ||||
| }; | ||||
| } // namespace squiggles | ||||
|  | ||||
| #endif | ||||
							
								
								
									
										67
									
								
								SerialTest/include/okapi/squiggles/geometry/pose.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										67
									
								
								SerialTest/include/okapi/squiggles/geometry/pose.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,67 @@ | ||||
| /** | ||||
|  * Copyright 2020 Jonathan Bayless | ||||
|  * | ||||
|  * Use of this source code is governed by an MIT-style license that can be found | ||||
|  * in the LICENSE file or at https://opensource.org/licenses/MIT. | ||||
|  */ | ||||
| #ifndef _GEOMETRY_POSE_HPP_ | ||||
| #define _GEOMETRY_POSE_HPP_ | ||||
|  | ||||
| #include <cmath> | ||||
| #include <string> | ||||
|  | ||||
| #include "math/utils.hpp" | ||||
|  | ||||
| namespace squiggles { | ||||
| class Pose { | ||||
|   public: | ||||
|   /** | ||||
|    * Specifies a point and heading in 2D space. | ||||
|    * | ||||
|    * @param ix The x position of the point in meters. | ||||
|    * @param iy The y position of the point in meters. | ||||
|    * @param iyaw The heading at the point in radians. | ||||
|    */ | ||||
|   Pose(double ix, double iy, double iyaw) : x(ix), y(iy), yaw(iyaw) {} | ||||
|  | ||||
|   Pose() = default; | ||||
|  | ||||
|   /** | ||||
|    * Calculates the Euclidean distance between this pose and another. | ||||
|    * | ||||
|    * @param other The point from which the distance will be calculated. | ||||
|    * | ||||
|    * @return The distance between this pose and Other. | ||||
|    */ | ||||
|   double dist(const Pose& other) const { | ||||
|     return std::sqrt((x - other.x) * (x - other.x) + | ||||
|                      (y - other.y) * (y - other.y)); | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * Serializes the Pose data for debugging. | ||||
|    * | ||||
|    * @return The Pose data. | ||||
|    */ | ||||
|   std::string to_string() const { | ||||
|     return "Pose: {x: " + std::to_string(x) + ", y: " + std::to_string(y) + | ||||
|            ", yaw: " + std::to_string(yaw) + "}"; | ||||
|   } | ||||
|  | ||||
|   std::string to_csv() const { | ||||
|     return std::to_string(x) + "," + std::to_string(y) + "," + | ||||
|            std::to_string(yaw); | ||||
|   } | ||||
|  | ||||
|   bool operator==(const Pose& other) const { | ||||
|     return nearly_equal(x, other.x) && nearly_equal(y, other.y) && | ||||
|            nearly_equal(yaw, other.yaw); | ||||
|   } | ||||
|  | ||||
|   double x; | ||||
|   double y; | ||||
|   double yaw; | ||||
| }; | ||||
| } // namespace squiggles | ||||
|  | ||||
| #endif | ||||
							
								
								
									
										100
									
								
								SerialTest/include/okapi/squiggles/geometry/profilepoint.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										100
									
								
								SerialTest/include/okapi/squiggles/geometry/profilepoint.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,100 @@ | ||||
| /** | ||||
|  * Copyright 2020 Jonathan Bayless | ||||
|  * | ||||
|  * Use of this source code is governed by an MIT-style license that can be found | ||||
|  * in the LICENSE file or at https://opensource.org/licenses/MIT. | ||||
|  */ | ||||
| #ifndef _GEOMETRY_PROFILE_POINT_HPP_ | ||||
| #define _GEOMETRY_PROFILE_POINT_HPP_ | ||||
|  | ||||
| #include <iostream> | ||||
| #include <string> | ||||
| #include <vector> | ||||
|  | ||||
| #include "controlvector.hpp" | ||||
| #include "math/utils.hpp" | ||||
|  | ||||
| namespace squiggles { | ||||
| struct ProfilePoint { | ||||
|   /** | ||||
|    * Defines a state along a motion profiled path. | ||||
|    * | ||||
|    * @param ivector The pose and associated dynamics at this state in the path. | ||||
|    * @param iwheel_velocities The component of the robot's velocity provided by | ||||
|    *                          each wheel in meters per second. | ||||
|    * @param icurvature The degree to which the curve deviates from a straight | ||||
|    *                   line at this point in 1 / meters. | ||||
|    * @param itime The timestamp for this state relative to the start of the | ||||
|    *              path in seconds. | ||||
|    */ | ||||
|   ProfilePoint(ControlVector ivector, | ||||
|                std::vector<double> iwheel_velocities, | ||||
|                double icurvature, | ||||
|                double itime) | ||||
|     : vector(ivector), | ||||
|       wheel_velocities(iwheel_velocities), | ||||
|       curvature(icurvature), | ||||
|       time(itime) {} | ||||
|  | ||||
|   ProfilePoint() = default; | ||||
|  | ||||
|   /** | ||||
|    * Serializes the Profile Point data for debugging. | ||||
|    * | ||||
|    * @return The Profile Point data. | ||||
|    */ | ||||
|   std::string to_string() const { | ||||
|     std::string wheels = "{"; | ||||
|     for (auto& w : wheel_velocities) { | ||||
|       wheels += std::to_string(w); | ||||
|       wheels += ", "; | ||||
|     } | ||||
|     wheels += "}"; | ||||
|     return "ProfilePoint: {" + vector.to_string() + ", wheels: " + wheels + | ||||
|            ", k: " + std::to_string(curvature) + | ||||
|            ", t: " + std::to_string(time) + "}"; | ||||
|   } | ||||
|  | ||||
|   std::string to_csv() const { | ||||
|     std::string wheels = ""; | ||||
|     for (auto& w : wheel_velocities) { | ||||
|       wheels += ","; | ||||
|       wheels += std::to_string(w); | ||||
|     } | ||||
|     return vector.to_csv() + "," + std::to_string(curvature) + "," + | ||||
|            std::to_string(time) + wheels; | ||||
|   } | ||||
|  | ||||
|   bool operator==(const ProfilePoint& other) const { | ||||
|     for (std::size_t i = 0; i < wheel_velocities.size(); ++i) { | ||||
|       if (!nearly_equal(wheel_velocities[i], other.wheel_velocities[i])) { | ||||
|         return false; | ||||
|       } | ||||
|     } | ||||
|     return vector == other.vector && nearly_equal(curvature, other.curvature) && | ||||
|            nearly_equal(time, other.time); | ||||
|   } | ||||
|  | ||||
|   friend std::ostream& operator<<(std::ostream& os, const ProfilePoint& p) { | ||||
|     return os << "ProfilePoint(ControlVector(Pose(" + | ||||
|                    std::to_string(p.vector.pose.x) + "," + | ||||
|                    std::to_string(p.vector.pose.y) + "," + | ||||
|                    std::to_string(p.vector.pose.yaw) + ")," + | ||||
|                    std::to_string(p.vector.vel) + "," + | ||||
|                    std::to_string(p.vector.accel) + "," + | ||||
|                    std::to_string(p.vector.jerk) + "),{" + | ||||
|                    std::to_string(p.wheel_velocities[0]) + "," + | ||||
|                    std::to_string(p.wheel_velocities[1]) + "}," + | ||||
|                    std::to_string(p.curvature) + "," + std::to_string(p.time) + | ||||
|                    "),"; | ||||
|     // return os << p.to_string(); | ||||
|   } | ||||
|  | ||||
|   ControlVector vector; | ||||
|   std::vector<double> wheel_velocities; | ||||
|   double curvature; | ||||
|   double time; | ||||
| }; | ||||
| } // namespace squiggles | ||||
|  | ||||
| #endif | ||||
							
								
								
									
										56
									
								
								SerialTest/include/okapi/squiggles/io.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										56
									
								
								SerialTest/include/okapi/squiggles/io.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,56 @@ | ||||
| /** | ||||
|  * Copyright 2020 Jonathan Bayless | ||||
|  * | ||||
|  * Use of this source code is governed by an MIT-style license that can be found | ||||
|  * in the LICENSE file or at https://opensource.org/licenses/MIT. | ||||
|  */ | ||||
| #ifndef _SQUIGGLES_IO_HPP_ | ||||
| #define _SQUIGGLES_IO_HPP_ | ||||
|  | ||||
| #include <optional> | ||||
| #include <vector> | ||||
|  | ||||
| #include "geometry/profilepoint.hpp" | ||||
|  | ||||
| namespace squiggles { | ||||
| /** | ||||
|  * Writes the path data to a CSV file. | ||||
|  * | ||||
|  * @param out The output stream to write the CSV data to. This is usually a | ||||
|  * file. | ||||
|  * @param path The path to serialized | ||||
|  * | ||||
|  * @return 0 if the path was serialized succesfully or -1 if an error occurred. | ||||
|  */ | ||||
| int serialize_path(std::ostream& out, std::vector<ProfilePoint> path); | ||||
|  | ||||
| /** | ||||
|  * Converts CSV data into a path. | ||||
|  * | ||||
|  * @param in The input stream containing the CSV data. This is usually a file. | ||||
|  * | ||||
|  * @return The path specified by the CSV data or std::nullopt if de-serializing | ||||
|  *         the path was unsuccessful. | ||||
|  */ | ||||
| std::optional<std::vector<ProfilePoint>> deserialize_path(std::istream& in); | ||||
|  | ||||
| /** | ||||
|  * Converts CSV data from the Pathfinder library's format to a Squiggles path. | ||||
|  * | ||||
|  * NOTE: this code translates data from Jaci Brunning's Pathfinder library. | ||||
|  * The source for that library can be found at: | ||||
|  * https://github.com/JaciBrunning/Pathfinder/ | ||||
|  * | ||||
|  * @param left The input stream containing the left wheels' CSV data. This is | ||||
|  *             usually a file. | ||||
|  * @param right The input stream containing the right wheels' CSV data. This is | ||||
|  *             usually a file. | ||||
|  * | ||||
|  * @return The path specified by the CSV data or std::nullopt if de-serializing | ||||
|  *         the path was unsuccessful. | ||||
|  */ | ||||
| std::optional<std::vector<ProfilePoint>> | ||||
| deserialize_pathfinder_path(std::istream& left, std::istream& right); | ||||
| } // namespace squiggles | ||||
|  | ||||
| #endif | ||||
| @@ -0,0 +1,65 @@ | ||||
| /** | ||||
|  * Copyright 2020 Jonathan Bayless | ||||
|  * | ||||
|  * Use of this source code is governed by an MIT-style license that can be found | ||||
|  * in the LICENSE file or at https://opensource.org/licenses/MIT. | ||||
|  */ | ||||
| #ifndef _MATH_QUINTIC_POLYNOMIAL_HPP_ | ||||
| #define _MATH_QUINTIC_POLYNOMIAL_HPP_ | ||||
|  | ||||
| #include <string> | ||||
|  | ||||
| namespace squiggles { | ||||
| class QuinticPolynomial { | ||||
|   public: | ||||
|   /** | ||||
|    * Defines the polynomial function for a spline in one dimension. | ||||
|    * | ||||
|    * @param s_p The starting position of the curve in meters. | ||||
|    * @param s_v The starting velocity of the curve in meters per second. | ||||
|    * @param s_a The starting acceleration of the curve in meters per second per | ||||
|    *            second. | ||||
|    * @param g_p The goal or ending position of the curve in meters. | ||||
|    * @param g_v The goal or ending velocity of the curve in meters per second. | ||||
|    * @param g_a The goal or ending acceleration of the curve in meters per | ||||
|    *            second per second. | ||||
|    * @param t The desired duration for the curve in seconds. | ||||
|    */ | ||||
|   QuinticPolynomial(double s_p, | ||||
|                     double s_v, | ||||
|                     double s_a, | ||||
|                     double g_p, | ||||
|                     double g_v, | ||||
|                     double g_a, | ||||
|                     double t); | ||||
|  | ||||
|   /** | ||||
|    * Calculates the values of the polynomial and its derivatives at the given | ||||
|    * time stamp. | ||||
|    */ | ||||
|   double calc_point(double t); | ||||
|   double calc_first_derivative(double t); | ||||
|   double calc_second_derivative(double t); | ||||
|   double calc_third_derivative(double t); | ||||
|  | ||||
|   /** | ||||
|    * Serializes the Quintic Polynomial data for debugging. | ||||
|    * | ||||
|    * @return The Quintic Polynomial data. | ||||
|    */ | ||||
|   std::string to_string() const { | ||||
|     return "QuinticPolynomial: {0: " + std::to_string(a0) + | ||||
|            " 1: " + std::to_string(a1) + " 2: " + std::to_string(a2) + | ||||
|            " 3: " + std::to_string(a3) + " 4: " + std::to_string(a4) + | ||||
|            " 5: " + std::to_string(a5) + "}"; | ||||
|   } | ||||
|  | ||||
|   protected: | ||||
|   /** | ||||
|    * The coefficients for each term of the polynomial. | ||||
|    */ | ||||
|   double a0, a1, a2, a3, a4, a5; | ||||
| }; | ||||
| } // namespace squiggles | ||||
|  | ||||
| #endif | ||||
							
								
								
									
										61
									
								
								SerialTest/include/okapi/squiggles/math/utils.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										61
									
								
								SerialTest/include/okapi/squiggles/math/utils.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,61 @@ | ||||
| /** | ||||
|  * Copyright 2020 Jonathan Bayless | ||||
|  * | ||||
|  * Use of this source code is governed by an MIT-style license that can be found | ||||
|  * in the LICENSE file or at https://opensource.org/licenses/MIT. | ||||
|  */ | ||||
| #ifndef _MATH_UTILS_HPP_ | ||||
| #define _MATH_UTILS_HPP_ | ||||
|  | ||||
| #include <cmath> | ||||
| #include <iostream> | ||||
|  | ||||
| namespace squiggles { | ||||
| /** | ||||
|  * Returns the sign value of the given value. | ||||
|  * | ||||
|  * @return 1 if the value is positive, -1 if the value is negative, and 0 if | ||||
|  *         the value is 0. | ||||
|  */ | ||||
| template <class T> inline int sgn(T v) { | ||||
|   return (v > T(0)) - (v < T(0)); | ||||
| } | ||||
|  | ||||
| inline bool | ||||
| nearly_equal(const double& a, const double& b, double epsilon = 1e-5) { | ||||
|   return std::fabs(a - b) < epsilon; | ||||
| } | ||||
| } // namespace squiggles | ||||
|  | ||||
| namespace std { | ||||
| // Copied from https://github.com/emsr/cxx_linear | ||||
| template <typename _Float> | ||||
| constexpr std::enable_if_t< | ||||
|   std::is_floating_point_v<_Float> && | ||||
|     __cplusplus <= 201703L, // Only defines this function if C++ standard < 20 | ||||
|   _Float> | ||||
| lerp(_Float __a, _Float __b, _Float __t) { | ||||
|   if (std::isnan(__a) || std::isnan(__b) || std::isnan(__t)) | ||||
|     return std::numeric_limits<_Float>::quiet_NaN(); | ||||
|   else if ((__a <= _Float{0} && __b >= _Float{0}) || | ||||
|            (__a >= _Float{0} && __b <= _Float{0})) | ||||
|   // ab <= 0 but product could overflow. | ||||
| #ifndef FMA | ||||
|     return __t * __b + (_Float{1} - __t) * __a; | ||||
| #else | ||||
|     return std::fma(__t, __b, (_Float{1} - __t) * __a); | ||||
| #endif | ||||
|   else if (__t == _Float{1}) | ||||
|     return __b; | ||||
|   else { // monotonic near t == 1. | ||||
| #ifndef FMA | ||||
|     const auto __x = __a + __t * (__b - __a); | ||||
| #else | ||||
|     const auto __x = std::fma(__t, __b - __a, __a); | ||||
| #endif | ||||
|     return (__t > _Float{1}) == (__b > __a) ? std::max(__b, __x) | ||||
|                                             : std::min(__b, __x); | ||||
|   } | ||||
| } | ||||
| } // namespace std | ||||
| #endif | ||||
| @@ -0,0 +1,38 @@ | ||||
| /** | ||||
|  * Copyright 2020 Jonathan Bayless | ||||
|  * | ||||
|  * Use of this source code is governed by an MIT-style license that can be found | ||||
|  * in the LICENSE file or at https://opensource.org/licenses/MIT. | ||||
|  */ | ||||
| #ifndef _PHYSICAL_MODEL_PASSTHROUGH_MODEL_HPP_ | ||||
| #define _PHYSICAL_MODEL_PASSTHROUGH_MODEL_HPP_ | ||||
|  | ||||
| #include "physicalmodel/physicalmodel.hpp" | ||||
|  | ||||
| namespace squiggles { | ||||
| class PassthroughModel : public PhysicalModel { | ||||
|   public: | ||||
|   /** | ||||
|    * Defines a Physical Model that imposes no constraints of its own. | ||||
|    */ | ||||
|   PassthroughModel() = default; | ||||
|  | ||||
|   Constraints constraints([[maybe_unused]] const Pose pose, | ||||
|                           [[maybe_unused]] double curvature, | ||||
|                           double vel) override { | ||||
|     return Constraints(vel); | ||||
|   }; | ||||
|  | ||||
|   std::vector<double> | ||||
|   linear_to_wheel_vels([[maybe_unused]] double lin_vel, | ||||
|                        [[maybe_unused]] double curvature) override { | ||||
|     return std::vector<double>{}; | ||||
|   } | ||||
|  | ||||
|   std::string to_string() const override { | ||||
|     return "PassthroughModel {}"; | ||||
|   } | ||||
| }; | ||||
| } // namespace squiggles | ||||
|  | ||||
| #endif | ||||
| @@ -0,0 +1,43 @@ | ||||
| /** | ||||
|  * Copyright 2020 Jonathan Bayless | ||||
|  * | ||||
|  * Use of this source code is governed by an MIT-style license that can be found | ||||
|  * in the LICENSE file or at https://opensource.org/licenses/MIT. | ||||
|  */ | ||||
| #ifndef _PHYSICAL_MODEL_PHYSICAL_MODEL_HPP_ | ||||
| #define _PHYSICAL_MODEL_PHYSICAL_MODEL_HPP_ | ||||
|  | ||||
| #include "constraints.hpp" | ||||
| #include "geometry/pose.hpp" | ||||
|  | ||||
| namespace squiggles { | ||||
| class PhysicalModel { | ||||
|   public: | ||||
|   /** | ||||
|    * Calculate a set of stricter constraints for the path at the given state | ||||
|    * than the general constraints based on the robot's kinematics. | ||||
|    * | ||||
|    * @param pose The 2D pose for this state in the path. | ||||
|    * @param curvature The change in heading at this state in the path in 1 / | ||||
|    *                  meters. | ||||
|    * @param vel The linear velocity at this state in the path in meters per | ||||
|    * second. | ||||
|    */ | ||||
|   virtual Constraints | ||||
|   constraints(const Pose pose, double curvature, double vel) = 0; | ||||
|  | ||||
|   /** | ||||
|    * Converts a linear velocity and desired curvature into the component for | ||||
|    * each wheel of the robot. | ||||
|    * | ||||
|    * @param linear The linear velocity for the robot in meters per second. | ||||
|    * @param curvature The change in heading for the robot in 1 / meters. | ||||
|    */ | ||||
|   virtual std::vector<double> linear_to_wheel_vels(double linear, | ||||
|                                                    double curvature) = 0; | ||||
|  | ||||
|   virtual std::string to_string() const = 0; | ||||
| }; | ||||
| } // namespace squiggles | ||||
|  | ||||
| #endif | ||||
| @@ -0,0 +1,45 @@ | ||||
| /** | ||||
|  * Copyright 2020 Jonathan Bayless | ||||
|  * | ||||
|  * Use of this source code is governed by an MIT-style license that can be found | ||||
|  * in the LICENSE file or at https://opensource.org/licenses/MIT. | ||||
|  */ | ||||
| #ifndef _PHYSICAL_MODEL_TANK_MODEL_HPP_ | ||||
| #define _PHYSICAL_MODEL_TANK_MODEL_HPP_ | ||||
|  | ||||
| #include <tuple> | ||||
| #include <vector> | ||||
|  | ||||
| #include "physicalmodel/physicalmodel.hpp" | ||||
|  | ||||
| namespace squiggles { | ||||
| class TankModel : public PhysicalModel { | ||||
|   public: | ||||
|   /** | ||||
|    * Defines a model of a tank drive or differential drive robot. | ||||
|    * | ||||
|    * @param itrack_width The distance between the the wheels on each side of the | ||||
|    *                     robot in meters. | ||||
|    * @param ilinear_constraints The maximum values for the robot's movement. | ||||
|    */ | ||||
|   TankModel(double itrack_width, Constraints ilinear_constraints); | ||||
|  | ||||
|   Constraints | ||||
|   constraints(const Pose pose, double curvature, double vel) override; | ||||
|  | ||||
|   std::vector<double> linear_to_wheel_vels(double lin_vel, | ||||
|                                            double curvature) override; | ||||
|  | ||||
|   std::string to_string() const override; | ||||
|  | ||||
|   private: | ||||
|   double vel_constraint(const Pose pose, double curvature, double vel); | ||||
|   std::tuple<double, double> | ||||
|   accel_constraint(const Pose pose, double curvature, double vel) const; | ||||
|  | ||||
|   double track_width; | ||||
|   Constraints linear_constraints; | ||||
| }; | ||||
| } // namespace squiggles | ||||
|  | ||||
| #endif | ||||
							
								
								
									
										310
									
								
								SerialTest/include/okapi/squiggles/spline.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										310
									
								
								SerialTest/include/okapi/squiggles/spline.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,310 @@ | ||||
| /** | ||||
|  * Copyright 2020 Jonathan Bayless | ||||
|  * | ||||
|  * Use of this source code is governed by an MIT-style license that can be found | ||||
|  * in the LICENSE file or at https://opensource.org/licenses/MIT. | ||||
|  */ | ||||
| #ifndef _SQUIGGLES_SPLINE_HPP_ | ||||
| #define _SQUIGGLES_SPLINE_HPP_ | ||||
|  | ||||
| #include <initializer_list> | ||||
| #include <memory> | ||||
| #include <vector> | ||||
|  | ||||
| #include "constraints.hpp" | ||||
| #include "geometry/controlvector.hpp" | ||||
| #include "geometry/profilepoint.hpp" | ||||
| #include "math/quinticpolynomial.hpp" | ||||
| #include "physicalmodel/passthroughmodel.hpp" | ||||
| #include "physicalmodel/physicalmodel.hpp" | ||||
|  | ||||
| namespace squiggles { | ||||
| class SplineGenerator { | ||||
|   public: | ||||
|   /** | ||||
|    * Generates curves that match the given motion constraints. | ||||
|    * | ||||
|    * @param iconstraints The maximum allowable values for the robot's motion. | ||||
|    * @param imodel The robot's physical characteristics and constraints | ||||
|    * @param idt The difference in time in seconds between each state for the | ||||
|    *            generated paths. | ||||
|    */ | ||||
|   SplineGenerator(Constraints iconstraints, | ||||
|                   std::shared_ptr<PhysicalModel> imodel = | ||||
|                     std::make_shared<PassthroughModel>(), | ||||
|                   double idt = 0.1); | ||||
|  | ||||
|   /** | ||||
|    * Creates a motion profiled path between the given waypoints. | ||||
|    * | ||||
|    * @param iwaypoints The list of poses that the robot should reach along the | ||||
|    *                   path. | ||||
|    * @param fast If true, the path optimization process will stop as soon as the | ||||
|    *             constraints are met. If false, the optimizer will find the | ||||
|    *             smoothest possible path between the points. | ||||
|    * | ||||
|    * @return A series of robot states defining a path between the poses. | ||||
|    */ | ||||
|   std::vector<ProfilePoint> generate(std::vector<Pose> iwaypoints, | ||||
|                                      bool fast = false); | ||||
|   std::vector<ProfilePoint> generate(std::initializer_list<Pose> iwaypoints, | ||||
|                                      bool fast = false); | ||||
|  | ||||
|   /** | ||||
|    * Creates a motion profiled path between the given waypoints. | ||||
|    * | ||||
|    * @param iwaypoints The list of vectors that the robot should reach along the | ||||
|    *                   path. | ||||
|    * | ||||
|    * @return A series of robot states defining a path between the vectors. | ||||
|    */ | ||||
|   std::vector<ProfilePoint> generate(std::vector<ControlVector> iwaypoints); | ||||
|   std::vector<ProfilePoint> | ||||
|   generate(std::initializer_list<ControlVector> iwaypoints); | ||||
|  | ||||
|   protected: | ||||
|   /** | ||||
|    * The maximum allowable values for the robot's motion. | ||||
|    */ | ||||
|   Constraints constraints; | ||||
|  | ||||
|   /** | ||||
|    * Defines the physical structure of the robot and translates the linear | ||||
|    * kinematics to wheel velocities. | ||||
|    */ | ||||
|   std::shared_ptr<PhysicalModel> model; | ||||
|  | ||||
|   /** | ||||
|    * The time difference between each value in the generated path. | ||||
|    */ | ||||
|   double dt; | ||||
|  | ||||
|   /** | ||||
|    * The minimum and maximum durations for a path to take. A larger range allows | ||||
|    * for longer possible paths at the expense of a longer path generation time. | ||||
|    */ | ||||
|   const int T_MIN = 2; | ||||
|   const int T_MAX = 15; | ||||
|   const int MAX_GRAD_DESCENT_ITERATIONS = 10; | ||||
|  | ||||
|   /** | ||||
|    * This is factor is used to create a "dummy velocity" in the initial path | ||||
|    * generation step one or both of the preferred start or end velocities is | ||||
|    * zero. The velocity will be replaced with the preferred start/end velocity | ||||
|    * in parameterization but a nonzero velocity is needed for the spline | ||||
|    * calculation. | ||||
|    * | ||||
|    * This was 1.2 in the WPILib example but that large of a value seems to | ||||
|    * create wild paths, 0.12 worked better in testing with VEX-sized paths. | ||||
|    */ | ||||
|   public: | ||||
|   const double K_DEFAULT_VEL = 1.0; | ||||
|  | ||||
|   /** | ||||
|    * The output of the initial, "naive" generation step. We discard the | ||||
|    * derivative values to replace them with values from a motion profile. | ||||
|    */ | ||||
|  | ||||
|   struct GeneratedPoint { | ||||
|     GeneratedPoint(Pose ipose, double icurvature = 0.0) | ||||
|       : pose(ipose), curvature(icurvature) {} | ||||
|  | ||||
|     std::string to_string() const { | ||||
|       return "GeneratedPoint: {" + pose.to_string() + | ||||
|              ", curvature: " + std::to_string(curvature) + "}"; | ||||
|     } | ||||
|  | ||||
|     Pose pose; | ||||
|     double curvature; | ||||
|   }; | ||||
|  | ||||
|   /** | ||||
|    * An intermediate value used in the "naive" generation step. Contains the | ||||
|    * final GeneratedPoint value that will be returned as well as the spline's | ||||
|    * derivative values to perform the initial check against the constraints. | ||||
|    */ | ||||
|   struct GeneratedVector { | ||||
|     GeneratedVector(GeneratedPoint ipoint, | ||||
|                     double ivel, | ||||
|                     double iaccel, | ||||
|                     double ijerk) | ||||
|       : point(ipoint), vel(ivel), accel(iaccel), jerk(ijerk) {} | ||||
|  | ||||
|     GeneratedPoint point; | ||||
|     double vel; | ||||
|     double accel; | ||||
|     double jerk; | ||||
|  | ||||
|     std::string to_string() const { | ||||
|       return "GeneratedVector: {" + point.to_string() + | ||||
|              ", vel: " + std::to_string(vel) + | ||||
|              ", accel: " + std::to_string(accel) + | ||||
|              ", jerk: " + std::to_string(jerk) + "}"; | ||||
|     } | ||||
|   }; | ||||
|  | ||||
|   std::vector<GeneratedVector> gen_single_raw_path(ControlVector start, | ||||
|                                                    ControlVector end, | ||||
|                                                    int duration, | ||||
|                                                    double start_vel, | ||||
|                                                    double end_vel); | ||||
|   /** | ||||
|    * Runs a Gradient Descent algorithm to minimize the linear acceleration, | ||||
|    * linear jerk, and curvature for the generated path. | ||||
|    * | ||||
|    * This is used when there is not a start/end velocity specified for a given | ||||
|    * path. | ||||
|    */ | ||||
|   std::vector<GeneratedPoint> | ||||
|   gradient_descent(ControlVector& start, ControlVector& end, bool fast); | ||||
|  | ||||
|   /** | ||||
|    * An intermediate value used in the parameterization step. Adds the | ||||
|    * constrained values from the motion profile to the output from the "naive" | ||||
|    * generation step. | ||||
|    */ | ||||
|   struct ConstrainedState { | ||||
|     ConstrainedState(Pose ipose, | ||||
|                      double icurvature, | ||||
|                      double idistance, | ||||
|                      double imax_vel, | ||||
|                      double imin_accel, | ||||
|                      double imax_accel) | ||||
|       : pose(ipose), | ||||
|         curvature(icurvature), | ||||
|         distance(idistance), | ||||
|         max_vel(imax_vel), | ||||
|         min_accel(imin_accel), | ||||
|         max_accel(imax_accel) {} | ||||
|  | ||||
|     ConstrainedState() = default; | ||||
|  | ||||
|     Pose pose = Pose(); | ||||
|     double curvature = 0; | ||||
|     double distance = 0; | ||||
|     double max_vel = 0; | ||||
|     double min_accel = 0; | ||||
|     double max_accel = 0; | ||||
|  | ||||
|     std::string to_string() const { | ||||
|       return "ConstrainedState: {x: " + std::to_string(pose.x) + | ||||
|              ", y: " + std::to_string(pose.y) + | ||||
|              ", yaw: " + std::to_string(pose.yaw) + | ||||
|              ", k: " + std::to_string(curvature) + | ||||
|              ", dist: " + std::to_string(distance) + | ||||
|              ", v: " + std::to_string(max_vel) + | ||||
|              ", min_a: " + std::to_string(min_accel) + | ||||
|              ", max_a: " + std::to_string(max_accel) + "}"; | ||||
|     } | ||||
|   }; | ||||
|  | ||||
|   /** | ||||
|    * The actual function called by the "generate" functions. | ||||
|    * | ||||
|    * @param start An iterator pointing to the first ControlVector in the path | ||||
|    * @param end An iterator pointting to the last ControlVector in the path | ||||
|    * | ||||
|    * @return The points from each path concatenated together | ||||
|    */ | ||||
|   template <class Iter> | ||||
|   std::vector<ProfilePoint> _generate(Iter start, Iter end, bool fast); | ||||
|  | ||||
|   public: | ||||
|   /** | ||||
|    * Performs the "naive" generation step. | ||||
|    * | ||||
|    * This step calculates the spline polynomials that fit within the | ||||
|    * SplineGenerator's acceleration and jerk constraints and returns the points | ||||
|    * that form the curve. | ||||
|    */ | ||||
|   std::vector<GeneratedPoint> | ||||
|   gen_raw_path(ControlVector& start, ControlVector& end, bool fast); | ||||
|  | ||||
|   /** | ||||
|    * Imposes a linear motion profile on the raw path. | ||||
|    * | ||||
|    * This step creates the velocity and acceleration values to command the robot | ||||
|    * at each point along the curve. | ||||
|    */ | ||||
|   std::vector<ProfilePoint> | ||||
|   parameterize(const ControlVector start, | ||||
|                const ControlVector end, | ||||
|                const std::vector<GeneratedPoint>& raw_path, | ||||
|                const double preferred_start_vel, | ||||
|                const double preferred_end_vel, | ||||
|                const double start_time); | ||||
|  | ||||
|   /** | ||||
|    * Finds the new timestamps for each point along the curve based on the motion | ||||
|    * profile. | ||||
|    */ | ||||
|   std::vector<ProfilePoint> | ||||
|   integrate_constrained_states(std::vector<ConstrainedState> constrainedStates); | ||||
|  | ||||
|   /** | ||||
|    * Finds the ProfilePoint on the profiled curve for the given timestamp. | ||||
|    * | ||||
|    * This with interpolate between points on the curve if a point with an exact | ||||
|    * matching timestamp is not found. | ||||
|    */ | ||||
|   ProfilePoint get_point_at_time(const ControlVector start, | ||||
|                                  const ControlVector end, | ||||
|                                  std::vector<ProfilePoint> points, | ||||
|                                  double t); | ||||
|  | ||||
|   /** | ||||
|    * Linearly interpolates between points along the profiled curve. | ||||
|    */ | ||||
|   ProfilePoint lerp_point(QuinticPolynomial x_qp, | ||||
|                           QuinticPolynomial y_qp, | ||||
|                           ProfilePoint start, | ||||
|                           ProfilePoint end, | ||||
|                           double i); | ||||
|  | ||||
|   /** | ||||
|    * Returns the spline curve for the given control vectors and path duration. | ||||
|    */ | ||||
|   QuinticPolynomial get_x_spline(const ControlVector start, | ||||
|                                  const ControlVector end, | ||||
|                                  const double duration); | ||||
|   QuinticPolynomial get_y_spline(const ControlVector start, | ||||
|                                  const ControlVector end, | ||||
|                                  const double duration); | ||||
|  | ||||
|   /** | ||||
|    * Applies the general constraints and model constraints to the given state. | ||||
|    */ | ||||
|   void enforce_accel_lims(ConstrainedState* state); | ||||
|  | ||||
|   /** | ||||
|    * Imposes the motion profile constraints on a segment of the path from the | ||||
|    * perspective of iterating forwards through the path. | ||||
|    */ | ||||
|   void forward_pass(ConstrainedState* predecessor, ConstrainedState* successor); | ||||
|  | ||||
|   /** | ||||
|    * Imposes the motion profile constraints on a segment of the path from the | ||||
|    * perspective of iterating backwards through the path. | ||||
|    */ | ||||
|   void backward_pass(ConstrainedState* predecessor, | ||||
|                      ConstrainedState* successor); | ||||
|  | ||||
|   /** | ||||
|    * Calculates the final velocity for a path segment. | ||||
|    */ | ||||
|   double vf(double vi, double a, double ds); | ||||
|  | ||||
|   /** | ||||
|    * Calculates the initial acceleration needed to match the segments' | ||||
|    * velocities. | ||||
|    */ | ||||
|   double ai(double vf, double vi, double s); | ||||
|  | ||||
|   /** | ||||
|    * Values that are closer to each other than this value are considered equal. | ||||
|    */ | ||||
|   static constexpr double K_EPSILON = 1e-5; | ||||
| }; | ||||
| } // namespace squiggles | ||||
|  | ||||
| #endif | ||||
							
								
								
									
										22
									
								
								SerialTest/include/okapi/squiggles/squiggles.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								SerialTest/include/okapi/squiggles/squiggles.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,22 @@ | ||||
| /** | ||||
|  * Copyright 2020 Jonathan Bayless | ||||
|  * | ||||
|  * Use of this source code is governed by an MIT-style license that can be found | ||||
|  * in the LICENSE file or at https://opensource.org/licenses/MIT. | ||||
|  */ | ||||
| #ifndef _ROBOT_SQUIGGLES_H_ | ||||
| #define _ROBOT_SQUIGGLES_H_ | ||||
|  | ||||
| #include "geometry/controlvector.hpp" | ||||
| #include "geometry/pose.hpp" | ||||
| #include "geometry/profilepoint.hpp" | ||||
|  | ||||
| #include "physicalmodel/passthroughmodel.hpp" | ||||
| #include "physicalmodel/physicalmodel.hpp" | ||||
| #include "physicalmodel/tankmodel.hpp" | ||||
|  | ||||
| #include "constraints.hpp" | ||||
| #include "io.hpp" | ||||
| #include "spline.hpp" | ||||
|  | ||||
| #endif | ||||
		Reference in New Issue
	
	Block a user