Initial commit - test serial
This commit is contained in:
		
							
								
								
									
										134
									
								
								SerialTest/include/okapi/api.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										134
									
								
								SerialTest/include/okapi/api.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,134 @@ | ||||
| /* | ||||
|  * This Source Code Form is subject to the terms of the Mozilla Public | ||||
|  * License, v. 2.0. If a copy of the MPL was not distributed with this | ||||
|  * file, You can obtain one at http://mozilla.org/MPL/2.0/. | ||||
|  */ | ||||
| #pragma once | ||||
|  | ||||
| /** @mainpage OkapiLib Index Page | ||||
|  * | ||||
|  * @section intro_sec Introduction | ||||
|  * | ||||
|  * **OkapiLib** is a PROS library for programming VEX V5 robots. This library is intended to raise | ||||
|  * the floor for teams with all levels of experience. New teams should have an easier time getting | ||||
|  * their robot up and running, and veteran teams should find that OkapiLib doesn't get in the way or | ||||
|  * place any limits on functionality. | ||||
|  * | ||||
|  * For tutorials on how to get the most out of OkapiLib, see the | ||||
|  * [Tutorials](docs/tutorials/index.md) section. For documentation on using the OkapiLib API, see | ||||
|  * the [API](docs/api/index.md) section. | ||||
|  * | ||||
|  * @section getting_started Getting Started | ||||
|  * Not sure where to start? Take a look at the | ||||
|  * [Getting Started](docs/tutorials/walkthrough/gettingStarted.md) tutorial. | ||||
|  * Once you have OkapiLib set up, check out the | ||||
|  * [Clawbot](docs/tutorials/walkthrough/clawbot.md) tutorial. | ||||
|  * | ||||
|  * @section using_docs Using The Documentation | ||||
|  * | ||||
|  * Start with reading the [Tutorials](docs/tutorials/index.md). Use the [API](docs/api/index.md) | ||||
|  * section to explore the class hierarchy. To see a list of all available classes, use the | ||||
|  * [Classes](annotated.html) section. | ||||
|  * | ||||
|  * This documentation has a powerful search feature, which can be brought up with the keyboard | ||||
|  * shortcuts `Tab` or `T`. All exports to the `okapi` namespace such as enums, constants, units, or | ||||
|  * functions can be found [here](@ref okapi). | ||||
|  */ | ||||
|  | ||||
| #include "okapi/api/chassis/controller/chassisControllerIntegrated.hpp" | ||||
| #include "okapi/api/chassis/controller/chassisControllerPid.hpp" | ||||
| #include "okapi/api/chassis/controller/chassisScales.hpp" | ||||
| #include "okapi/api/chassis/controller/defaultOdomChassisController.hpp" | ||||
| #include "okapi/api/chassis/controller/odomChassisController.hpp" | ||||
| #include "okapi/api/chassis/model/hDriveModel.hpp" | ||||
| #include "okapi/api/chassis/model/readOnlyChassisModel.hpp" | ||||
| #include "okapi/api/chassis/model/skidSteerModel.hpp" | ||||
| #include "okapi/api/chassis/model/threeEncoderSkidSteerModel.hpp" | ||||
| #include "okapi/api/chassis/model/threeEncoderXDriveModel.hpp" | ||||
| #include "okapi/api/chassis/model/xDriveModel.hpp" | ||||
| #include "okapi/impl/chassis/controller/chassisControllerBuilder.hpp" | ||||
|  | ||||
| #include "okapi/api/control/async/asyncLinearMotionProfileController.hpp" | ||||
| #include "okapi/api/control/async/asyncMotionProfileController.hpp" | ||||
| #include "okapi/api/control/async/asyncPosIntegratedController.hpp" | ||||
| #include "okapi/api/control/async/asyncPosPidController.hpp" | ||||
| #include "okapi/api/control/async/asyncVelIntegratedController.hpp" | ||||
| #include "okapi/api/control/async/asyncVelPidController.hpp" | ||||
| #include "okapi/api/control/async/asyncWrapper.hpp" | ||||
| #include "okapi/api/control/controllerInput.hpp" | ||||
| #include "okapi/api/control/controllerOutput.hpp" | ||||
| #include "okapi/api/control/iterative/iterativeMotorVelocityController.hpp" | ||||
| #include "okapi/api/control/iterative/iterativePosPidController.hpp" | ||||
| #include "okapi/api/control/iterative/iterativeVelPidController.hpp" | ||||
| #include "okapi/api/control/util/controllerRunner.hpp" | ||||
| #include "okapi/api/control/util/flywheelSimulator.hpp" | ||||
| #include "okapi/api/control/util/pidTuner.hpp" | ||||
| #include "okapi/api/control/util/settledUtil.hpp" | ||||
| #include "okapi/impl/control/async/asyncMotionProfileControllerBuilder.hpp" | ||||
| #include "okapi/impl/control/async/asyncPosControllerBuilder.hpp" | ||||
| #include "okapi/impl/control/async/asyncVelControllerBuilder.hpp" | ||||
| #include "okapi/impl/control/iterative/iterativeControllerFactory.hpp" | ||||
| #include "okapi/impl/control/util/controllerRunnerFactory.hpp" | ||||
| #include "okapi/impl/control/util/pidTunerFactory.hpp" | ||||
|  | ||||
| #include "okapi/api/odometry/odomMath.hpp" | ||||
| #include "okapi/api/odometry/odometry.hpp" | ||||
| #include "okapi/api/odometry/threeEncoderOdometry.hpp" | ||||
|  | ||||
| #include "okapi/api/device/rotarysensor/continuousRotarySensor.hpp" | ||||
| #include "okapi/api/device/rotarysensor/rotarySensor.hpp" | ||||
| #include "okapi/impl/device/adiUltrasonic.hpp" | ||||
| #include "okapi/impl/device/button/adiButton.hpp" | ||||
| #include "okapi/impl/device/button/controllerButton.hpp" | ||||
| #include "okapi/impl/device/controller.hpp" | ||||
| #include "okapi/impl/device/distanceSensor.hpp" | ||||
| #include "okapi/impl/device/motor/adiMotor.hpp" | ||||
| #include "okapi/impl/device/motor/motor.hpp" | ||||
| #include "okapi/impl/device/motor/motorGroup.hpp" | ||||
| #include "okapi/impl/device/opticalSensor.hpp" | ||||
| #include "okapi/impl/device/rotarysensor/IMU.hpp" | ||||
| #include "okapi/impl/device/rotarysensor/adiEncoder.hpp" | ||||
| #include "okapi/impl/device/rotarysensor/adiGyro.hpp" | ||||
| #include "okapi/impl/device/rotarysensor/integratedEncoder.hpp" | ||||
| #include "okapi/impl/device/rotarysensor/potentiometer.hpp" | ||||
| #include "okapi/impl/device/rotarysensor/rotationSensor.hpp" | ||||
|  | ||||
| #include "okapi/api/filter/averageFilter.hpp" | ||||
| #include "okapi/api/filter/composableFilter.hpp" | ||||
| #include "okapi/api/filter/demaFilter.hpp" | ||||
| #include "okapi/api/filter/ekfFilter.hpp" | ||||
| #include "okapi/api/filter/emaFilter.hpp" | ||||
| #include "okapi/api/filter/filter.hpp" | ||||
| #include "okapi/api/filter/filteredControllerInput.hpp" | ||||
| #include "okapi/api/filter/medianFilter.hpp" | ||||
| #include "okapi/api/filter/passthroughFilter.hpp" | ||||
| #include "okapi/api/filter/velMath.hpp" | ||||
| #include "okapi/impl/filter/velMathFactory.hpp" | ||||
|  | ||||
| #include "okapi/api/units/QAcceleration.hpp" | ||||
| #include "okapi/api/units/QAngle.hpp" | ||||
| #include "okapi/api/units/QAngularAcceleration.hpp" | ||||
| #include "okapi/api/units/QAngularJerk.hpp" | ||||
| #include "okapi/api/units/QAngularSpeed.hpp" | ||||
| #include "okapi/api/units/QArea.hpp" | ||||
| #include "okapi/api/units/QForce.hpp" | ||||
| #include "okapi/api/units/QFrequency.hpp" | ||||
| #include "okapi/api/units/QJerk.hpp" | ||||
| #include "okapi/api/units/QLength.hpp" | ||||
| #include "okapi/api/units/QMass.hpp" | ||||
| #include "okapi/api/units/QPressure.hpp" | ||||
| #include "okapi/api/units/QSpeed.hpp" | ||||
| #include "okapi/api/units/QTime.hpp" | ||||
| #include "okapi/api/units/QTorque.hpp" | ||||
| #include "okapi/api/units/QVolume.hpp" | ||||
| #include "okapi/api/units/RQuantityName.hpp" | ||||
|  | ||||
| #include "okapi/api/util/abstractRate.hpp" | ||||
| #include "okapi/api/util/abstractTimer.hpp" | ||||
| #include "okapi/api/util/mathUtil.hpp" | ||||
| #include "okapi/api/util/supplier.hpp" | ||||
| #include "okapi/api/util/timeUtil.hpp" | ||||
| #include "okapi/impl/util/configurableTimeUtilFactory.hpp" | ||||
| #include "okapi/impl/util/rate.hpp" | ||||
| #include "okapi/impl/util/timeUtilFactory.hpp" | ||||
| #include "okapi/impl/util/timer.hpp" | ||||
| @@ -0,0 +1,142 @@ | ||||
| /* | ||||
|  * This Source Code Form is subject to the terms of the Mozilla Public | ||||
|  * License, v. 2.0. If a copy of the MPL was not distributed with this | ||||
|  * file, You can obtain one at http://mozilla.org/MPL/2.0/. | ||||
|  */ | ||||
| #pragma once | ||||
|  | ||||
| #include "okapi/api/chassis/controller/chassisScales.hpp" | ||||
| #include "okapi/api/chassis/model/chassisModel.hpp" | ||||
| #include "okapi/api/device/motor/abstractMotor.hpp" | ||||
| #include "okapi/api/units/QAngle.hpp" | ||||
| #include "okapi/api/units/QLength.hpp" | ||||
| #include <memory> | ||||
| #include <valarray> | ||||
|  | ||||
| namespace okapi { | ||||
| class ChassisController { | ||||
|   public: | ||||
|   /** | ||||
|    * A ChassisController adds a closed-loop layer on top of a ChassisModel. moveDistance and | ||||
|    * turnAngle both use closed-loop control to move the robot. There are passthrough functions for | ||||
|    * everything defined in ChassisModel. | ||||
|    * | ||||
|    * @param imodel underlying ChassisModel | ||||
|    */ | ||||
|   explicit ChassisController() = default; | ||||
|  | ||||
|   virtual ~ChassisController() = default; | ||||
|  | ||||
|   /** | ||||
|    * Drives the robot straight for a distance (using closed-loop control). | ||||
|    * | ||||
|    * @param itarget distance to travel | ||||
|    */ | ||||
|   virtual void moveDistance(QLength itarget) = 0; | ||||
|  | ||||
|   /** | ||||
|    * Drives the robot straight for a distance (using closed-loop control). | ||||
|    * | ||||
|    * @param itarget distance to travel in motor degrees | ||||
|    */ | ||||
|   virtual void moveRaw(double itarget) = 0; | ||||
|  | ||||
|   /** | ||||
|    * Sets the target distance for the robot to drive straight (using closed-loop control). | ||||
|    * | ||||
|    * @param itarget distance to travel | ||||
|    */ | ||||
|   virtual void moveDistanceAsync(QLength itarget) = 0; | ||||
|  | ||||
|   /** | ||||
|    * Sets the target distance for the robot to drive straight (using closed-loop control). | ||||
|    * | ||||
|    * @param itarget distance to travel in motor degrees | ||||
|    */ | ||||
|   virtual void moveRawAsync(double itarget) = 0; | ||||
|  | ||||
|   /** | ||||
|    * Turns the robot clockwise in place (using closed-loop control). | ||||
|    * | ||||
|    * @param idegTarget angle to turn for | ||||
|    */ | ||||
|   virtual void turnAngle(QAngle idegTarget) = 0; | ||||
|  | ||||
|   /** | ||||
|    * Turns the robot clockwise in place (using closed-loop control). | ||||
|    * | ||||
|    * @param idegTarget angle to turn for in motor degrees | ||||
|    */ | ||||
|   virtual void turnRaw(double idegTarget) = 0; | ||||
|  | ||||
|   /** | ||||
|    * Sets the target angle for the robot to turn clockwise in place (using closed-loop control). | ||||
|    * | ||||
|    * @param idegTarget angle to turn for | ||||
|    */ | ||||
|   virtual void turnAngleAsync(QAngle idegTarget) = 0; | ||||
|  | ||||
|   /** | ||||
|    * Sets the target angle for the robot to turn clockwise in place (using closed-loop control). | ||||
|    * | ||||
|    * @param idegTarget angle to turn for in motor degrees | ||||
|    */ | ||||
|   virtual void turnRawAsync(double idegTarget) = 0; | ||||
|  | ||||
|   /** | ||||
|    * Sets whether turns should be mirrored. | ||||
|    * | ||||
|    * @param ishouldMirror whether turns should be mirrored | ||||
|    */ | ||||
|   virtual void setTurnsMirrored(bool ishouldMirror) = 0; | ||||
|  | ||||
|   /** | ||||
|    * Checks whether the internal controllers are currently settled. | ||||
|    * | ||||
|    * @return Whether this ChassisController is settled. | ||||
|    */ | ||||
|   virtual bool isSettled() = 0; | ||||
|  | ||||
|   /** | ||||
|    * Delays until the currently executing movement completes. | ||||
|    */ | ||||
|   virtual void waitUntilSettled() = 0; | ||||
|  | ||||
|   /** | ||||
|    * Interrupts the current movement to stop the robot. | ||||
|    */ | ||||
|   virtual void stop() = 0; | ||||
|  | ||||
|   /** | ||||
|    * Sets a new maximum velocity in RPM [0-600]. | ||||
|    * | ||||
|    * @param imaxVelocity The new maximum velocity. | ||||
|    */ | ||||
|   virtual void setMaxVelocity(double imaxVelocity) = 0; | ||||
|  | ||||
|   /** | ||||
|    * @return The maximum velocity in RPM [0-600]. | ||||
|    */ | ||||
|   virtual double getMaxVelocity() const = 0; | ||||
|  | ||||
|   /** | ||||
|    * Get the ChassisScales. | ||||
|    */ | ||||
|   virtual ChassisScales getChassisScales() const = 0; | ||||
|  | ||||
|   /** | ||||
|    * Get the GearsetRatioPair. | ||||
|    */ | ||||
|   virtual AbstractMotor::GearsetRatioPair getGearsetRatioPair() const = 0; | ||||
|  | ||||
|   /** | ||||
|    * @return The internal ChassisModel. | ||||
|    */ | ||||
|   virtual std::shared_ptr<ChassisModel> getModel() = 0; | ||||
|  | ||||
|   /** | ||||
|    * @return The internal ChassisModel. | ||||
|    */ | ||||
|   virtual ChassisModel &model() = 0; | ||||
| }; | ||||
| } // namespace okapi | ||||
| @@ -0,0 +1,184 @@ | ||||
| /* | ||||
|  * This Source Code Form is subject to the terms of the Mozilla Public | ||||
|  * License, v. 2.0. If a copy of the MPL was not distributed with this | ||||
|  * file, You can obtain one at http://mozilla.org/MPL/2.0/. | ||||
|  */ | ||||
| #pragma once | ||||
|  | ||||
| #include "okapi/api/chassis/controller/chassisController.hpp" | ||||
| #include "okapi/api/control/async/asyncPosIntegratedController.hpp" | ||||
| #include "okapi/api/util/logging.hpp" | ||||
| #include "okapi/api/util/timeUtil.hpp" | ||||
|  | ||||
| namespace okapi { | ||||
| class ChassisControllerIntegrated : public ChassisController { | ||||
|   public: | ||||
|   /** | ||||
|    * ChassisController using the V5 motor's integrated control. Puts the motors into encoder count | ||||
|    * units. Throws a `std::invalid_argument` exception if the gear ratio is zero. The initial | ||||
|    * model's max velocity will be propagated to the controllers. | ||||
|    * | ||||
|    * @param itimeUtil The TimeUtil. | ||||
|    * @param imodel The ChassisModel used to read from sensors/write to motors. | ||||
|    * @param ileftController The controller used for the left side motors. | ||||
|    * @param irightController The controller used for the right side motors. | ||||
|    * @param igearset The internal gearset and external ratio used on the drive motors. | ||||
|    * @param iscales The ChassisScales. | ||||
|    * @param ilogger The logger this instance will log to. | ||||
|    */ | ||||
|   ChassisControllerIntegrated( | ||||
|     const TimeUtil &itimeUtil, | ||||
|     std::shared_ptr<ChassisModel> imodel, | ||||
|     std::unique_ptr<AsyncPosIntegratedController> ileftController, | ||||
|     std::unique_ptr<AsyncPosIntegratedController> irightController, | ||||
|     const AbstractMotor::GearsetRatioPair &igearset = AbstractMotor::gearset::green, | ||||
|     const ChassisScales &iscales = ChassisScales({1, 1}, imev5GreenTPR), | ||||
|     std::shared_ptr<Logger> ilogger = Logger::getDefaultLogger()); | ||||
|  | ||||
|   /** | ||||
|    * Drives the robot straight for a distance (using closed-loop control). | ||||
|    * | ||||
|    * ```cpp | ||||
|    * // Drive forward 6 inches | ||||
|    * chassis->moveDistance(6_in); | ||||
|    * | ||||
|    * // Drive backward 0.2 meters | ||||
|    * chassis->moveDistance(-0.2_m); | ||||
|    * ``` | ||||
|    * | ||||
|    * @param itarget distance to travel | ||||
|    */ | ||||
|   void moveDistance(QLength itarget) override; | ||||
|  | ||||
|   /** | ||||
|    * Drives the robot straight for a distance (using closed-loop control). | ||||
|    * | ||||
|    * ```cpp | ||||
|    * // Drive forward by spinning the motors 400 degrees | ||||
|    * chassis->moveRaw(400); | ||||
|    * ``` | ||||
|    * | ||||
|    * @param itarget distance to travel in motor degrees | ||||
|    */ | ||||
|   void moveRaw(double itarget) override; | ||||
|  | ||||
|   /** | ||||
|    * Sets the target distance for the robot to drive straight (using closed-loop control). | ||||
|    * | ||||
|    * @param itarget distance to travel | ||||
|    */ | ||||
|   void moveDistanceAsync(QLength itarget) override; | ||||
|  | ||||
|   /** | ||||
|    * Sets the target distance for the robot to drive straight (using closed-loop control). | ||||
|    * | ||||
|    * @param itarget distance to travel in motor degrees | ||||
|    */ | ||||
|   void moveRawAsync(double itarget) override; | ||||
|  | ||||
|   /** | ||||
|    * Turns the robot clockwise in place (using closed-loop control). | ||||
|    * | ||||
|    * ```cpp | ||||
|    * // Turn 90 degrees clockwise | ||||
|    * chassis->turnAngle(90_deg); | ||||
|    * ``` | ||||
|    * | ||||
|    * @param idegTarget angle to turn for | ||||
|    */ | ||||
|   void turnAngle(QAngle idegTarget) override; | ||||
|  | ||||
|   /** | ||||
|    * Turns the robot clockwise in place (using closed-loop control). | ||||
|    * | ||||
|    * ```cpp | ||||
|    * // Turn clockwise by spinning the motors 200 degrees | ||||
|    * chassis->turnRaw(200); | ||||
|    * ``` | ||||
|    * | ||||
|    * @param idegTarget angle to turn for in motor degrees | ||||
|    */ | ||||
|   void turnRaw(double idegTarget) override; | ||||
|  | ||||
|   /** | ||||
|    * Sets the target angle for the robot to turn clockwise in place (using closed-loop control). | ||||
|    * | ||||
|    * @param idegTarget angle to turn for | ||||
|    */ | ||||
|   void turnAngleAsync(QAngle idegTarget) override; | ||||
|  | ||||
|   /** | ||||
|    * Sets the target angle for the robot to turn clockwise in place (using closed-loop control). | ||||
|    * | ||||
|    * @param idegTarget angle to turn for in motor degrees | ||||
|    */ | ||||
|   void turnRawAsync(double idegTarget) override; | ||||
|  | ||||
|   /** | ||||
|    * Sets whether turns should be mirrored. | ||||
|    * | ||||
|    * @param ishouldMirror whether turns should be mirrored | ||||
|    */ | ||||
|   void setTurnsMirrored(bool ishouldMirror) override; | ||||
|  | ||||
|   /** | ||||
|    * Checks whether the internal controllers are currently settled. | ||||
|    * | ||||
|    * @return Whether this ChassisController is settled. | ||||
|    */ | ||||
|   bool isSettled() override; | ||||
|  | ||||
|   /** | ||||
|    * Delays until the currently executing movement completes. | ||||
|    */ | ||||
|   void waitUntilSettled() override; | ||||
|  | ||||
|   /** | ||||
|    * Interrupts the current movement to stop the robot. | ||||
|    */ | ||||
|   void stop() override; | ||||
|  | ||||
|   /** | ||||
|    * Get the ChassisScales. | ||||
|    */ | ||||
|   ChassisScales getChassisScales() const override; | ||||
|  | ||||
|   /** | ||||
|    * Get the GearsetRatioPair. | ||||
|    */ | ||||
|   AbstractMotor::GearsetRatioPair getGearsetRatioPair() const override; | ||||
|  | ||||
|   /** | ||||
|    * @return The internal ChassisModel. | ||||
|    */ | ||||
|   std::shared_ptr<ChassisModel> getModel() override; | ||||
|  | ||||
|   /** | ||||
|    * @return The internal ChassisModel. | ||||
|    */ | ||||
|   ChassisModel &model() override; | ||||
|  | ||||
|   /** | ||||
|    * Sets a new maximum velocity in RPM [0-600]. | ||||
|    * | ||||
|    * @param imaxVelocity The new maximum velocity. | ||||
|    */ | ||||
|   void setMaxVelocity(double imaxVelocity) override; | ||||
|  | ||||
|   /** | ||||
|    * @return The maximum velocity in RPM [0-600]. | ||||
|    */ | ||||
|   double getMaxVelocity() const override; | ||||
|  | ||||
|   protected: | ||||
|   std::shared_ptr<Logger> logger; | ||||
|   bool normalTurns{true}; | ||||
|   std::shared_ptr<ChassisModel> chassisModel; | ||||
|   TimeUtil timeUtil; | ||||
|   std::unique_ptr<AsyncPosIntegratedController> leftController; | ||||
|   std::unique_ptr<AsyncPosIntegratedController> rightController; | ||||
|   int lastTarget; | ||||
|   ChassisScales scales; | ||||
|   AbstractMotor::GearsetRatioPair gearsetRatioPair; | ||||
| }; | ||||
| } // namespace okapi | ||||
| @@ -0,0 +1,275 @@ | ||||
| /* | ||||
|  * This Source Code Form is subject to the terms of the Mozilla Public | ||||
|  * License, v. 2.0. If a copy of the MPL was not distributed with this | ||||
|  * file, You can obtain one at http://mozilla.org/MPL/2.0/. | ||||
|  */ | ||||
| #pragma once | ||||
|  | ||||
| #include "okapi/api/chassis/controller/chassisController.hpp" | ||||
| #include "okapi/api/control/iterative/iterativePosPidController.hpp" | ||||
| #include "okapi/api/util/abstractRate.hpp" | ||||
| #include "okapi/api/util/logging.hpp" | ||||
| #include "okapi/api/util/timeUtil.hpp" | ||||
| #include <atomic> | ||||
| #include <memory> | ||||
| #include <tuple> | ||||
|  | ||||
| namespace okapi { | ||||
| class ChassisControllerPID : public ChassisController { | ||||
|   public: | ||||
|   /** | ||||
|    * ChassisController using PID control. Puts the motors into encoder count units. Throws a | ||||
|    * `std::invalid_argument` exception if the gear ratio is zero. | ||||
|    * | ||||
|    * @param itimeUtil The TimeUtil. | ||||
|    * @param imodel The ChassisModel used to read from sensors/write to motors. | ||||
|    * @param idistanceController The PID controller that controls chassis distance for driving | ||||
|    * straight. | ||||
|    * @param iturnController The PID controller that controls chassis angle for turning. | ||||
|    * @param iangleController The PID controller that controls chassis angle for driving straight. | ||||
|    * @param igearset The internal gearset and external ratio used on the drive motors. | ||||
|    * @param iscales The ChassisScales. | ||||
|    * @param ilogger The logger this instance will log to. | ||||
|    */ | ||||
|   ChassisControllerPID( | ||||
|     TimeUtil itimeUtil, | ||||
|     std::shared_ptr<ChassisModel> imodel, | ||||
|     std::unique_ptr<IterativePosPIDController> idistanceController, | ||||
|     std::unique_ptr<IterativePosPIDController> iturnController, | ||||
|     std::unique_ptr<IterativePosPIDController> iangleController, | ||||
|     const AbstractMotor::GearsetRatioPair &igearset = AbstractMotor::gearset::green, | ||||
|     const ChassisScales &iscales = ChassisScales({1, 1}, imev5GreenTPR), | ||||
|     std::shared_ptr<Logger> ilogger = Logger::getDefaultLogger()); | ||||
|  | ||||
|   ChassisControllerPID(const ChassisControllerPID &) = delete; | ||||
|   ChassisControllerPID(ChassisControllerPID &&other) = delete; | ||||
|   ChassisControllerPID &operator=(const ChassisControllerPID &other) = delete; | ||||
|   ChassisControllerPID &operator=(ChassisControllerPID &&other) = delete; | ||||
|  | ||||
|   ~ChassisControllerPID() override; | ||||
|  | ||||
|   /** | ||||
|    * Drives the robot straight for a distance (using closed-loop control). | ||||
|    * | ||||
|    * ```cpp | ||||
|    * // Drive forward 6 inches | ||||
|    * chassis->moveDistance(6_in); | ||||
|    * | ||||
|    * // Drive backward 0.2 meters | ||||
|    * chassis->moveDistance(-0.2_m); | ||||
|    * ``` | ||||
|    * | ||||
|    * @param itarget distance to travel | ||||
|    */ | ||||
|   void moveDistance(QLength itarget) override; | ||||
|  | ||||
|   /** | ||||
|    * Drives the robot straight for a distance (using closed-loop control). | ||||
|    * | ||||
|    * ```cpp | ||||
|    * // Drive forward by spinning the motors 400 degrees | ||||
|    * chassis->moveRaw(400); | ||||
|    * ``` | ||||
|    * | ||||
|    * @param itarget distance to travel in motor degrees | ||||
|    */ | ||||
|   void moveRaw(double itarget) override; | ||||
|  | ||||
|   /** | ||||
|    * Sets the target distance for the robot to drive straight (using closed-loop control). | ||||
|    * | ||||
|    * @param itarget distance to travel | ||||
|    */ | ||||
|   void moveDistanceAsync(QLength itarget) override; | ||||
|  | ||||
|   /** | ||||
|    * Sets the target distance for the robot to drive straight (using closed-loop control). | ||||
|    * | ||||
|    * @param itarget distance to travel in motor degrees | ||||
|    */ | ||||
|   void moveRawAsync(double itarget) override; | ||||
|  | ||||
|   /** | ||||
|    * Turns the robot clockwise in place (using closed-loop control). | ||||
|    * | ||||
|    * ```cpp | ||||
|    * // Turn 90 degrees clockwise | ||||
|    * chassis->turnAngle(90_deg); | ||||
|    * ``` | ||||
|    * | ||||
|    * @param idegTarget angle to turn for | ||||
|    */ | ||||
|   void turnAngle(QAngle idegTarget) override; | ||||
|  | ||||
|   /** | ||||
|    * Turns the robot clockwise in place (using closed-loop control). | ||||
|    * | ||||
|    * ```cpp | ||||
|    * // Turn clockwise by spinning the motors 200 degrees | ||||
|    * chassis->turnRaw(200); | ||||
|    * ``` | ||||
|    * | ||||
|    * @param idegTarget angle to turn for in motor degrees | ||||
|    */ | ||||
|   void turnRaw(double idegTarget) override; | ||||
|  | ||||
|   /** | ||||
|    * Sets the target angle for the robot to turn clockwise in place (using closed-loop control). | ||||
|    * | ||||
|    * @param idegTarget angle to turn for | ||||
|    */ | ||||
|   void turnAngleAsync(QAngle idegTarget) override; | ||||
|  | ||||
|   /** | ||||
|    * Sets the target angle for the robot to turn clockwise in place (using closed-loop control). | ||||
|    * | ||||
|    * @param idegTarget angle to turn for in motor degrees | ||||
|    */ | ||||
|   void turnRawAsync(double idegTarget) override; | ||||
|  | ||||
|   /** | ||||
|    * Sets whether turns should be mirrored. | ||||
|    * | ||||
|    * @param ishouldMirror whether turns should be mirrored | ||||
|    */ | ||||
|   void setTurnsMirrored(bool ishouldMirror) override; | ||||
|  | ||||
|   /** | ||||
|    * Checks whether the internal controllers are currently settled. | ||||
|    * | ||||
|    * @return Whether this ChassisController is settled. | ||||
|    */ | ||||
|   bool isSettled() override; | ||||
|  | ||||
|   /** | ||||
|    * Delays until the currently executing movement completes. | ||||
|    */ | ||||
|   void waitUntilSettled() override; | ||||
|  | ||||
|   /** | ||||
|    * Gets the ChassisScales. | ||||
|    */ | ||||
|   ChassisScales getChassisScales() const override; | ||||
|  | ||||
|   /** | ||||
|    * Gets the GearsetRatioPair. | ||||
|    */ | ||||
|   AbstractMotor::GearsetRatioPair getGearsetRatioPair() const override; | ||||
|  | ||||
|   /** | ||||
|    * Sets the velocity mode flag. When the controller is in velocity mode, the control loop will | ||||
|    * set motor velocities. When the controller is in voltage mode (`ivelocityMode = false`), the | ||||
|    * control loop will set motor voltages. Additionally, when the controller is in voltage mode, | ||||
|    * it will not obey maximum velocity limits. | ||||
|    * | ||||
|    * @param ivelocityMode Whether the controller should be in velocity or voltage mode. | ||||
|    */ | ||||
|   void setVelocityMode(bool ivelocityMode); | ||||
|  | ||||
|   /** | ||||
|    * Sets the gains for all controllers. | ||||
|    * | ||||
|    * @param idistanceGains The distance controller gains. | ||||
|    * @param iturnGains The turn controller gains. | ||||
|    * @param iangleGains The angle controller gains. | ||||
|    */ | ||||
|   void setGains(const IterativePosPIDController::Gains &idistanceGains, | ||||
|                 const IterativePosPIDController::Gains &iturnGains, | ||||
|                 const IterativePosPIDController::Gains &iangleGains); | ||||
|  | ||||
|   /** | ||||
|    * Gets the current controller gains. | ||||
|    * | ||||
|    * @return The current controller gains in the order: distance, turn, angle. | ||||
|    */ | ||||
|   std::tuple<IterativePosPIDController::Gains, | ||||
|              IterativePosPIDController::Gains, | ||||
|              IterativePosPIDController::Gains> | ||||
|   getGains() const; | ||||
|  | ||||
|   /** | ||||
|    * Starts the internal thread. This method is called by the ChassisControllerBuilder when making a | ||||
|    * new instance of this class. | ||||
|    */ | ||||
|   void startThread(); | ||||
|  | ||||
|   /** | ||||
|    * Returns the underlying thread handle. | ||||
|    * | ||||
|    * @return The underlying thread handle. | ||||
|    */ | ||||
|   CrossplatformThread *getThread() const; | ||||
|  | ||||
|   /** | ||||
|    * Interrupts the current movement to stop the robot. | ||||
|    */ | ||||
|   void stop() override; | ||||
|  | ||||
|   /** | ||||
|    * Sets a new maximum velocity in RPM [0-600]. In voltage mode, the max velocity is ignored and a | ||||
|    * max voltage should be set on the underlying ChassisModel instead. | ||||
|    * | ||||
|    * @param imaxVelocity The new maximum velocity. | ||||
|    */ | ||||
|   void setMaxVelocity(double imaxVelocity) override; | ||||
|  | ||||
|   /** | ||||
|    * @return The maximum velocity in RPM [0-600]. | ||||
|    */ | ||||
|   double getMaxVelocity() const override; | ||||
|  | ||||
|   /** | ||||
|    * @return The internal ChassisModel. | ||||
|    */ | ||||
|   std::shared_ptr<ChassisModel> getModel() override; | ||||
|  | ||||
|   /** | ||||
|    * @return The internal ChassisModel. | ||||
|    */ | ||||
|   ChassisModel &model() override; | ||||
|  | ||||
|   protected: | ||||
|   std::shared_ptr<Logger> logger; | ||||
|   bool normalTurns{true}; | ||||
|   std::shared_ptr<ChassisModel> chassisModel; | ||||
|   TimeUtil timeUtil; | ||||
|   std::unique_ptr<IterativePosPIDController> distancePid; | ||||
|   std::unique_ptr<IterativePosPIDController> turnPid; | ||||
|   std::unique_ptr<IterativePosPIDController> anglePid; | ||||
|   ChassisScales scales; | ||||
|   AbstractMotor::GearsetRatioPair gearsetRatioPair; | ||||
|   bool velocityMode{true}; | ||||
|   std::atomic_bool doneLooping{true}; | ||||
|   std::atomic_bool doneLoopingSeen{true}; | ||||
|   std::atomic_bool newMovement{false}; | ||||
|   std::atomic_bool dtorCalled{false}; | ||||
|   QTime threadSleepTime{10_ms}; | ||||
|  | ||||
|   static void trampoline(void *context); | ||||
|   void loop(); | ||||
|  | ||||
|   /** | ||||
|    * Wait for the distance setup (distancePid and anglePid) to settle. | ||||
|    * | ||||
|    * @return true if done settling; false if settling should be tried again | ||||
|    */ | ||||
|   bool waitForDistanceSettled(); | ||||
|  | ||||
|   /** | ||||
|    * Wait for the angle setup (anglePid) to settle. | ||||
|    * | ||||
|    * @return true if done settling; false if settling should be tried again | ||||
|    */ | ||||
|   bool waitForAngleSettled(); | ||||
|  | ||||
|   /** | ||||
|    * Stops all the controllers and the ChassisModel. | ||||
|    */ | ||||
|   void stopAfterSettled(); | ||||
|  | ||||
|   typedef enum { distance, angle, none } modeType; | ||||
|   modeType mode{none}; | ||||
|  | ||||
|   CrossplatformThread *task{nullptr}; | ||||
| }; | ||||
| } // namespace okapi | ||||
| @@ -0,0 +1,88 @@ | ||||
| /* | ||||
|  * This Source Code Form is subject to the terms of the Mozilla Public | ||||
|  * License, v. 2.0. If a copy of the MPL was not distributed with this | ||||
|  * file, You can obtain one at http://mozilla.org/MPL/2.0/. | ||||
|  */ | ||||
| #pragma once | ||||
|  | ||||
| #include "okapi/api/units/QAngle.hpp" | ||||
| #include "okapi/api/units/QLength.hpp" | ||||
| #include "okapi/api/units/RQuantity.hpp" | ||||
| #include "okapi/api/util/logging.hpp" | ||||
| #include <initializer_list> | ||||
| #include <stdexcept> | ||||
| #include <vector> | ||||
|  | ||||
| namespace okapi { | ||||
| class ChassisScales { | ||||
|   public: | ||||
|   /** | ||||
|    * The scales a ChassisController needs to do all of its closed-loop control. The first element is | ||||
|    * the wheel diameter, the second element is the wheel track. For three-encoder configurations, | ||||
|    * the length from the center of rotation to the middle wheel and the middle wheel diameter are | ||||
|    * passed as the third and fourth elements. | ||||
|    * | ||||
|    * The wheel track is the center-to-center distance between the wheels (center-to-center | ||||
|    * meaning the width between the centers of both wheels). For example, if you are using four inch | ||||
|    * omni wheels and there are 11.5 inches between the centers of each wheel, you would call the | ||||
|    * constructor like so: | ||||
|    *   `ChassisScales scales({4_in, 11.5_in}, imev5GreenTPR); // imev5GreenTPR for a green gearset` | ||||
|    * | ||||
|    *                             Wheel diameter | ||||
|    * | ||||
|    *                              +-+      Center of rotation | ||||
|    *                              | |      | | ||||
|    *                              v v      +----------+ Length to middle wheel | ||||
|    *                                       |          | from center of rotation | ||||
|    *                     +--->    ===      |      === | | ||||
|    *                     |         +       v       +  | | ||||
|    *                     |        ++---------------++ | | ||||
|    *                     |        |                 | v | ||||
|    *       Wheel track   |        |                 | | ||||
|    *                     |        |        x        |+|  <-- Middle wheel | ||||
|    *                     |        |                 | | ||||
|    *                     |        |                 | | ||||
|    *                     |        ++---------------++ | ||||
|    *                     |         +               + | ||||
|    *                     +--->    ===             === | ||||
|    * | ||||
|    * | ||||
|    * @param idimensions {wheel diameter, wheel track} or {wheel diameter, wheel track, length to | ||||
|    * middle wheel, middle wheel diameter}. | ||||
|    * @param itpr The ticks per revolution of the encoders. | ||||
|    * @param ilogger The logger this instance will log to. | ||||
|    */ | ||||
|   ChassisScales(const std::initializer_list<QLength> &idimensions, | ||||
|                 double itpr, | ||||
|                 const std::shared_ptr<Logger> &ilogger = Logger::getDefaultLogger()); | ||||
|  | ||||
|   /** | ||||
|    * The scales a ChassisController needs to do all of its closed-loop control. The first element is | ||||
|    * the straight scale, the second element is the turn scale. Optionally, the length from the | ||||
|    * center of rotation to the middle wheel and the middle scale can be passed as the third and | ||||
|    * fourth elements. The straight scale converts motor degrees to meters, the turn scale converts | ||||
|    * motor degrees to robot turn degrees, and the middle scale converts middle wheel degrees to | ||||
|    * meters. | ||||
|    * | ||||
|    * @param iscales {straight scale, turn scale} or {straight scale, turn scale, length to middle | ||||
|    * wheel in meters, middle scale}. | ||||
|    * @param itpr The ticks per revolution of the encoders. | ||||
|    * @param ilogger The logger this instance will log to. | ||||
|    */ | ||||
|   ChassisScales(const std::initializer_list<double> &iscales, | ||||
|                 double itpr, | ||||
|                 const std::shared_ptr<Logger> &ilogger = Logger::getDefaultLogger()); | ||||
|  | ||||
|   QLength wheelDiameter; | ||||
|   QLength wheelTrack; | ||||
|   QLength middleWheelDistance; | ||||
|   QLength middleWheelDiameter; | ||||
|   double straight; | ||||
|   double turn; | ||||
|   double middle; | ||||
|   double tpr; | ||||
|  | ||||
|   protected: | ||||
|   static void validateInputSize(std::size_t inputSize, const std::shared_ptr<Logger> &logger); | ||||
| }; | ||||
| } // namespace okapi | ||||
| @@ -0,0 +1,183 @@ | ||||
| /* | ||||
|  * This Source Code Form is subject to the terms of the Mozilla Public | ||||
|  * License, v. 2.0. If a copy of the MPL was not distributed with this | ||||
|  * file, You can obtain one at http://mozilla.org/MPL/2.0/. | ||||
|  */ | ||||
| #pragma once | ||||
|  | ||||
| #include "okapi/api/chassis/controller/chassisControllerIntegrated.hpp" | ||||
| #include "okapi/api/chassis/controller/odomChassisController.hpp" | ||||
| #include "okapi/api/chassis/model/skidSteerModel.hpp" | ||||
| #include "okapi/api/odometry/odometry.hpp" | ||||
| #include <memory> | ||||
|  | ||||
| namespace okapi { | ||||
| class DefaultOdomChassisController : public OdomChassisController { | ||||
|   public: | ||||
|   /** | ||||
|    * Odometry based chassis controller that moves using a separately constructed chassis controller. | ||||
|    * Spins up a task at the default priority plus 1 for odometry when constructed. | ||||
|    * | ||||
|    * Moves the robot around in the odom frame. Instead of telling the robot to drive forward or | ||||
|    * turn some amount, you instead tell it to drive to a specific point on the field or turn to | ||||
|    * a specific angle, relative to its starting position. | ||||
|    * | ||||
|    * @param itimeUtil The TimeUtil. | ||||
|    * @param iodometry The odometry to read state estimates from. | ||||
|    * @param icontroller The chassis controller to delegate to. | ||||
|    * @param imode The new default StateMode used to interpret target points and query the Odometry | ||||
|    * state. | ||||
|    * @param imoveThreshold minimum length movement (smaller movements will be skipped) | ||||
|    * @param iturnThreshold minimum angle turn (smaller turns will be skipped) | ||||
|    * @param ilogger The logger this instance will log to. | ||||
|    */ | ||||
|   DefaultOdomChassisController(const TimeUtil &itimeUtil, | ||||
|                                std::shared_ptr<Odometry> iodometry, | ||||
|                                std::shared_ptr<ChassisController> icontroller, | ||||
|                                const StateMode &imode = StateMode::FRAME_TRANSFORMATION, | ||||
|                                QLength imoveThreshold = 0_mm, | ||||
|                                QAngle iturnThreshold = 0_deg, | ||||
|                                std::shared_ptr<Logger> ilogger = Logger::getDefaultLogger()); | ||||
|  | ||||
|   DefaultOdomChassisController(const DefaultOdomChassisController &) = delete; | ||||
|   DefaultOdomChassisController(DefaultOdomChassisController &&other) = delete; | ||||
|   DefaultOdomChassisController &operator=(const DefaultOdomChassisController &other) = delete; | ||||
|   DefaultOdomChassisController &operator=(DefaultOdomChassisController &&other) = delete; | ||||
|  | ||||
|   /** | ||||
|    * Drives the robot straight to a point in the odom frame. | ||||
|    * | ||||
|    * @param ipoint The target point to navigate to. | ||||
|    * @param ibackwards Whether to drive to the target point backwards. | ||||
|    * @param ioffset An offset from the target point in the direction pointing towards the robot. The | ||||
|    * robot will stop this far away from the target point. | ||||
|    */ | ||||
|   void driveToPoint(const Point &ipoint, | ||||
|                     bool ibackwards = false, | ||||
|                     const QLength &ioffset = 0_mm) override; | ||||
|  | ||||
|   /** | ||||
|    * Turns the robot to face a point in the odom frame. | ||||
|    * | ||||
|    * @param ipoint The target point to turn to face. | ||||
|    */ | ||||
|   void turnToPoint(const Point &ipoint) override; | ||||
|  | ||||
|   /** | ||||
|    * @return The internal ChassisController. | ||||
|    */ | ||||
|   std::shared_ptr<ChassisController> getChassisController(); | ||||
|  | ||||
|   /** | ||||
|    * @return The internal ChassisController. | ||||
|    */ | ||||
|   ChassisController &chassisController(); | ||||
|  | ||||
|   /** | ||||
|    * This delegates to the input ChassisController. | ||||
|    */ | ||||
|   void turnToAngle(const QAngle &iangle) override; | ||||
|  | ||||
|   /** | ||||
|    * This delegates to the input ChassisController. | ||||
|    */ | ||||
|   void moveDistance(QLength itarget) override; | ||||
|  | ||||
|   /** | ||||
|    * This delegates to the input ChassisController. | ||||
|    */ | ||||
|   void moveRaw(double itarget) override; | ||||
|  | ||||
|   /** | ||||
|    * This delegates to the input ChassisController. | ||||
|    */ | ||||
|   void moveDistanceAsync(QLength itarget) override; | ||||
|  | ||||
|   /** | ||||
|    * This delegates to the input ChassisController. | ||||
|    */ | ||||
|   void moveRawAsync(double itarget) override; | ||||
|  | ||||
|   /** | ||||
|    * Turns chassis to desired angle (turns in the direction of smallest angle) | ||||
|    * (ex. If current angle is 0 and target is 270, the chassis will turn -90 degrees) | ||||
|    *  | ||||
|    * @param idegTarget target angle | ||||
|    */ | ||||
|   void turnAngle(QAngle idegTarget) override; | ||||
|  | ||||
|   /** | ||||
|    * This delegates to the input ChassisController. | ||||
|    */ | ||||
|   void turnRaw(double idegTarget) override; | ||||
|  | ||||
|   /** | ||||
|    * Turns chassis to desired angle (turns in the direction of smallest angle) | ||||
|    * (ex. If current angle is 0 and target is 270, the chassis will turn -90 degrees) | ||||
|    *  | ||||
|    * @param idegTarget target angle  | ||||
|    */ | ||||
|   void turnAngleAsync(QAngle idegTarget) override; | ||||
|  | ||||
|   /** | ||||
|    * This delegates to the input ChassisController. | ||||
|    */ | ||||
|   void turnRawAsync(double idegTarget) override; | ||||
|  | ||||
|   /** | ||||
|    * This delegates to the input ChassisController. | ||||
|    */ | ||||
|   void setTurnsMirrored(bool ishouldMirror) override; | ||||
|  | ||||
|   /** | ||||
|    * This delegates to the input ChassisController. | ||||
|    */ | ||||
|   bool isSettled() override; | ||||
|  | ||||
|   /** | ||||
|    * This delegates to the input ChassisController. | ||||
|    */ | ||||
|   void waitUntilSettled() override; | ||||
|  | ||||
|   /** | ||||
|    * This delegates to the input ChassisController. | ||||
|    */ | ||||
|   void stop() override; | ||||
|  | ||||
|   /** | ||||
|    * This delegates to the input ChassisController. | ||||
|    */ | ||||
|   void setMaxVelocity(double imaxVelocity) override; | ||||
|  | ||||
|   /** | ||||
|    * This delegates to the input ChassisController. | ||||
|    */ | ||||
|   double getMaxVelocity() const override; | ||||
|  | ||||
|   /** | ||||
|    * This delegates to the input ChassisController. | ||||
|    */ | ||||
|   ChassisScales getChassisScales() const override; | ||||
|  | ||||
|   /** | ||||
|    * This delegates to the input ChassisController. | ||||
|    */ | ||||
|   AbstractMotor::GearsetRatioPair getGearsetRatioPair() const override; | ||||
|  | ||||
|   /** | ||||
|    * This delegates to the input ChassisController. | ||||
|    */ | ||||
|   std::shared_ptr<ChassisModel> getModel() override; | ||||
|  | ||||
|   /** | ||||
|    * This delegates to the input ChassisController. | ||||
|    */ | ||||
|   ChassisModel &model() override; | ||||
|  | ||||
|   protected: | ||||
|   std::shared_ptr<Logger> logger; | ||||
|   std::shared_ptr<ChassisController> controller; | ||||
|  | ||||
|   void waitForOdomTask(); | ||||
| }; | ||||
| } // namespace okapi | ||||
| @@ -0,0 +1,154 @@ | ||||
| /* | ||||
|  * This Source Code Form is subject to the terms of the Mozilla Public | ||||
|  * License, v. 2.0. If a copy of the MPL was not distributed with this | ||||
|  * file, You can obtain one at http://mozilla.org/MPL/2.0/. | ||||
|  */ | ||||
| #pragma once | ||||
|  | ||||
| #include "okapi/api/chassis/controller/chassisController.hpp" | ||||
| #include "okapi/api/chassis/model/skidSteerModel.hpp" | ||||
| #include "okapi/api/coreProsAPI.hpp" | ||||
| #include "okapi/api/odometry/odometry.hpp" | ||||
| #include "okapi/api/odometry/point.hpp" | ||||
| #include "okapi/api/units/QSpeed.hpp" | ||||
| #include "okapi/api/util/abstractRate.hpp" | ||||
| #include "okapi/api/util/logging.hpp" | ||||
| #include "okapi/api/util/timeUtil.hpp" | ||||
| #include <atomic> | ||||
| #include <memory> | ||||
| #include <valarray> | ||||
|  | ||||
| namespace okapi { | ||||
| class OdomChassisController : public ChassisController { | ||||
|   public: | ||||
|   /** | ||||
|    * Odometry based chassis controller. Starts task at the default for odometry when constructed, | ||||
|    * which calls `Odometry::step` every `10ms`. The default StateMode is | ||||
|    * `StateMode::FRAME_TRANSFORMATION`. | ||||
|    * | ||||
|    * Moves the robot around in the odom frame. Instead of telling the robot to drive forward or | ||||
|    * turn some amount, you instead tell it to drive to a specific point on the field or turn to | ||||
|    * a specific angle relative to its starting position. | ||||
|    * | ||||
|    * @param itimeUtil The TimeUtil. | ||||
|    * @param iodometry The Odometry instance to run in a new task. | ||||
|    * @param imode The new default StateMode used to interpret target points and query the Odometry | ||||
|    * state. | ||||
|    * @param imoveThreshold minimum length movement (smaller movements will be skipped) | ||||
|    * @param iturnThreshold minimum angle turn (smaller turns will be skipped) | ||||
|    */ | ||||
|   OdomChassisController(TimeUtil itimeUtil, | ||||
|                         std::shared_ptr<Odometry> iodometry, | ||||
|                         const StateMode &imode = StateMode::FRAME_TRANSFORMATION, | ||||
|                         const QLength &imoveThreshold = 0_mm, | ||||
|                         const QAngle &iturnThreshold = 0_deg, | ||||
|                         std::shared_ptr<Logger> ilogger = Logger::getDefaultLogger()); | ||||
|  | ||||
|   ~OdomChassisController() override; | ||||
|  | ||||
|   OdomChassisController(const OdomChassisController &) = delete; | ||||
|   OdomChassisController(OdomChassisController &&other) = delete; | ||||
|   OdomChassisController &operator=(const OdomChassisController &other) = delete; | ||||
|   OdomChassisController &operator=(OdomChassisController &&other) = delete; | ||||
|  | ||||
|   /** | ||||
|    * Drives the robot straight to a point in the odom frame. | ||||
|    * | ||||
|    * @param ipoint The target point to navigate to. | ||||
|    * @param ibackwards Whether to drive to the target point backwards. | ||||
|    * @param ioffset An offset from the target point in the direction pointing towards the robot. The | ||||
|    * robot will stop this far away from the target point. | ||||
|    */ | ||||
|   virtual void | ||||
|   driveToPoint(const Point &ipoint, bool ibackwards = false, const QLength &ioffset = 0_mm) = 0; | ||||
|  | ||||
|   /** | ||||
|    * Turns the robot to face a point in the odom frame. | ||||
|    * | ||||
|    * @param ipoint The target point to turn to face. | ||||
|    */ | ||||
|   virtual void turnToPoint(const Point &ipoint) = 0; | ||||
|  | ||||
|   /** | ||||
|    * Turns the robot to face an angle in the odom frame. | ||||
|    * | ||||
|    * @param iangle The angle to turn to. | ||||
|    */ | ||||
|   virtual void turnToAngle(const QAngle &iangle) = 0; | ||||
|  | ||||
|   /** | ||||
|    * @return The current state. | ||||
|    */ | ||||
|   virtual OdomState getState() const; | ||||
|  | ||||
|   /** | ||||
|    * Set a new state to be the current state. The default StateMode is | ||||
|    * `StateMode::FRAME_TRANSFORMATION`. | ||||
|    * | ||||
|    * @param istate The new state in the given format. | ||||
|    * @param imode The mode to treat the input state as. | ||||
|    */ | ||||
|   virtual void setState(const OdomState &istate); | ||||
|  | ||||
|   /** | ||||
|    * Sets a default StateMode that will be used to interpret target points and query the Odometry | ||||
|    * state. | ||||
|    * | ||||
|    * @param imode The new default StateMode. | ||||
|    */ | ||||
|   void setDefaultStateMode(const StateMode &imode); | ||||
|  | ||||
|   /** | ||||
|    * Set a new move threshold. Any requested movements smaller than this threshold will be skipped. | ||||
|    * | ||||
|    * @param imoveThreshold new move threshold | ||||
|    */ | ||||
|   virtual void setMoveThreshold(const QLength &imoveThreshold); | ||||
|  | ||||
|   /** | ||||
|    * Set a new turn threshold. Any requested turns smaller than this threshold will be skipped. | ||||
|    * | ||||
|    * @param iturnTreshold new turn threshold | ||||
|    */ | ||||
|   virtual void setTurnThreshold(const QAngle &iturnTreshold); | ||||
|  | ||||
|   /** | ||||
|    * @return The current move threshold. | ||||
|    */ | ||||
|   virtual QLength getMoveThreshold() const; | ||||
|  | ||||
|   /** | ||||
|    * @return The current turn threshold. | ||||
|    */ | ||||
|   virtual QAngle getTurnThreshold() const; | ||||
|  | ||||
|   /** | ||||
|    * Starts the internal odometry thread. This should not be called by normal users. | ||||
|    */ | ||||
|   void startOdomThread(); | ||||
|  | ||||
|   /** | ||||
|    * @return The underlying thread handle. | ||||
|    */ | ||||
|   CrossplatformThread *getOdomThread() const; | ||||
|  | ||||
|   /** | ||||
|    * @return The internal odometry. | ||||
|    */ | ||||
|   std::shared_ptr<Odometry> getOdometry(); | ||||
|  | ||||
|   protected: | ||||
|   std::shared_ptr<Logger> logger; | ||||
|   TimeUtil timeUtil; | ||||
|   QLength moveThreshold; | ||||
|   QAngle turnThreshold; | ||||
|   std::shared_ptr<Odometry> odom; | ||||
|   CrossplatformThread *odomTask{nullptr}; | ||||
|   std::atomic_bool dtorCalled{false}; | ||||
|   StateMode defaultStateMode{StateMode::FRAME_TRANSFORMATION}; | ||||
|   std::atomic_bool odomTaskRunning{false}; | ||||
|  | ||||
|   static void trampoline(void *context); | ||||
|   void loop(); | ||||
| }; | ||||
| } // namespace okapi | ||||
							
								
								
									
										165
									
								
								SerialTest/include/okapi/api/chassis/model/chassisModel.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										165
									
								
								SerialTest/include/okapi/api/chassis/model/chassisModel.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,165 @@ | ||||
| /* | ||||
|  * This Source Code Form is subject to the terms of the Mozilla Public | ||||
|  * License, v. 2.0. If a copy of the MPL was not distributed with this | ||||
|  * file, You can obtain one at http://mozilla.org/MPL/2.0/. | ||||
|  */ | ||||
| #pragma once | ||||
|  | ||||
| #include "okapi/api/chassis/model/readOnlyChassisModel.hpp" | ||||
| #include "okapi/api/device/motor/abstractMotor.hpp" | ||||
| #include <array> | ||||
| #include <initializer_list> | ||||
| #include <memory> | ||||
| #include <vector> | ||||
|  | ||||
| namespace okapi { | ||||
| /** | ||||
|  * A version of the ReadOnlyChassisModel that also supports write methods, such as setting motor | ||||
|  * speed. Because this class can write to motors, there can only be one owner and as such copying | ||||
|  * is disabled. | ||||
|  */ | ||||
| class ChassisModel : public ReadOnlyChassisModel { | ||||
|   public: | ||||
|   explicit ChassisModel() = default; | ||||
|   ChassisModel(const ChassisModel &) = delete; | ||||
|   ChassisModel &operator=(const ChassisModel &) = delete; | ||||
|  | ||||
|   /** | ||||
|    * Drive the robot forwards (using open-loop control). Uses velocity mode. | ||||
|    * | ||||
|    * @param ipower motor power | ||||
|    */ | ||||
|   virtual void forward(double ispeed) = 0; | ||||
|  | ||||
|   /** | ||||
|    * Drive the robot in an arc (using open-loop control). Uses velocity mode. | ||||
|    * The algorithm is (approximately): | ||||
|    *   leftPower = forwardSpeed + yaw | ||||
|    *   rightPower = forwardSpeed - yaw | ||||
|    * | ||||
|    * @param iforwadSpeed speed in the forward direction | ||||
|    * @param iyaw speed around the vertical axis | ||||
|    */ | ||||
|   virtual void driveVector(double iforwardSpeed, double iyaw) = 0; | ||||
|  | ||||
|   /** | ||||
|    * Drive the robot in an arc. Uses voltage mode. | ||||
|    * The algorithm is (approximately): | ||||
|    *   leftPower = forwardSpeed + yaw | ||||
|    *   rightPower = forwardSpeed - yaw | ||||
|    * | ||||
|    * @param iforwadSpeed speed in the forward direction | ||||
|    * @param iyaw speed around the vertical axis | ||||
|    */ | ||||
|   virtual void driveVectorVoltage(double iforwardSpeed, double iyaw) = 0; | ||||
|  | ||||
|   /** | ||||
|    * Turn the robot clockwise (using open-loop control). Uses velocity mode. | ||||
|    * | ||||
|    * @param ispeed motor power | ||||
|    */ | ||||
|   virtual void rotate(double ispeed) = 0; | ||||
|  | ||||
|   /** | ||||
|    * Stop the robot (set all the motors to 0). Uses velocity mode. | ||||
|    */ | ||||
|   virtual void stop() = 0; | ||||
|  | ||||
|   /** | ||||
|    * Drive the robot with a tank drive layout. Uses voltage mode. | ||||
|    * | ||||
|    * @param ileftSpeed left side speed | ||||
|    * @param irightSpeed right side speed | ||||
|    * @param ithreshold deadband on joystick values | ||||
|    */ | ||||
|   virtual void tank(double ileftSpeed, double irightSpeed, double ithreshold = 0) = 0; | ||||
|  | ||||
|   /** | ||||
|    * Drive the robot with an arcade drive layout. Uses voltage mode. | ||||
|    * | ||||
|    * @param iforwardSpeed speed forward direction | ||||
|    * @param iyaw speed around the vertical axis | ||||
|    * @param ithreshold deadband on joystick values | ||||
|    */ | ||||
|   virtual void arcade(double iforwardSpeed, double iyaw, double ithreshold = 0) = 0; | ||||
|  | ||||
|   /** | ||||
|    * Drive the robot with a curvature drive layout. The robot drives in constant radius turns | ||||
|    * where you control the curvature (inverse of radius) you drive in. This is advantageous | ||||
|    * because the forward speed will not affect the rate of turning. The algorithm switches to | ||||
|    * arcade if the forward speed is 0. Uses voltage mode. | ||||
|    * | ||||
|    * @param iforwardSpeed speed in the forward direction | ||||
|    * @param icurvature curvature (inverse of radius) to drive in | ||||
|    * @param ithreshold deadband on joystick values | ||||
|    */ | ||||
|   virtual void curvature(double iforwardSpeed, double icurvature, double ithreshold = 0) = 0; | ||||
|  | ||||
|   /** | ||||
|    * Power the left side motors. Uses velocity mode. | ||||
|    * | ||||
|    * @param ipower motor power | ||||
|    */ | ||||
|   virtual void left(double ispeed) = 0; | ||||
|  | ||||
|   /** | ||||
|    * Power the right side motors. Uses velocity mode. | ||||
|    * | ||||
|    * @param ipower motor power | ||||
|    */ | ||||
|   virtual void right(double ispeed) = 0; | ||||
|  | ||||
|   /** | ||||
|    * Reset the sensors to their zero point. | ||||
|    */ | ||||
|   virtual void resetSensors() = 0; | ||||
|  | ||||
|   /** | ||||
|    * Set the brake mode for each motor. | ||||
|    * | ||||
|    * @param mode new brake mode | ||||
|    */ | ||||
|   virtual void setBrakeMode(AbstractMotor::brakeMode mode) = 0; | ||||
|  | ||||
|   /** | ||||
|    * Set the encoder units for each motor. | ||||
|    * | ||||
|    * @param units new motor encoder units | ||||
|    */ | ||||
|   virtual void setEncoderUnits(AbstractMotor::encoderUnits units) = 0; | ||||
|  | ||||
|   /** | ||||
|    * Set the gearset for each motor. | ||||
|    * | ||||
|    * @param gearset new motor gearset | ||||
|    */ | ||||
|   virtual void setGearing(AbstractMotor::gearset gearset) = 0; | ||||
|  | ||||
|   /** | ||||
|    * Sets a new maximum velocity in RPM. The usable maximum depends on the maximum velocity of the | ||||
|    * currently installed gearset. If the configured maximum velocity is greater than the attainable | ||||
|    * maximum velocity from the currently installed gearset, the ChassisModel will still scale to | ||||
|    * that velocity. | ||||
|    * | ||||
|    * @param imaxVelocity The new maximum velocity. | ||||
|    */ | ||||
|   virtual void setMaxVelocity(double imaxVelocity) = 0; | ||||
|  | ||||
|   /** | ||||
|    * @return The current maximum velocity. | ||||
|    */ | ||||
|   virtual double getMaxVelocity() const = 0; | ||||
|  | ||||
|   /** | ||||
|    * Sets a new maximum voltage in mV in the range `[0-12000]`. | ||||
|    * | ||||
|    * @param imaxVoltage The new maximum voltage. | ||||
|    */ | ||||
|   virtual void setMaxVoltage(double imaxVoltage) = 0; | ||||
|  | ||||
|   /** | ||||
|    * @return The maximum voltage in mV `[0-12000]`. | ||||
|    */ | ||||
|   virtual double getMaxVoltage() const = 0; | ||||
| }; | ||||
| } // namespace okapi | ||||
							
								
								
									
										247
									
								
								SerialTest/include/okapi/api/chassis/model/hDriveModel.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										247
									
								
								SerialTest/include/okapi/api/chassis/model/hDriveModel.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,247 @@ | ||||
| /* | ||||
|  * This Source Code Form is subject to the terms of the Mozilla Public | ||||
|  * License, v. 2.0. If a copy of the MPL was not distributed with this | ||||
|  * file, You can obtain one at http://mozilla.org/MPL/2.0/. | ||||
|  */ | ||||
| #pragma once | ||||
|  | ||||
| #include "okapi/api/chassis/model/chassisModel.hpp" | ||||
| #include "okapi/api/device/motor/abstractMotor.hpp" | ||||
| #include "okapi/api/device/rotarysensor/continuousRotarySensor.hpp" | ||||
|  | ||||
| namespace okapi { | ||||
| class HDriveModel : public ChassisModel { | ||||
|   public: | ||||
|   /** | ||||
|    * Model for an h-drive (wheels parallel with robot's direction of motion, with an additional | ||||
|    * wheel perpendicular to those). When the left and right side motors are powered +100%, the robot | ||||
|    * should move forward in a straight line. When the middle motor is powered +100%, the robot | ||||
|    * should strafe right in a straight line. | ||||
|    * | ||||
|    * @param ileftSideMotor The left side motor. | ||||
|    * @param irightSideMotor The right side motor. | ||||
|    * @param imiddleMotor The middle (perpendicular) motor. | ||||
|    * @param ileftEnc The left side encoder. | ||||
|    * @param irightEnc The right side encoder. | ||||
|    * @param imiddleEnc The middle encoder. | ||||
|    */ | ||||
|   HDriveModel(std::shared_ptr<AbstractMotor> ileftSideMotor, | ||||
|               std::shared_ptr<AbstractMotor> irightSideMotor, | ||||
|               std::shared_ptr<AbstractMotor> imiddleMotor, | ||||
|               std::shared_ptr<ContinuousRotarySensor> ileftEnc, | ||||
|               std::shared_ptr<ContinuousRotarySensor> irightEnc, | ||||
|               std::shared_ptr<ContinuousRotarySensor> imiddleEnc, | ||||
|               double imaxVelocity, | ||||
|               double imaxVoltage); | ||||
|  | ||||
|   /** | ||||
|    * Drive the robot forwards (using open-loop control). Uses velocity mode. Sets the middle motor | ||||
|    * to zero velocity. | ||||
|    * | ||||
|    * @param ispeed motor power | ||||
|    */ | ||||
|   void forward(double ispeed) override; | ||||
|  | ||||
|   /** | ||||
|    * Drive the robot in an arc (using open-loop control). Uses velocity mode. Sets the middle motor | ||||
|    * to zero velocity. | ||||
|    * | ||||
|    * The algorithm is (approximately): | ||||
|    *    leftPower = ySpeed + zRotation | ||||
|    *    rightPower = ySpeed - zRotation | ||||
|    * | ||||
|    * @param iySpeed speed on y axis (forward) | ||||
|    * @param izRotation speed around z axis (up) | ||||
|    */ | ||||
|   void driveVector(double iySpeed, double izRotation) override; | ||||
|  | ||||
|   /** | ||||
|    * Drive the robot in an arc. Uses voltage mode. Sets the middle motor to zero velocity. | ||||
|    * | ||||
|    * The algorithm is (approximately): | ||||
|    *   leftPower = forwardSpeed + yaw | ||||
|    *   rightPower = forwardSpeed - yaw | ||||
|    * | ||||
|    * @param iforwadSpeed speed in the forward direction | ||||
|    * @param iyaw speed around the vertical axis | ||||
|    */ | ||||
|   void driveVectorVoltage(double iforwardSpeed, double iyaw) override; | ||||
|  | ||||
|   /** | ||||
|    * Turn the robot clockwise (using open-loop control). Uses velocity mode. Sets the middle motor | ||||
|    * to zero velocity. | ||||
|    * | ||||
|    * @param ispeed motor power | ||||
|    */ | ||||
|   void rotate(double ispeed) override; | ||||
|  | ||||
|   /** | ||||
|    * Stop the robot (set all the motors to 0). Uses velocity mode. | ||||
|    */ | ||||
|   void stop() override; | ||||
|  | ||||
|   /** | ||||
|    * Drive the robot with a tank drive layout. Uses voltage mode. Sets the middle motor to zero | ||||
|    * velocity. | ||||
|    * | ||||
|    * @param ileftSpeed left side speed | ||||
|    * @param irightSpeed right side speed | ||||
|    * @param ithreshold deadband on joystick values | ||||
|    */ | ||||
|   void tank(double ileftSpeed, double irightSpeed, double ithreshold = 0) override; | ||||
|  | ||||
|   /** | ||||
|    * Drive the robot with an arcade drive layout. Uses voltage mode. Sets the middle motor to zero | ||||
|    * velocity. | ||||
|    * | ||||
|    * @param iforwardSpeed speed in the forward direction | ||||
|    * @param iyaw speed around the vertical axis | ||||
|    * @param ithreshold deadband on joystick values | ||||
|    */ | ||||
|   void arcade(double iforwardSpeed, double iyaw, double ithreshold = 0) override; | ||||
|  | ||||
|   /** | ||||
|    * Drive the robot with a curvature drive layout. The robot drives in constant radius turns | ||||
|    * where you control the curvature (inverse of radius) you drive in. This is advantageous | ||||
|    * because the forward speed will not affect the rate of turning. The algorithm switches to | ||||
|    * arcade if the forward speed is 0. Uses voltage mode. Sets the middle motor to zero velocity. | ||||
|    * | ||||
|    * @param iforwardSpeed speed in the forward direction | ||||
|    * @param icurvature curvature (inverse of radius) to drive in | ||||
|    * @param ithreshold deadband on joystick values | ||||
|    */ | ||||
|   void curvature(double iforwardSpeed, double icurvature, double ithreshold = 0) override; | ||||
|  | ||||
|   /** | ||||
|    * Drive the robot with an arcade drive layout. Uses voltage mode. | ||||
|    * | ||||
|    * @param irightSpeed speed to the right | ||||
|    * @param iforwardSpeed speed in the forward direction | ||||
|    * @param iyaw speed around the vertical axis | ||||
|    * @param ithreshold deadband on joystick values | ||||
|    */ | ||||
|   virtual void | ||||
|   hArcade(double irightSpeed, double iforwardSpeed, double iyaw, double ithreshold = 0); | ||||
|  | ||||
|   /** | ||||
|    * Drive the robot with an curvature drive layout. Uses voltage mode. | ||||
|    * | ||||
|    * @param irightSpeed speed to the right | ||||
|    * @param iforwardSpeed speed in the forward direction | ||||
|    * @param icurvature curvature (inverse of radius) to drive in | ||||
|    * @param ithreshold deadband on joystick values | ||||
|    */ | ||||
|   virtual void | ||||
|   hCurvature(double irightSpeed, double iforwardSpeed, double icurvature, double ithreshold = 0); | ||||
|  | ||||
|   /** | ||||
|    * Power the left side motors. Uses velocity mode. | ||||
|    * | ||||
|    * @param ispeed The motor power. | ||||
|    */ | ||||
|   void left(double ispeed) override; | ||||
|  | ||||
|   /** | ||||
|    * Power the right side motors. Uses velocity mode. | ||||
|    * | ||||
|    * @param ispeed The motor power. | ||||
|    */ | ||||
|   void right(double ispeed) override; | ||||
|  | ||||
|   /** | ||||
|    * Power the middle motors. Uses velocity mode. | ||||
|    * | ||||
|    * @param ispeed The motor power. | ||||
|    */ | ||||
|   virtual void middle(double ispeed); | ||||
|  | ||||
|   /** | ||||
|    * Read the sensors. | ||||
|    * | ||||
|    * @return sensor readings in the format {left, right, middle} | ||||
|    */ | ||||
|   std::valarray<std::int32_t> getSensorVals() const override; | ||||
|  | ||||
|   /** | ||||
|    * Reset the sensors to their zero point. | ||||
|    */ | ||||
|   void resetSensors() override; | ||||
|  | ||||
|   /** | ||||
|    * Set the brake mode for each motor. | ||||
|    * | ||||
|    * @param mode new brake mode | ||||
|    */ | ||||
|   void setBrakeMode(AbstractMotor::brakeMode mode) override; | ||||
|  | ||||
|   /** | ||||
|    * Set the encoder units for each motor. | ||||
|    * | ||||
|    * @param units new motor encoder units | ||||
|    */ | ||||
|   void setEncoderUnits(AbstractMotor::encoderUnits units) override; | ||||
|  | ||||
|   /** | ||||
|    * Set the gearset for each motor. | ||||
|    * | ||||
|    * @param gearset new motor gearset | ||||
|    */ | ||||
|   void setGearing(AbstractMotor::gearset gearset) override; | ||||
|  | ||||
|   /** | ||||
|    * Sets a new maximum velocity in RPM. The usable maximum depends on the maximum velocity of the | ||||
|    * currently installed gearset. If the configured maximum velocity is greater than the attainable | ||||
|    * maximum velocity from the currently installed gearset, the ChassisModel will still scale to | ||||
|    * that velocity. | ||||
|    * | ||||
|    * @param imaxVelocity The new maximum velocity. | ||||
|    */ | ||||
|   void setMaxVelocity(double imaxVelocity) override; | ||||
|  | ||||
|   /** | ||||
|    * @return The current maximum velocity. | ||||
|    */ | ||||
|   double getMaxVelocity() const override; | ||||
|  | ||||
|   /** | ||||
|    * Sets a new maximum voltage in mV in the range `[0-12000]`. | ||||
|    * | ||||
|    * @param imaxVoltage The new maximum voltage. | ||||
|    */ | ||||
|   void setMaxVoltage(double imaxVoltage) override; | ||||
|  | ||||
|   /** | ||||
|    * @return The maximum voltage in mV in the range `[0-12000]`. | ||||
|    */ | ||||
|   double getMaxVoltage() const override; | ||||
|  | ||||
|   /** | ||||
|    * Returns the left side motor. | ||||
|    * | ||||
|    * @return the left side motor | ||||
|    */ | ||||
|   std::shared_ptr<AbstractMotor> getLeftSideMotor() const; | ||||
|  | ||||
|   /** | ||||
|    * Returns the left side motor. | ||||
|    * | ||||
|    * @return the left side motor | ||||
|    */ | ||||
|   std::shared_ptr<AbstractMotor> getRightSideMotor() const; | ||||
|  | ||||
|   /** | ||||
|    * @return The middle motor. | ||||
|    */ | ||||
|   std::shared_ptr<AbstractMotor> getMiddleMotor() const; | ||||
|  | ||||
|   protected: | ||||
|   double maxVelocity; | ||||
|   double maxVoltage; | ||||
|   std::shared_ptr<AbstractMotor> leftSideMotor; | ||||
|   std::shared_ptr<AbstractMotor> rightSideMotor; | ||||
|   std::shared_ptr<AbstractMotor> middleMotor; | ||||
|   std::shared_ptr<ContinuousRotarySensor> leftSensor; | ||||
|   std::shared_ptr<ContinuousRotarySensor> rightSensor; | ||||
|   std::shared_ptr<ContinuousRotarySensor> middleSensor; | ||||
| }; | ||||
| } // namespace okapi | ||||
| @@ -0,0 +1,28 @@ | ||||
| /* | ||||
|  * This Source Code Form is subject to the terms of the Mozilla Public | ||||
|  * License, v. 2.0. If a copy of the MPL was not distributed with this | ||||
|  * file, You can obtain one at http://mozilla.org/MPL/2.0/. | ||||
|  */ | ||||
| #pragma once | ||||
|  | ||||
| #include "okapi/api/coreProsAPI.hpp" | ||||
| #include <valarray> | ||||
|  | ||||
| namespace okapi { | ||||
| /** | ||||
|  * A version of the ChassisModel that only supports read methods, such as querying sensor values. | ||||
|  * This class does not let you write to motors, so it supports having multiple owners and as a | ||||
|  * result copying is enabled. | ||||
|  */ | ||||
| class ReadOnlyChassisModel { | ||||
|   public: | ||||
|   virtual ~ReadOnlyChassisModel() = default; | ||||
|  | ||||
|   /** | ||||
|    * Read the sensors. | ||||
|    * | ||||
|    * @return sensor readings (format is implementation dependent) | ||||
|    */ | ||||
|   virtual std::valarray<std::int32_t> getSensorVals() const = 0; | ||||
| }; | ||||
| } // namespace okapi | ||||
							
								
								
									
										198
									
								
								SerialTest/include/okapi/api/chassis/model/skidSteerModel.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										198
									
								
								SerialTest/include/okapi/api/chassis/model/skidSteerModel.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,198 @@ | ||||
| /* | ||||
|  * This Source Code Form is subject to the terms of the Mozilla Public | ||||
|  * License, v. 2.0. If a copy of the MPL was not distributed with this | ||||
|  * file, You can obtain one at http://mozilla.org/MPL/2.0/. | ||||
|  */ | ||||
| #pragma once | ||||
|  | ||||
| #include "okapi/api/chassis/model/chassisModel.hpp" | ||||
| #include "okapi/api/device/motor/abstractMotor.hpp" | ||||
| #include "okapi/api/device/rotarysensor/continuousRotarySensor.hpp" | ||||
|  | ||||
| namespace okapi { | ||||
| class SkidSteerModel : public ChassisModel { | ||||
|   public: | ||||
|   /** | ||||
|    * Model for a skid steer drive (wheels parallel with robot's direction of motion). When all | ||||
|    * motors are powered +100%, the robot should move forward in a straight line. | ||||
|    * | ||||
|    * @param ileftSideMotor The left side motor. | ||||
|    * @param irightSideMotor The right side motor. | ||||
|    * @param ileftEnc The left side encoder. | ||||
|    * @param irightEnc The right side encoder. | ||||
|    */ | ||||
|   SkidSteerModel(std::shared_ptr<AbstractMotor> ileftSideMotor, | ||||
|                  std::shared_ptr<AbstractMotor> irightSideMotor, | ||||
|                  std::shared_ptr<ContinuousRotarySensor> ileftEnc, | ||||
|                  std::shared_ptr<ContinuousRotarySensor> irightEnc, | ||||
|                  double imaxVelocity, | ||||
|                  double imaxVoltage); | ||||
|  | ||||
|   /** | ||||
|    * Drive the robot forwards (using open-loop control). Uses velocity mode. | ||||
|    * | ||||
|    * @param ispeed motor power | ||||
|    */ | ||||
|   void forward(double ispeed) override; | ||||
|  | ||||
|   /** | ||||
|    * Drive the robot in an arc (using open-loop control). Uses velocity mode. | ||||
|    * The algorithm is (approximately): | ||||
|    *   leftPower = ySpeed + zRotation | ||||
|    *   rightPower = ySpeed - zRotation | ||||
|    * | ||||
|    * @param iySpeed speed on y axis (forward) | ||||
|    * @param izRotation speed around z axis (up) | ||||
|    */ | ||||
|   void driveVector(double iySpeed, double izRotation) override; | ||||
|  | ||||
|   /** | ||||
|    * Drive the robot in an arc. Uses voltage mode. | ||||
|    * The algorithm is (approximately): | ||||
|    *   leftPower = forwardSpeed + yaw | ||||
|    *   rightPower = forwardSpeed - yaw | ||||
|    * | ||||
|    * @param iforwadSpeed speed in the forward direction | ||||
|    * @param iyaw speed around the vertical axis | ||||
|    */ | ||||
|   void driveVectorVoltage(double iforwardSpeed, double iyaw) override; | ||||
|  | ||||
|   /** | ||||
|    * Turn the robot clockwise (using open-loop control). Uses velocity mode. | ||||
|    * | ||||
|    * @param ispeed motor power | ||||
|    */ | ||||
|   void rotate(double ispeed) override; | ||||
|  | ||||
|   /** | ||||
|    * Stop the robot (set all the motors to 0). Uses velocity mode. | ||||
|    */ | ||||
|   void stop() override; | ||||
|  | ||||
|   /** | ||||
|    * Drive the robot with a tank drive layout. Uses voltage mode. | ||||
|    * | ||||
|    * @param ileftSpeed left side speed | ||||
|    * @param irightSpeed right side speed | ||||
|    * @param ithreshold deadband on joystick values | ||||
|    */ | ||||
|   void tank(double ileftSpeed, double irightSpeed, double ithreshold = 0) override; | ||||
|  | ||||
|   /** | ||||
|    * Drive the robot with an arcade drive layout. Uses voltage mode. | ||||
|    * | ||||
|    * @param iforwardSpeed speed in the forward direction | ||||
|    * @param iyaw speed around the vertical axis | ||||
|    * @param ithreshold deadband on joystick values | ||||
|    */ | ||||
|   void arcade(double iforwardSpeed, double iyaw, double ithreshold = 0) override; | ||||
|  | ||||
|   /** | ||||
|    * Drive the robot with a curvature drive layout. The robot drives in constant radius turns | ||||
|    * where you control the curvature (inverse of radius) you drive in. This is advantageous | ||||
|    * because the forward speed will not affect the rate of turning. The algorithm switches to | ||||
|    * arcade if the forward speed is 0. Uses voltage mode. | ||||
|    * | ||||
|    * @param iforwardSpeed speed in the forward direction | ||||
|    * @param icurvature curvature (inverse of radius) to drive in | ||||
|    * @param ithreshold deadband on joystick values | ||||
|    */ | ||||
|   void curvature(double iforwardSpeed, double icurvature, double ithreshold = 0) override; | ||||
|  | ||||
|   /** | ||||
|    * Power the left side motors. Uses velocity mode. | ||||
|    * | ||||
|    * @param ispeed The motor power. | ||||
|    */ | ||||
|   void left(double ispeed) override; | ||||
|  | ||||
|   /** | ||||
|    * Power the right side motors. Uses velocity mode. | ||||
|    * | ||||
|    * @param ispeed The motor power. | ||||
|    */ | ||||
|   void right(double ispeed) override; | ||||
|  | ||||
|   /** | ||||
|    * Read the sensors. | ||||
|    * | ||||
|    * @return sensor readings in the format {left, right} | ||||
|    */ | ||||
|   std::valarray<std::int32_t> getSensorVals() const override; | ||||
|  | ||||
|   /** | ||||
|    * Reset the sensors to their zero point. | ||||
|    */ | ||||
|   void resetSensors() override; | ||||
|  | ||||
|   /** | ||||
|    * Set the brake mode for each motor. | ||||
|    * | ||||
|    * @param mode new brake mode | ||||
|    */ | ||||
|   void setBrakeMode(AbstractMotor::brakeMode mode) override; | ||||
|  | ||||
|   /** | ||||
|    * Set the encoder units for each motor. | ||||
|    * | ||||
|    * @param units new motor encoder units | ||||
|    */ | ||||
|   void setEncoderUnits(AbstractMotor::encoderUnits units) override; | ||||
|  | ||||
|   /** | ||||
|    * Set the gearset for each motor. | ||||
|    * | ||||
|    * @param gearset new motor gearset | ||||
|    */ | ||||
|   void setGearing(AbstractMotor::gearset gearset) override; | ||||
|  | ||||
|   /** | ||||
|    * Sets a new maximum velocity in RPM. The usable maximum depends on the maximum velocity of the | ||||
|    * currently installed gearset. If the configured maximum velocity is greater than the attainable | ||||
|    * maximum velocity from the currently installed gearset, the ChassisModel will still scale to | ||||
|    * that velocity. | ||||
|    * | ||||
|    * @param imaxVelocity The new maximum velocity. | ||||
|    */ | ||||
|   void setMaxVelocity(double imaxVelocity) override; | ||||
|  | ||||
|   /** | ||||
|    * @return The current maximum velocity. | ||||
|    */ | ||||
|   double getMaxVelocity() const override; | ||||
|  | ||||
|   /** | ||||
|    * Sets a new maximum voltage in mV in the range `[0-12000]`. | ||||
|    * | ||||
|    * @param imaxVoltage The new maximum voltage. | ||||
|    */ | ||||
|   void setMaxVoltage(double imaxVoltage) override; | ||||
|  | ||||
|   /** | ||||
|    * @return The maximum voltage in mV in the range `[0-12000]`. | ||||
|    */ | ||||
|   double getMaxVoltage() const override; | ||||
|  | ||||
|   /** | ||||
|    * Returns the left side motor. | ||||
|    * | ||||
|    * @return the left side motor | ||||
|    */ | ||||
|   std::shared_ptr<AbstractMotor> getLeftSideMotor() const; | ||||
|  | ||||
|   /** | ||||
|    * Returns the left side motor. | ||||
|    * | ||||
|    * @return the left side motor | ||||
|    */ | ||||
|   std::shared_ptr<AbstractMotor> getRightSideMotor() const; | ||||
|  | ||||
|   protected: | ||||
|   double maxVelocity; | ||||
|   double maxVoltage; | ||||
|   std::shared_ptr<AbstractMotor> leftSideMotor; | ||||
|   std::shared_ptr<AbstractMotor> rightSideMotor; | ||||
|   std::shared_ptr<ContinuousRotarySensor> leftSensor; | ||||
|   std::shared_ptr<ContinuousRotarySensor> rightSensor; | ||||
| }; | ||||
| } // namespace okapi | ||||
| @@ -0,0 +1,46 @@ | ||||
| /* | ||||
|  * This Source Code Form is subject to the terms of the Mozilla Public | ||||
|  * License, v. 2.0. If a copy of the MPL was not distributed with this | ||||
|  * file, You can obtain one at http://mozilla.org/MPL/2.0/. | ||||
|  */ | ||||
| #pragma once | ||||
|  | ||||
| #include "okapi/api/chassis/model/skidSteerModel.hpp" | ||||
|  | ||||
| namespace okapi { | ||||
| class ThreeEncoderSkidSteerModel : public SkidSteerModel { | ||||
|   public: | ||||
|   /** | ||||
|    * Model for a skid steer drive (wheels parallel with robot's direction of motion). When all | ||||
|    * motors are powered +127, the robot should move forward in a straight line. | ||||
|    * | ||||
|    * @param ileftSideMotor left side motor | ||||
|    * @param irightSideMotor right side motor | ||||
|    * @param ileftEnc left side encoder | ||||
|    * @param imiddleEnc middle encoder (mounted perpendicular to the left and right side encoders) | ||||
|    * @param irightEnc right side encoder | ||||
|    */ | ||||
|   ThreeEncoderSkidSteerModel(std::shared_ptr<AbstractMotor> ileftSideMotor, | ||||
|                              std::shared_ptr<AbstractMotor> irightSideMotor, | ||||
|                              std::shared_ptr<ContinuousRotarySensor> ileftEnc, | ||||
|                              std::shared_ptr<ContinuousRotarySensor> irightEnc, | ||||
|                              std::shared_ptr<ContinuousRotarySensor> imiddleEnc, | ||||
|                              double imaxVelocity, | ||||
|                              double imaxVoltage); | ||||
|  | ||||
|   /** | ||||
|    * Read the sensors. | ||||
|    * | ||||
|    * @return sensor readings in the format {left, right, middle} | ||||
|    */ | ||||
|   std::valarray<std::int32_t> getSensorVals() const override; | ||||
|  | ||||
|   /** | ||||
|    * Reset the sensors to their zero point. | ||||
|    */ | ||||
|   void resetSensors() override; | ||||
|  | ||||
|   protected: | ||||
|   std::shared_ptr<ContinuousRotarySensor> middleSensor; | ||||
| }; | ||||
| } // namespace okapi | ||||
| @@ -0,0 +1,50 @@ | ||||
| /* | ||||
|  * This Source Code Form is subject to the terms of the Mozilla Public | ||||
|  * License, v. 2.0. If a copy of the MPL was not distributed with this | ||||
|  * file, You can obtain one at http://mozilla.org/MPL/2.0/. | ||||
|  */ | ||||
| #pragma once | ||||
|  | ||||
| #include "okapi/api/chassis/model/xDriveModel.hpp" | ||||
|  | ||||
| namespace okapi { | ||||
| class ThreeEncoderXDriveModel : public XDriveModel { | ||||
|   public: | ||||
|   /** | ||||
|    * Model for an x drive (wheels at 45 deg from a skid steer drive). When all motors are powered | ||||
|    * +100%, the robot should move forward in a straight line. | ||||
|    * | ||||
|    * @param itopLeftMotor The top left motor. | ||||
|    * @param itopRightMotor The top right motor. | ||||
|    * @param ibottomRightMotor The bottom right motor. | ||||
|    * @param ibottomLeftMotor The bottom left motor. | ||||
|    * @param ileftEnc The left side encoder. | ||||
|    * @param irightEnc The right side encoder. | ||||
|    * @param imiddleEnc The middle encoder. | ||||
|    */ | ||||
|   ThreeEncoderXDriveModel(std::shared_ptr<AbstractMotor> itopLeftMotor, | ||||
|                           std::shared_ptr<AbstractMotor> itopRightMotor, | ||||
|                           std::shared_ptr<AbstractMotor> ibottomRightMotor, | ||||
|                           std::shared_ptr<AbstractMotor> ibottomLeftMotor, | ||||
|                           std::shared_ptr<ContinuousRotarySensor> ileftEnc, | ||||
|                           std::shared_ptr<ContinuousRotarySensor> irightEnc, | ||||
|                           std::shared_ptr<ContinuousRotarySensor> imiddleEnc, | ||||
|                           double imaxVelocity, | ||||
|                           double imaxVoltage); | ||||
|  | ||||
|   /** | ||||
|    * Read the sensors. | ||||
|    * | ||||
|    * @return sensor readings in the format {left, right, middle} | ||||
|    */ | ||||
|   std::valarray<std::int32_t> getSensorVals() const override; | ||||
|  | ||||
|   /** | ||||
|    * Reset the sensors to their zero point. | ||||
|    */ | ||||
|   void resetSensors() override; | ||||
|  | ||||
|   protected: | ||||
|   std::shared_ptr<ContinuousRotarySensor> middleSensor; | ||||
| }; | ||||
| } // namespace okapi | ||||
							
								
								
									
										273
									
								
								SerialTest/include/okapi/api/chassis/model/xDriveModel.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										273
									
								
								SerialTest/include/okapi/api/chassis/model/xDriveModel.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,273 @@ | ||||
| /* | ||||
|  * This Source Code Form is subject to the terms of the Mozilla Public | ||||
|  * License, v. 2.0. If a copy of the MPL was not distributed with this | ||||
|  * file, You can obtain one at http://mozilla.org/MPL/2.0/. | ||||
|  */ | ||||
| #pragma once | ||||
|  | ||||
| #include "okapi/api/chassis/model/chassisModel.hpp" | ||||
| #include "okapi/api/device/motor/abstractMotor.hpp" | ||||
| #include "okapi/api/device/rotarysensor/continuousRotarySensor.hpp" | ||||
| #include "okapi/api/units/QAngle.hpp" | ||||
|  | ||||
| namespace okapi { | ||||
| class XDriveModel : public ChassisModel { | ||||
|   public: | ||||
|   /** | ||||
|    * Model for an x drive (wheels at 45 deg from a skid steer drive). When all motors are powered | ||||
|    * +100%, the robot should move forward in a straight line. | ||||
|    * | ||||
|    * @param itopLeftMotor The top left motor. | ||||
|    * @param itopRightMotor The top right motor. | ||||
|    * @param ibottomRightMotor The bottom right motor. | ||||
|    * @param ibottomLeftMotor The bottom left motor. | ||||
|    * @param ileftEnc The left side encoder. | ||||
|    * @param irightEnc The right side encoder. | ||||
|    */ | ||||
|   XDriveModel(std::shared_ptr<AbstractMotor> itopLeftMotor, | ||||
|               std::shared_ptr<AbstractMotor> itopRightMotor, | ||||
|               std::shared_ptr<AbstractMotor> ibottomRightMotor, | ||||
|               std::shared_ptr<AbstractMotor> ibottomLeftMotor, | ||||
|               std::shared_ptr<ContinuousRotarySensor> ileftEnc, | ||||
|               std::shared_ptr<ContinuousRotarySensor> irightEnc, | ||||
|               double imaxVelocity, | ||||
|               double imaxVoltage); | ||||
|  | ||||
|   /** | ||||
|    * Drive the robot forwards (using open-loop control). Uses velocity mode. | ||||
|    * | ||||
|    * @param ispeed motor power | ||||
|    */ | ||||
|   void forward(double ipower) override; | ||||
|  | ||||
|   /** | ||||
|    * Drive the robot in an arc (using open-loop control). Uses velocity mode. | ||||
|    * The algorithm is (approximately): | ||||
|    *   leftPower = forwardSpeed + yaw | ||||
|    *   rightPower = forwardSpeed - yaw | ||||
|    * | ||||
|    * @param iforwardSpeed speed in the forward direction | ||||
|    * @param iyaw speed around the vertical axis | ||||
|    */ | ||||
|   void driveVector(double iforwardSpeed, double iyaw) override; | ||||
|  | ||||
|   /** | ||||
|    * Drive the robot in an arc. Uses voltage mode. | ||||
|    * The algorithm is (approximately): | ||||
|    *   leftPower = forwardSpeed + yaw | ||||
|    *   rightPower = forwardSpeed - yaw | ||||
|    * | ||||
|    * @param iforwadSpeed speed in the forward direction | ||||
|    * @param iyaw speed around the vertical axis | ||||
|    */ | ||||
|   void driveVectorVoltage(double iforwardSpeed, double iyaw) override; | ||||
|  | ||||
|   /** | ||||
|    * Turn the robot clockwise (using open-loop control). Uses velocity mode. | ||||
|    * | ||||
|    * @param ipower motor power | ||||
|    */ | ||||
|   void rotate(double ipower) override; | ||||
|  | ||||
|   /** | ||||
|    * Drive the robot side-ways (using open-loop control) where positive ipower is | ||||
|    * to the right and negative ipower is to the left. Uses velocity mode. | ||||
|    * | ||||
|    * @param ispeed motor power | ||||
|    */ | ||||
|   void strafe(double ipower); | ||||
|  | ||||
|   /** | ||||
|    * Strafe the robot in an arc (using open-loop control) where positive istrafeSpeed is | ||||
|    * to the right and negative istrafeSpeed is to the left. Uses velocity mode. | ||||
|    * The algorithm is (approximately): | ||||
|    *   topLeftPower = -1 * istrafeSpeed + yaw | ||||
|    *   topRightPower = istrafeSpeed - yaw | ||||
|    *   bottomRightPower = -1 * istrafeSpeed - yaw | ||||
|    *   bottomLeftPower = istrafeSpeed + yaw | ||||
|    * | ||||
|    * @param istrafeSpeed speed to the right | ||||
|    * @param iyaw speed around the vertical axis | ||||
|    */ | ||||
|   void strafeVector(double istrafeSpeed, double iyaw); | ||||
|  | ||||
|   /** | ||||
|    * Stop the robot (set all the motors to 0). Uses velocity mode. | ||||
|    */ | ||||
|   void stop() override; | ||||
|  | ||||
|   /** | ||||
|    * Drive the robot with a tank drive layout. Uses voltage mode. | ||||
|    * | ||||
|    * @param ileftSpeed left side speed | ||||
|    * @param irightSpeed right side speed | ||||
|    * @param ithreshold deadband on joystick values | ||||
|    */ | ||||
|   void tank(double ileftSpeed, double irightSpeed, double ithreshold = 0) override; | ||||
|  | ||||
|   /** | ||||
|    * Drive the robot with an arcade drive layout. Uses voltage mode. | ||||
|    * | ||||
|    * @param iforwardSpeed speed in the forward direction | ||||
|    * @param iyaw speed around the vertical axis | ||||
|    * @param ithreshold deadband on joystick values | ||||
|    */ | ||||
|   void arcade(double iforwardSpeed, double iyaw, double ithreshold = 0) override; | ||||
|  | ||||
|   /** | ||||
|    * Drive the robot with a curvature drive layout. The robot drives in constant radius turns | ||||
|    * where you control the curvature (inverse of radius) you drive in. This is advantageous | ||||
|    * because the forward speed will not affect the rate of turning. The algorithm switches to | ||||
|    * arcade if the forward speed is 0. Uses voltage mode. | ||||
|    * | ||||
|    * @param iforwardSpeed speed forward direction | ||||
|    * @param icurvature curvature (inverse of radius) to drive in | ||||
|    * @param ithreshold deadband on joystick values | ||||
|    */ | ||||
|   void curvature(double iforwardSpeed, double icurvature, double ithreshold = 0) override; | ||||
|  | ||||
|   /** | ||||
|    * Drive the robot with an arcade drive layout. Uses voltage mode. | ||||
|    * | ||||
|    * @param irightSpeed speed to the right | ||||
|    * @param iforwardSpeed speed in the forward direction | ||||
|    * @param iyaw speed around the vertical axis | ||||
|    * @param ithreshold deadband on joystick values | ||||
|    */ | ||||
|   virtual void | ||||
|   xArcade(double irightSpeed, double iforwardSpeed, double iyaw, double ithreshold = 0); | ||||
|  | ||||
|   /** | ||||
|    * Drive the robot with a field-oriented arcade drive layout. Uses voltage mode. | ||||
|    * For example: | ||||
|    *    Both `fieldOrientedXArcade(1, 0, 0, 0_deg)` and `fieldOrientedXArcade(1, 0, 0, 90_deg)` | ||||
|    *    will drive the chassis in the forward/north direction. In other words, no matter | ||||
|    *    the robot's heading, the robot will move forward/north when you tell it | ||||
|    *    to move forward/north and will move right/east when you tell it to move right/east. | ||||
|    * | ||||
|    * | ||||
|    * @param ixSpeed forward speed -- (`+1`) forward, (`-1`) backward | ||||
|    * @param iySpeed sideways speed -- (`+1`) right, (`-1`) left | ||||
|    * @param iyaw turn speed -- (`+1`) clockwise, (`-1`) counter-clockwise | ||||
|    * @param iangle current chassis angle (`0_deg` = no correction, winds clockwise) | ||||
|    * @param ithreshold deadband on joystick values | ||||
|    */ | ||||
|   virtual void fieldOrientedXArcade(double ixSpeed, | ||||
|                                     double iySpeed, | ||||
|                                     double iyaw, | ||||
|                                     QAngle iangle, | ||||
|                                     double ithreshold = 0); | ||||
|  | ||||
|   /** | ||||
|    * Power the left side motors. Uses velocity mode. | ||||
|    * | ||||
|    * @param ispeed The motor power. | ||||
|    */ | ||||
|   void left(double ispeed) override; | ||||
|  | ||||
|   /** | ||||
|    * Power the right side motors. Uses velocity mode. | ||||
|    * | ||||
|    * @param ispeed The motor power. | ||||
|    */ | ||||
|   void right(double ispeed) override; | ||||
|  | ||||
|   /** | ||||
|    * Read the sensors. | ||||
|    * | ||||
|    * @return sensor readings in the format {left, right} | ||||
|    */ | ||||
|   std::valarray<std::int32_t> getSensorVals() const override; | ||||
|  | ||||
|   /** | ||||
|    * Reset the sensors to their zero point. | ||||
|    */ | ||||
|   void resetSensors() override; | ||||
|  | ||||
|   /** | ||||
|    * Set the brake mode for each motor. | ||||
|    * | ||||
|    * @param mode new brake mode | ||||
|    */ | ||||
|   void setBrakeMode(AbstractMotor::brakeMode mode) override; | ||||
|  | ||||
|   /** | ||||
|    * Set the encoder units for each motor. | ||||
|    * | ||||
|    * @param units new motor encoder units | ||||
|    */ | ||||
|   void setEncoderUnits(AbstractMotor::encoderUnits units) override; | ||||
|  | ||||
|   /** | ||||
|    * Set the gearset for each motor. | ||||
|    * | ||||
|    * @param gearset new motor gearset | ||||
|    */ | ||||
|   void setGearing(AbstractMotor::gearset gearset) override; | ||||
|  | ||||
|   /** | ||||
|    * Sets a new maximum velocity in RPM. The usable maximum depends on the maximum velocity of the | ||||
|    * currently installed gearset. If the configured maximum velocity is greater than the attainable | ||||
|    * maximum velocity from the currently installed gearset, the ChassisModel will still scale to | ||||
|    * that velocity. | ||||
|    * | ||||
|    * @param imaxVelocity The new maximum velocity. | ||||
|    */ | ||||
|   void setMaxVelocity(double imaxVelocity) override; | ||||
|  | ||||
|   /** | ||||
|    * @return The current maximum velocity. | ||||
|    */ | ||||
|   double getMaxVelocity() const override; | ||||
|  | ||||
|   /** | ||||
|    * Sets a new maximum voltage in mV in the range `[0-12000]`. | ||||
|    * | ||||
|    * @param imaxVoltage The new maximum voltage. | ||||
|    */ | ||||
|   void setMaxVoltage(double imaxVoltage) override; | ||||
|  | ||||
|   /** | ||||
|    * @return The maximum voltage in mV in the range `[0-12000]`. | ||||
|    */ | ||||
|   double getMaxVoltage() const override; | ||||
|  | ||||
|   /** | ||||
|    * Returns the top left motor. | ||||
|    * | ||||
|    * @return the top left motor | ||||
|    */ | ||||
|   std::shared_ptr<AbstractMotor> getTopLeftMotor() const; | ||||
|  | ||||
|   /** | ||||
|    * Returns the top right motor. | ||||
|    * | ||||
|    * @return the top right motor | ||||
|    */ | ||||
|   std::shared_ptr<AbstractMotor> getTopRightMotor() const; | ||||
|  | ||||
|   /** | ||||
|    * Returns the bottom right motor. | ||||
|    * | ||||
|    * @return the bottom right motor | ||||
|    */ | ||||
|   std::shared_ptr<AbstractMotor> getBottomRightMotor() const; | ||||
|  | ||||
|   /** | ||||
|    * Returns the bottom left motor. | ||||
|    * | ||||
|    * @return the bottom left motor | ||||
|    */ | ||||
|   std::shared_ptr<AbstractMotor> getBottomLeftMotor() const; | ||||
|  | ||||
|   protected: | ||||
|   double maxVelocity; | ||||
|   double maxVoltage; | ||||
|   std::shared_ptr<AbstractMotor> topLeftMotor; | ||||
|   std::shared_ptr<AbstractMotor> topRightMotor; | ||||
|   std::shared_ptr<AbstractMotor> bottomRightMotor; | ||||
|   std::shared_ptr<AbstractMotor> bottomLeftMotor; | ||||
|   std::shared_ptr<ContinuousRotarySensor> leftSensor; | ||||
|   std::shared_ptr<ContinuousRotarySensor> rightSensor; | ||||
| }; | ||||
| } // namespace okapi | ||||
| @@ -0,0 +1,24 @@ | ||||
| /* | ||||
|  * This Source Code Form is subject to the terms of the Mozilla Public | ||||
|  * License, v. 2.0. If a copy of the MPL was not distributed with this | ||||
|  * file, You can obtain one at http://mozilla.org/MPL/2.0/. | ||||
|  */ | ||||
| #pragma once | ||||
|  | ||||
| #include "okapi/api/control/closedLoopController.hpp" | ||||
|  | ||||
| namespace okapi { | ||||
| /** | ||||
|  * Closed-loop controller that steps on its own in another thread and automatically writes to the | ||||
|  * output. | ||||
|  */ | ||||
| template <typename Input, typename Output> | ||||
| class AsyncController : public ClosedLoopController<Input, Output> { | ||||
|   public: | ||||
|   /** | ||||
|    * Blocks the current task until the controller has settled. Determining what settling means is | ||||
|    * implementation-dependent. | ||||
|    */ | ||||
|   virtual void waitUntilSettled() = 0; | ||||
| }; | ||||
| } // namespace okapi | ||||
| @@ -0,0 +1,291 @@ | ||||
| /* | ||||
|  * This Source Code Form is subject to the terms of the Mozilla Public | ||||
|  * License, v. 2.0. If a copy of the MPL was not distributed with this | ||||
|  * file, You can obtain one at http://mozilla.org/MPL/2.0/. | ||||
|  */ | ||||
| #pragma once | ||||
|  | ||||
| #include "okapi/api/control/async/asyncPositionController.hpp" | ||||
| #include "okapi/api/control/util/pathfinderUtil.hpp" | ||||
| #include "okapi/api/device/motor/abstractMotor.hpp" | ||||
| #include "okapi/api/units/QAngularSpeed.hpp" | ||||
| #include "okapi/api/units/QSpeed.hpp" | ||||
| #include "okapi/api/util/logging.hpp" | ||||
| #include "okapi/api/util/timeUtil.hpp" | ||||
| #include <atomic> | ||||
| #include <map> | ||||
|  | ||||
| #include "squiggles.hpp" | ||||
|  | ||||
| namespace okapi { | ||||
| class AsyncLinearMotionProfileController : public AsyncPositionController<std::string, double> { | ||||
|   public: | ||||
|   /** | ||||
|    * An Async Controller which generates and follows 1D motion profiles. | ||||
|    * | ||||
|    * @param itimeUtil The TimeUtil. | ||||
|    * @param ilimits The default limits. | ||||
|    * @param ioutput The output to write velocity targets to. | ||||
|    * @param idiameter The effective diameter for whatever the motor spins. | ||||
|    * @param ipair The gearset. | ||||
|    * @param ilogger The logger this instance will log to. | ||||
|    */ | ||||
|   AsyncLinearMotionProfileController( | ||||
|     const TimeUtil &itimeUtil, | ||||
|     const PathfinderLimits &ilimits, | ||||
|     const std::shared_ptr<ControllerOutput<double>> &ioutput, | ||||
|     const QLength &idiameter, | ||||
|     const AbstractMotor::GearsetRatioPair &ipair, | ||||
|     const std::shared_ptr<Logger> &ilogger = Logger::getDefaultLogger()); | ||||
|  | ||||
|   AsyncLinearMotionProfileController(AsyncLinearMotionProfileController &&other) = delete; | ||||
|  | ||||
|   AsyncLinearMotionProfileController & | ||||
|   operator=(AsyncLinearMotionProfileController &&other) = delete; | ||||
|  | ||||
|   ~AsyncLinearMotionProfileController() override; | ||||
|  | ||||
|   /** | ||||
|    * Generates a path which intersects the given waypoints and saves it internally with a key of | ||||
|    * pathId. Call `executePath()` with the same `pathId` to run it. | ||||
|    * | ||||
|    * If the waypoints form a path which is impossible to achieve, an instance of | ||||
|    * `std::runtime_error` is thrown (and an error is logged) which describes the waypoints. If there | ||||
|    * are no waypoints, no path is generated. | ||||
|    * | ||||
|    * @param iwaypoints The waypoints to hit on the path. | ||||
|    * @param ipathId A unique identifier to save the path with. | ||||
|    */ | ||||
|   void generatePath(std::initializer_list<QLength> iwaypoints, const std::string &ipathId); | ||||
|  | ||||
|   /** | ||||
|    * Generates a path which intersects the given waypoints and saves it internally with a key of | ||||
|    * pathId. Call `executePath()` with the same pathId to run it. | ||||
|    * | ||||
|    * If the waypoints form a path which is impossible to achieve, an instance of | ||||
|    * `std::runtime_error` is thrown (and an error is logged) which describes the waypoints. If there | ||||
|    * are no waypoints, no path is generated. | ||||
|    * | ||||
|    * @param iwaypoints The waypoints to hit on the path. | ||||
|    * @param ipathId A unique identifier to save the path with. | ||||
|    * @param ilimits The limits to use for this path only. | ||||
|    */ | ||||
|   void generatePath(std::initializer_list<QLength> iwaypoints, | ||||
|                     const std::string &ipathId, | ||||
|                     const PathfinderLimits &ilimits); | ||||
|  | ||||
|   /** | ||||
|    * Removes a path and frees the memory it used. This function returns `true` if the path was | ||||
|    * either deleted or didn't exist in the first place. It returns `false` if the path could not be | ||||
|    * removed because it is running. | ||||
|    * | ||||
|    * @param ipathId A unique identifier for the path, previously passed to generatePath() | ||||
|    * @return `true` if the path no longer exists | ||||
|    */ | ||||
|   bool removePath(const std::string &ipathId); | ||||
|  | ||||
|   /** | ||||
|    * Gets the identifiers of all paths saved in this `AsyncMotionProfileController`. | ||||
|    * | ||||
|    * @return The identifiers of all paths | ||||
|    */ | ||||
|   std::vector<std::string> getPaths(); | ||||
|  | ||||
|   /** | ||||
|    * Executes a path with the given ID. If there is no path matching the ID, the method will | ||||
|    * return. Any targets set while a path is being followed will be ignored. | ||||
|    * | ||||
|    * @param ipathId A unique identifier for the path, previously passed to `generatePath()`. | ||||
|    */ | ||||
|   void setTarget(std::string ipathId) override; | ||||
|  | ||||
|   /** | ||||
|    * Executes a path with the given ID. If there is no path matching the ID, the method will | ||||
|    * return. Any targets set while a path is being followed will be ignored. | ||||
|    * | ||||
|    * @param ipathId A unique identifier for the path, previously passed to `generatePath()`. | ||||
|    * @param ibackwards Whether to follow the profile backwards. | ||||
|    */ | ||||
|   void setTarget(std::string ipathId, bool ibackwards); | ||||
|  | ||||
|   /** | ||||
|    * Writes the value of the controller output. This method might be automatically called in another | ||||
|    * thread by the controller. | ||||
|    * | ||||
|    * This just calls `setTarget()`. | ||||
|    */ | ||||
|   void controllerSet(std::string ivalue) override; | ||||
|  | ||||
|   /** | ||||
|    * Gets the last set target, or the default target if none was set. | ||||
|    * | ||||
|    * @return the last target | ||||
|    */ | ||||
|   std::string getTarget() override; | ||||
|  | ||||
|   /** | ||||
|    * Gets the last set target, or the default target if none was set. | ||||
|    * | ||||
|    * @return the last target | ||||
|    */ | ||||
|   virtual std::string getTarget() const; | ||||
|  | ||||
|   /** | ||||
|    * This is overridden to return the current path. | ||||
|    * | ||||
|    * @return The most recent value of the process variable. | ||||
|    */ | ||||
|   std::string getProcessValue() const override; | ||||
|  | ||||
|   /** | ||||
|    * Blocks the current task until the controller has settled. This controller is settled when | ||||
|    * it has finished following a path. If no path is being followed, it is settled. | ||||
|    */ | ||||
|   void waitUntilSettled() override; | ||||
|  | ||||
|   /** | ||||
|    * Generates a new path from the position (typically the current position) to the target and | ||||
|    * blocks until the controller has settled. Does not save the path which was generated. | ||||
|    * | ||||
|    * @param iposition The starting position. | ||||
|    * @param itarget The target position. | ||||
|    * @param ibackwards Whether to follow the profile backwards. | ||||
|    */ | ||||
|   void moveTo(const QLength &iposition, const QLength &itarget, bool ibackwards = false); | ||||
|  | ||||
|   /** | ||||
|    * Generates a new path from the position (typically the current position) to the target and | ||||
|    * blocks until the controller has settled. Does not save the path which was generated. | ||||
|    * | ||||
|    * @param iposition The starting position. | ||||
|    * @param itarget The target position. | ||||
|    * @param ilimits The limits to use for this path only. | ||||
|    * @param ibackwards Whether to follow the profile backwards. | ||||
|    */ | ||||
|   void moveTo(const QLength &iposition, | ||||
|               const QLength &itarget, | ||||
|               const PathfinderLimits &ilimits, | ||||
|               bool ibackwards = false); | ||||
|  | ||||
|   /** | ||||
|    * Returns the last error of the controller. Does not update when disabled. Returns zero if there | ||||
|    * is no path currently being followed. | ||||
|    * | ||||
|    * @return the last error | ||||
|    */ | ||||
|   double getError() const override; | ||||
|  | ||||
|   /** | ||||
|    * Returns whether the controller has settled at the target. Determining what settling means is | ||||
|    * implementation-dependent. | ||||
|    * | ||||
|    * If the controller is disabled, this method must return `true`. | ||||
|    * | ||||
|    * @return whether the controller is settled | ||||
|    */ | ||||
|   bool isSettled() override; | ||||
|  | ||||
|   /** | ||||
|    * Resets the controller's internal state so it is similar to when it was first initialized, while | ||||
|    * keeping any user-configured information. This implementation also stops movement. | ||||
|    */ | ||||
|   void reset() override; | ||||
|  | ||||
|   /** | ||||
|    * Changes whether the controller is off or on. Turning the controller on after it was off will | ||||
|    * NOT cause the controller to move to its last set target. | ||||
|    */ | ||||
|   void flipDisable() override; | ||||
|  | ||||
|   /** | ||||
|    * Sets whether the controller is off or on. Turning the controller on after it was off will | ||||
|    * NOT cause the controller to move to its last set target, unless it was reset in that time. | ||||
|    * | ||||
|    * @param iisDisabled whether the controller is disabled | ||||
|    */ | ||||
|   void flipDisable(bool iisDisabled) override; | ||||
|  | ||||
|   /** | ||||
|    * Returns whether the controller is currently disabled. | ||||
|    * | ||||
|    * @return whether the controller is currently disabled | ||||
|    */ | ||||
|   bool isDisabled() const override; | ||||
|  | ||||
|   /** | ||||
|    * This implementation does nothing because the API always requires the starting position to be | ||||
|    * specified. | ||||
|    */ | ||||
|   void tarePosition() override; | ||||
|  | ||||
|   /** | ||||
|    * This implementation does nothing because the maximum velocity is configured using | ||||
|    * PathfinderLimits elsewhere. | ||||
|    * | ||||
|    * @param imaxVelocity Ignored. | ||||
|    */ | ||||
|   void setMaxVelocity(std::int32_t imaxVelocity) override; | ||||
|  | ||||
|   /** | ||||
|    * Starts the internal thread. This should not be called by normal users. This method is called | ||||
|    * by the AsyncControllerFactory when making a new instance of this class. | ||||
|    */ | ||||
|   void startThread(); | ||||
|  | ||||
|   /** | ||||
|    * Returns the underlying thread handle. | ||||
|    * | ||||
|    * @return The underlying thread handle. | ||||
|    */ | ||||
|   CrossplatformThread *getThread() const; | ||||
|  | ||||
|   /** | ||||
|    * Attempts to remove a path without stopping execution, then if that fails, disables the | ||||
|    * controller and removes the path. | ||||
|    * | ||||
|    * @param ipathId The path ID that will be removed | ||||
|    */ | ||||
|   void forceRemovePath(const std::string &ipathId); | ||||
|  | ||||
|   protected: | ||||
|   std::shared_ptr<Logger> logger; | ||||
|   std::map<std::string, std::vector<squiggles::ProfilePoint>> paths{}; | ||||
|   PathfinderLimits limits; | ||||
|   std::shared_ptr<ControllerOutput<double>> output; | ||||
|   QLength diameter; | ||||
|   AbstractMotor::GearsetRatioPair pair; | ||||
|   double currentProfilePosition{0}; | ||||
|   TimeUtil timeUtil; | ||||
|  | ||||
|   // This must be locked when accessing the current path | ||||
|   CrossplatformMutex currentPathMutex; | ||||
|  | ||||
|   std::string currentPath{""}; | ||||
|   std::atomic_bool isRunning{false}; | ||||
|   std::atomic_int direction{1}; | ||||
|   std::atomic_bool disabled{false}; | ||||
|   std::atomic_bool dtorCalled{false}; | ||||
|   CrossplatformThread *task{nullptr}; | ||||
|  | ||||
|   static void trampoline(void *context); | ||||
|   void loop(); | ||||
|  | ||||
|   /** | ||||
|    * Follow the supplied path. Must follow the disabled lifecycle. | ||||
|    */ | ||||
|   virtual void executeSinglePath(const std::vector<squiggles::ProfilePoint> &path, | ||||
|                                  std::unique_ptr<AbstractRate> rate); | ||||
|  | ||||
|   /** | ||||
|    * Converts linear "chassis" speed to rotational motor speed. | ||||
|    * | ||||
|    * @param linear "chassis" frame speed | ||||
|    * @return motor frame speed | ||||
|    */ | ||||
|   QAngularSpeed convertLinearToRotational(QSpeed linear) const; | ||||
|  | ||||
|   std::string getPathErrorMessage(const std::vector<PathfinderPoint> &points, | ||||
|                                   const std::string &ipathId, | ||||
|                                   int length); | ||||
| }; | ||||
| } // namespace okapi | ||||
| @@ -0,0 +1,326 @@ | ||||
| /* | ||||
|  * This Source Code Form is subject to the terms of the Mozilla Public | ||||
|  * License, v. 2.0. If a copy of the MPL was not distributed with this | ||||
|  * file, You can obtain one at http://mozilla.org/MPL/2.0/. | ||||
|  */ | ||||
| #pragma once | ||||
|  | ||||
| #include "okapi/api/chassis/controller/chassisScales.hpp" | ||||
| #include "okapi/api/chassis/model/skidSteerModel.hpp" | ||||
| #include "okapi/api/control/async/asyncPositionController.hpp" | ||||
| #include "okapi/api/control/util/pathfinderUtil.hpp" | ||||
| #include "okapi/api/units/QAngularSpeed.hpp" | ||||
| #include "okapi/api/units/QSpeed.hpp" | ||||
| #include "okapi/api/util/logging.hpp" | ||||
| #include "okapi/api/util/timeUtil.hpp" | ||||
| #include <atomic> | ||||
| #include <iostream> | ||||
| #include <map> | ||||
|  | ||||
| #include "squiggles.hpp" | ||||
|  | ||||
| namespace okapi { | ||||
| class AsyncMotionProfileController : public AsyncPositionController<std::string, PathfinderPoint> { | ||||
|   public: | ||||
|   /** | ||||
|    * An Async Controller which generates and follows 2D motion profiles. Throws a | ||||
|    * `std::invalid_argument` exception if the gear ratio is zero. | ||||
|    * | ||||
|    * @param itimeUtil The TimeUtil. | ||||
|    * @param ilimits The default limits. | ||||
|    * @param imodel The chassis model to control. | ||||
|    * @param iscales The chassis dimensions. | ||||
|    * @param ipair The gearset. | ||||
|    * @param ilogger The logger this instance will log to. | ||||
|    */ | ||||
|   AsyncMotionProfileController(const TimeUtil &itimeUtil, | ||||
|                                const PathfinderLimits &ilimits, | ||||
|                                const std::shared_ptr<ChassisModel> &imodel, | ||||
|                                const ChassisScales &iscales, | ||||
|                                const AbstractMotor::GearsetRatioPair &ipair, | ||||
|                                const std::shared_ptr<Logger> &ilogger = Logger::getDefaultLogger()); | ||||
|  | ||||
|   AsyncMotionProfileController(AsyncMotionProfileController &&other) = delete; | ||||
|  | ||||
|   AsyncMotionProfileController &operator=(AsyncMotionProfileController &&other) = delete; | ||||
|  | ||||
|   ~AsyncMotionProfileController() override; | ||||
|  | ||||
|   /** | ||||
|    * Generates a path which intersects the given waypoints and saves it internally with a key of | ||||
|    * pathId. Call `executePath()` with the same pathId to run it. | ||||
|    * | ||||
|    * If the waypoints form a path which is impossible to achieve, an instance of | ||||
|    * `std::runtime_error` is thrown (and an error is logged) which describes the waypoints. If there | ||||
|    * are no waypoints, no path is generated. | ||||
|    * | ||||
|    * @param iwaypoints The waypoints to hit on the path. | ||||
|    * @param ipathId A unique identifier to save the path with. | ||||
|    */ | ||||
|   void generatePath(std::initializer_list<PathfinderPoint> iwaypoints, const std::string &ipathId); | ||||
|  | ||||
|   /** | ||||
|    * Generates a path which intersects the given waypoints and saves it internally with a key of | ||||
|    * pathId. Call `executePath()` with the same pathId to run it. | ||||
|    * | ||||
|    * If the waypoints form a path which is impossible to achieve, an instance of | ||||
|    * `std::runtime_error` is thrown (and an error is logged) which describes the waypoints. If there | ||||
|    * are no waypoints, no path is generated. | ||||
|    * | ||||
|    * NOTE: The waypoints are expected to be in the | ||||
|    * okapi::State::FRAME_TRANSFORMATION format where +x is forward, +y is right, | ||||
|    * and 0 theta is measured from the +x axis to the +y axis. | ||||
|    * | ||||
|    * @param iwaypoints The waypoints to hit on the path. | ||||
|    * @param ipathId A unique identifier to save the path with. | ||||
|    * @param ilimits The limits to use for this path only. | ||||
|    */ | ||||
|   void generatePath(std::initializer_list<PathfinderPoint> iwaypoints, | ||||
|                     const std::string &ipathId, | ||||
|                     const PathfinderLimits &ilimits); | ||||
|  | ||||
|   /** | ||||
|    * Removes a path and frees the memory it used. This function returns true if the path was either | ||||
|    * deleted or didn't exist in the first place. It returns false if the path could not be removed | ||||
|    * because it is running. | ||||
|    * | ||||
|    * @param ipathId A unique identifier for the path, previously passed to `generatePath()` | ||||
|    * @return True if the path no longer exists | ||||
|    */ | ||||
|   bool removePath(const std::string &ipathId); | ||||
|  | ||||
|   /** | ||||
|    * Gets the identifiers of all paths saved in this `AsyncMotionProfileController`. | ||||
|    * | ||||
|    * @return The identifiers of all paths | ||||
|    */ | ||||
|   std::vector<std::string> getPaths(); | ||||
|  | ||||
|   /** | ||||
|    * Executes a path with the given ID. If there is no path matching the ID, the method will | ||||
|    * return. Any targets set while a path is being followed will be ignored. | ||||
|    * | ||||
|    * @param ipathId A unique identifier for the path, previously passed to `generatePath()`. | ||||
|    */ | ||||
|   void setTarget(std::string ipathId) override; | ||||
|  | ||||
|   /** | ||||
|    * Executes a path with the given ID. If there is no path matching the ID, the method will | ||||
|    * return. Any targets set while a path is being followed will be ignored. | ||||
|    * | ||||
|    * @param ipathId A unique identifier for the path, previously passed to `generatePath()`. | ||||
|    * @param ibackwards Whether to follow the profile backwards. | ||||
|    * @param imirrored Whether to follow the profile mirrored. | ||||
|    */ | ||||
|   void setTarget(std::string ipathId, bool ibackwards, bool imirrored = false); | ||||
|  | ||||
|   /** | ||||
|    * Writes the value of the controller output. This method might be automatically called in another | ||||
|    * thread by the controller. This just calls `setTarget()`. | ||||
|    */ | ||||
|   void controllerSet(std::string ivalue) override; | ||||
|  | ||||
|   /** | ||||
|    * Gets the last set target, or the default target if none was set. | ||||
|    * | ||||
|    * @return the last target | ||||
|    */ | ||||
|   std::string getTarget() override; | ||||
|  | ||||
|   /** | ||||
|    * This is overridden to return the current path. | ||||
|    * | ||||
|    * @return The most recent value of the process variable. | ||||
|    */ | ||||
|   std::string getProcessValue() const override; | ||||
|  | ||||
|   /** | ||||
|    * Blocks the current task until the controller has settled. This controller is settled when | ||||
|    * it has finished following a path. If no path is being followed, it is settled. | ||||
|    */ | ||||
|   void waitUntilSettled() override; | ||||
|  | ||||
|   /** | ||||
|    * Generates a new path from the position (typically the current position) to the target and | ||||
|    * blocks until the controller has settled. Does not save the path which was generated. | ||||
|    * | ||||
|    * @param iwaypoints The waypoints to hit on the path. | ||||
|    * @param ibackwards Whether to follow the profile backwards. | ||||
|    * @param imirrored Whether to follow the profile mirrored. | ||||
|    */ | ||||
|   void moveTo(std::initializer_list<PathfinderPoint> iwaypoints, | ||||
|               bool ibackwards = false, | ||||
|               bool imirrored = false); | ||||
|  | ||||
|   /** | ||||
|    * Generates a new path from the position (typically the current position) to the target and | ||||
|    * blocks until the controller has settled. Does not save the path which was generated. | ||||
|    * | ||||
|    * @param iwaypoints The waypoints to hit on the path. | ||||
|    * @param ilimits The limits to use for this path only. | ||||
|    * @param ibackwards Whether to follow the profile backwards. | ||||
|    * @param imirrored Whether to follow the profile mirrored. | ||||
|    */ | ||||
|   void moveTo(std::initializer_list<PathfinderPoint> iwaypoints, | ||||
|               const PathfinderLimits &ilimits, | ||||
|               bool ibackwards = false, | ||||
|               bool imirrored = false); | ||||
|  | ||||
|   /** | ||||
|    * Returns the last error of the controller. Does not update when disabled. This implementation | ||||
|    * always returns zero since the robot is assumed to perfectly follow the path. Subclasses can | ||||
|    * override this to be more accurate using odometry information. | ||||
|    * | ||||
|    * @return the last error | ||||
|    */ | ||||
|   PathfinderPoint getError() const override; | ||||
|  | ||||
|   /** | ||||
|    * Returns whether the controller has settled at the target. Determining what settling means is | ||||
|    * implementation-dependent. | ||||
|    * | ||||
|    * If the controller is disabled, this method must return true. | ||||
|    * | ||||
|    * @return whether the controller is settled | ||||
|    */ | ||||
|   bool isSettled() override; | ||||
|  | ||||
|   /** | ||||
|    * Resets the controller so it can start from 0 again properly. Keeps configuration from | ||||
|    * before. This implementation also stops movement. | ||||
|    */ | ||||
|   void reset() override; | ||||
|  | ||||
|   /** | ||||
|    * Changes whether the controller is off or on. Turning the controller on after it was off will | ||||
|    * NOT cause the controller to move to its last set target. | ||||
|    */ | ||||
|   void flipDisable() override; | ||||
|  | ||||
|   /** | ||||
|    * Sets whether the controller is off or on. Turning the controller on after it was off will | ||||
|    * NOT cause the controller to move to its last set target, unless it was reset in that time. | ||||
|    * | ||||
|    * @param iisDisabled whether the controller is disabled | ||||
|    */ | ||||
|   void flipDisable(bool iisDisabled) override; | ||||
|  | ||||
|   /** | ||||
|    * Returns whether the controller is currently disabled. | ||||
|    * | ||||
|    * @return whether the controller is currently disabled | ||||
|    */ | ||||
|   bool isDisabled() const override; | ||||
|  | ||||
|   /** | ||||
|    * This implementation does nothing because the API always requires the starting position to be | ||||
|    * specified. | ||||
|    */ | ||||
|   void tarePosition() override; | ||||
|  | ||||
|   /** | ||||
|    * This implementation does nothing because the maximum velocity is configured using | ||||
|    * PathfinderLimits elsewhere. | ||||
|    * | ||||
|    * @param imaxVelocity Ignored. | ||||
|    */ | ||||
|   void setMaxVelocity(std::int32_t imaxVelocity) override; | ||||
|  | ||||
|   /** | ||||
|    * Starts the internal thread. This should not be called by normal users. This method is called | ||||
|    * by the `AsyncMotionProfileControllerBuilder` when making a new instance of this class. | ||||
|    */ | ||||
|   void startThread(); | ||||
|  | ||||
|   /** | ||||
|    * @return The underlying thread handle. | ||||
|    */ | ||||
|   CrossplatformThread *getThread() const; | ||||
|  | ||||
|   /** | ||||
|    * Saves a generated path to a file. Paths are stored as `<ipathId>.csv`. An SD card | ||||
|    * must be inserted into the brain and the directory must exist. `idirectory` can be prefixed with | ||||
|    * `/usd/`, but it this is not required. | ||||
|    * | ||||
|    * @param idirectory The directory to store the path file in | ||||
|    * @param ipathId The path ID of the generated path | ||||
|    */ | ||||
|   void storePath(const std::string &idirectory, const std::string &ipathId); | ||||
|  | ||||
|   /** | ||||
|    * Loads a path from a directory on the SD card containing a path CSV file. `/usd/` is | ||||
|    * automatically prepended to `idirectory` if it is not specified. | ||||
|    * | ||||
|    * @param idirectory The directory that the path files are stored in | ||||
|    * @param ipathId The path ID that the paths are stored under (and will be loaded into) | ||||
|    */ | ||||
|   void loadPath(const std::string &idirectory, const std::string &ipathId); | ||||
|  | ||||
|   /** | ||||
|    * Attempts to remove a path without stopping execution. If that fails, disables the controller | ||||
|    * and removes the path. | ||||
|    * | ||||
|    * @param ipathId The path ID that will be removed | ||||
|    */ | ||||
|   void forceRemovePath(const std::string &ipathId); | ||||
|  | ||||
|   protected: | ||||
|   std::shared_ptr<Logger> logger; | ||||
|   std::map<std::string, std::vector<squiggles::ProfilePoint>> paths{}; | ||||
|   PathfinderLimits limits; | ||||
|   std::shared_ptr<ChassisModel> model; | ||||
|   ChassisScales scales; | ||||
|   AbstractMotor::GearsetRatioPair pair; | ||||
|   TimeUtil timeUtil; | ||||
|  | ||||
|   // This must be locked when accessing the current path | ||||
|   CrossplatformMutex currentPathMutex; | ||||
|  | ||||
|   std::string currentPath{""}; | ||||
|   std::atomic_bool isRunning{false}; | ||||
|   std::atomic_int direction{1}; | ||||
|   std::atomic_bool mirrored{false}; | ||||
|   std::atomic_bool disabled{false}; | ||||
|   std::atomic_bool dtorCalled{false}; | ||||
|   CrossplatformThread *task{nullptr}; | ||||
|  | ||||
|   static void trampoline(void *context); | ||||
|   void loop(); | ||||
|  | ||||
|   /** | ||||
|    * Follow the supplied path. Must follow the disabled lifecycle. | ||||
|    */ | ||||
|   virtual void executeSinglePath(const std::vector<squiggles::ProfilePoint> &path, | ||||
|                                  std::unique_ptr<AbstractRate> rate); | ||||
|  | ||||
|   /** | ||||
|    * Converts linear chassis speed to rotational motor speed. | ||||
|    * | ||||
|    * @param linear chassis frame speed | ||||
|    * @return motor frame speed | ||||
|    */ | ||||
|   QAngularSpeed convertLinearToRotational(QSpeed linear) const; | ||||
|  | ||||
|   std::string getPathErrorMessage(const std::vector<PathfinderPoint> &points, | ||||
|                                   const std::string &ipathId, | ||||
|                                   int length); | ||||
|  | ||||
|   /** | ||||
|    * Joins and escapes a directory and file name | ||||
|    * | ||||
|    * @param directory The directory path, separated by forward slashes (/) and with or without a | ||||
|    * trailing slash | ||||
|    * @param filename The file name in the directory | ||||
|    * @return the fully qualified and legal path name | ||||
|    */ | ||||
|   static std::string makeFilePath(const std::string &directory, const std::string &filename); | ||||
|  | ||||
|   void internalStorePath(std::ostream &file, const std::string &ipathId); | ||||
|   void internalLoadPath(std::istream &file, const std::string &ipathId); | ||||
|   void internalLoadPathfinderPath(std::istream &leftFile, | ||||
|                                   std::istream &rightFile, | ||||
|                                   const std::string &ipathId); | ||||
|  | ||||
|   static constexpr double DT = 0.01; | ||||
| }; | ||||
| } // namespace okapi | ||||
| @@ -0,0 +1,145 @@ | ||||
| /* | ||||
|  * This Source Code Form is subject to the terms of the Mozilla Public | ||||
|  * License, v. 2.0. If a copy of the MPL was not distributed with this | ||||
|  * file, You can obtain one at http://mozilla.org/MPL/2.0/. | ||||
|  */ | ||||
| #pragma once | ||||
|  | ||||
| #include "okapi/api/control/async/asyncPositionController.hpp" | ||||
| #include "okapi/api/device/motor/abstractMotor.hpp" | ||||
| #include "okapi/api/util/logging.hpp" | ||||
| #include "okapi/api/util/timeUtil.hpp" | ||||
|  | ||||
| namespace okapi { | ||||
| /** | ||||
|  * Closed-loop controller that uses the V5 motor's onboard control to move. Input units are whatever | ||||
|  * units the motor is in. | ||||
|  */ | ||||
| class AsyncPosIntegratedController : public AsyncPositionController<double, double> { | ||||
|   public: | ||||
|   /** | ||||
|    * Closed-loop controller that uses the V5 motor's onboard control to move. Input units are | ||||
|    * whatever units the motor is in. Throws a std::invalid_argument exception if the gear ratio is | ||||
|    * zero. | ||||
|    * | ||||
|    * @param imotor The motor to control. | ||||
|    * @param ipair The gearset. | ||||
|    * @param imaxVelocity The maximum velocity after gearing. | ||||
|    * @param itimeUtil The TimeUtil. | ||||
|    * @param ilogger The logger this instance will log to. | ||||
|    */ | ||||
|   AsyncPosIntegratedController(const std::shared_ptr<AbstractMotor> &imotor, | ||||
|                                const AbstractMotor::GearsetRatioPair &ipair, | ||||
|                                std::int32_t imaxVelocity, | ||||
|                                const TimeUtil &itimeUtil, | ||||
|                                const std::shared_ptr<Logger> &ilogger = Logger::getDefaultLogger()); | ||||
|  | ||||
|   /** | ||||
|    * Sets the target for the controller. | ||||
|    */ | ||||
|   void setTarget(double itarget) override; | ||||
|  | ||||
|   /** | ||||
|    * Gets the last set target, or the default target if none was set. | ||||
|    * | ||||
|    * @return the last target | ||||
|    */ | ||||
|   double getTarget() override; | ||||
|  | ||||
|   /** | ||||
|    * @return The most recent value of the process variable. | ||||
|    */ | ||||
|   double getProcessValue() const override; | ||||
|  | ||||
|   /** | ||||
|    * Returns the last error of the controller. Does not update when disabled. | ||||
|    */ | ||||
|   double getError() const override; | ||||
|  | ||||
|   /** | ||||
|    * Returns whether the controller has settled at the target. Determining what settling means is | ||||
|    * implementation-dependent. | ||||
|    * | ||||
|    * If the controller is disabled, this method must return true. | ||||
|    * | ||||
|    * @return whether the controller is settled | ||||
|    */ | ||||
|   bool isSettled() override; | ||||
|  | ||||
|   /** | ||||
|    * Resets the controller's internal state so it is similar to when it was first initialized, while | ||||
|    * keeping any user-configured information. | ||||
|    */ | ||||
|   void reset() override; | ||||
|  | ||||
|   /** | ||||
|    * Changes whether the controller is off or on. Turning the controller on after it was off will | ||||
|    * cause the controller to move to its last set target, unless it was reset in that time. | ||||
|    */ | ||||
|   void flipDisable() override; | ||||
|  | ||||
|   /** | ||||
|    * Sets whether the controller is off or on. Turning the controller on after it was off will | ||||
|    * cause the controller to move to its last set target, unless it was reset in that time. | ||||
|    * | ||||
|    * @param iisDisabled whether the controller is disabled | ||||
|    */ | ||||
|   void flipDisable(bool iisDisabled) override; | ||||
|  | ||||
|   /** | ||||
|    * Returns whether the controller is currently disabled. | ||||
|    * | ||||
|    * @return whether the controller is currently disabled | ||||
|    */ | ||||
|   bool isDisabled() const override; | ||||
|  | ||||
|   /** | ||||
|    * Blocks the current task until the controller has settled. Determining what settling means is | ||||
|    * implementation-dependent. | ||||
|    */ | ||||
|   void waitUntilSettled() override; | ||||
|  | ||||
|   /** | ||||
|    * Writes the value of the controller output. This method might be automatically called in another | ||||
|    * thread by the controller. The range of input values is expected to be [-1, 1]. | ||||
|    * | ||||
|    * @param ivalue the controller's output in the range [-1, 1] | ||||
|    */ | ||||
|   void controllerSet(double ivalue) override; | ||||
|  | ||||
|   /** | ||||
|    * Sets the "absolute" zero position of the controller to its current position. | ||||
|    */ | ||||
|   void tarePosition() override; | ||||
|  | ||||
|   /** | ||||
|    * Sets a new maximum velocity in motor RPM [0-600]. | ||||
|    * | ||||
|    * @param imaxVelocity The new maximum velocity in motor RPM [0-600]. | ||||
|    */ | ||||
|   void setMaxVelocity(std::int32_t imaxVelocity) override; | ||||
|  | ||||
|   /** | ||||
|    * Stops the motor mid-movement. Does not change the last set target. | ||||
|    */ | ||||
|   virtual void stop(); | ||||
|  | ||||
|   protected: | ||||
|   std::shared_ptr<Logger> logger; | ||||
|   TimeUtil timeUtil; | ||||
|   std::shared_ptr<AbstractMotor> motor; | ||||
|   AbstractMotor::GearsetRatioPair pair; | ||||
|   std::int32_t maxVelocity; | ||||
|   double lastTarget{0}; | ||||
|   double offset{0}; | ||||
|   bool controllerIsDisabled{false}; | ||||
|   bool hasFirstTarget{false}; | ||||
|   std::unique_ptr<SettledUtil> settledUtil; | ||||
|  | ||||
|   /** | ||||
|    * Resumes moving after the controller is reset. Should not cause movement if the controller is | ||||
|    * turned off, reset, and turned back on. | ||||
|    */ | ||||
|   virtual void resumeMovement(); | ||||
| }; | ||||
| } // namespace okapi | ||||
| @@ -0,0 +1,100 @@ | ||||
| /* | ||||
|  * This Source Code Form is subject to the terms of the Mozilla Public | ||||
|  * License, v. 2.0. If a copy of the MPL was not distributed with this | ||||
|  * file, You can obtain one at http://mozilla.org/MPL/2.0/. | ||||
|  */ | ||||
| #pragma once | ||||
|  | ||||
| #include "okapi/api/control/async/asyncPositionController.hpp" | ||||
| #include "okapi/api/control/async/asyncWrapper.hpp" | ||||
| #include "okapi/api/control/controllerOutput.hpp" | ||||
| #include "okapi/api/control/iterative/iterativePosPidController.hpp" | ||||
| #include "okapi/api/control/offsettableControllerInput.hpp" | ||||
| #include "okapi/api/util/timeUtil.hpp" | ||||
| #include <memory> | ||||
|  | ||||
| namespace okapi { | ||||
| class AsyncPosPIDController : public AsyncWrapper<double, double>, | ||||
|                               public AsyncPositionController<double, double> { | ||||
|   public: | ||||
|   /** | ||||
|    * An async position PID controller. | ||||
|    * | ||||
|    * @param iinput The controller input. Will be turned into an OffsettableControllerInput. | ||||
|    * @param ioutput The controller output. | ||||
|    * @param itimeUtil The TimeUtil. | ||||
|    * @param ikP The proportional gain. | ||||
|    * @param ikI The integral gain. | ||||
|    * @param ikD The derivative gain. | ||||
|    * @param ikBias The controller bias. | ||||
|    * @param iratio Any external gear ratio. | ||||
|    * @param iderivativeFilter The derivative filter. | ||||
|    */ | ||||
|   AsyncPosPIDController( | ||||
|     const std::shared_ptr<ControllerInput<double>> &iinput, | ||||
|     const std::shared_ptr<ControllerOutput<double>> &ioutput, | ||||
|     const TimeUtil &itimeUtil, | ||||
|     double ikP, | ||||
|     double ikI, | ||||
|     double ikD, | ||||
|     double ikBias = 0, | ||||
|     double iratio = 1, | ||||
|     std::unique_ptr<Filter> iderivativeFilter = std::make_unique<PassthroughFilter>(), | ||||
|     const std::shared_ptr<Logger> &ilogger = Logger::getDefaultLogger()); | ||||
|  | ||||
|   /** | ||||
|    * An async position PID controller. | ||||
|    * | ||||
|    * @param iinput The controller input. | ||||
|    * @param ioutput The controller output. | ||||
|    * @param itimeUtil The TimeUtil. | ||||
|    * @param ikP The proportional gain. | ||||
|    * @param ikI The integral gain. | ||||
|    * @param ikD The derivative gain. | ||||
|    * @param ikBias The controller bias. | ||||
|    * @param iratio Any external gear ratio. | ||||
|    * @param iderivativeFilter The derivative filter. | ||||
|    */ | ||||
|   AsyncPosPIDController( | ||||
|     const std::shared_ptr<OffsetableControllerInput> &iinput, | ||||
|     const std::shared_ptr<ControllerOutput<double>> &ioutput, | ||||
|     const TimeUtil &itimeUtil, | ||||
|     double ikP, | ||||
|     double ikI, | ||||
|     double ikD, | ||||
|     double ikBias = 0, | ||||
|     double iratio = 1, | ||||
|     std::unique_ptr<Filter> iderivativeFilter = std::make_unique<PassthroughFilter>(), | ||||
|     const std::shared_ptr<Logger> &ilogger = Logger::getDefaultLogger()); | ||||
|  | ||||
|   /** | ||||
|    * Sets the "absolute" zero position of the controller to its current position. | ||||
|    */ | ||||
|   void tarePosition() override; | ||||
|  | ||||
|   /** | ||||
|    * This implementation does not respect the maximum velocity. | ||||
|    * | ||||
|    * @param imaxVelocity Ignored. | ||||
|    */ | ||||
|   void setMaxVelocity(std::int32_t imaxVelocity) override; | ||||
|  | ||||
|   /** | ||||
|    * Set controller gains. | ||||
|    * | ||||
|    * @param igains The new gains. | ||||
|    */ | ||||
|   void setGains(const IterativePosPIDController::Gains &igains); | ||||
|  | ||||
|   /** | ||||
|    * Gets the current gains. | ||||
|    * | ||||
|    * @return The current gains. | ||||
|    */ | ||||
|   IterativePosPIDController::Gains getGains() const; | ||||
|  | ||||
|   protected: | ||||
|   std::shared_ptr<OffsetableControllerInput> offsettableInput; | ||||
|   std::shared_ptr<IterativePosPIDController> internalController; | ||||
| }; | ||||
| } // namespace okapi | ||||
| @@ -0,0 +1,28 @@ | ||||
| /* | ||||
|  * This Source Code Form is subject to the terms of the Mozilla Public | ||||
|  * License, v. 2.0. If a copy of the MPL was not distributed with this | ||||
|  * file, You can obtain one at http://mozilla.org/MPL/2.0/. | ||||
|  */ | ||||
| #pragma once | ||||
|  | ||||
| #include "okapi/api/control/async/asyncController.hpp" | ||||
| #include <memory> | ||||
|  | ||||
| namespace okapi { | ||||
| template <typename Input, typename Output> | ||||
| class AsyncPositionController : virtual public AsyncController<Input, Output> { | ||||
|   public: | ||||
|   /** | ||||
|    * Sets the "absolute" zero position of the controller to its current position. | ||||
|    */ | ||||
|   virtual void tarePosition() = 0; | ||||
|  | ||||
|   /** | ||||
|    * Sets a new maximum velocity (typically motor RPM [0-600]). The interpretation of the units | ||||
|    * of this velocity and whether it will be respected is implementation-dependent. | ||||
|    * | ||||
|    * @param imaxVelocity The new maximum velocity. | ||||
|    */ | ||||
|   virtual void setMaxVelocity(std::int32_t imaxVelocity) = 0; | ||||
| }; | ||||
| } // namespace okapi | ||||
| @@ -0,0 +1,124 @@ | ||||
| /* | ||||
|  * This Source Code Form is subject to the terms of the Mozilla Public | ||||
|  * License, v. 2.0. If a copy of the MPL was not distributed with this | ||||
|  * file, You can obtain one at http://mozilla.org/MPL/2.0/. | ||||
|  */ | ||||
| #pragma once | ||||
|  | ||||
| #include "okapi/api/control/async/asyncVelocityController.hpp" | ||||
| #include "okapi/api/device/motor/abstractMotor.hpp" | ||||
| #include "okapi/api/util/logging.hpp" | ||||
| #include "okapi/api/util/timeUtil.hpp" | ||||
| #include <memory> | ||||
|  | ||||
| namespace okapi { | ||||
| /** | ||||
|  * Closed-loop controller that uses the V5 motor's onboard control to move. Input units are whatever | ||||
|  * units the motor is in. | ||||
|  */ | ||||
| class AsyncVelIntegratedController : public AsyncVelocityController<double, double> { | ||||
|   public: | ||||
|   /** | ||||
|    * Closed-loop controller that uses the V5 motor's onboard control to move. Input units are | ||||
|    * whatever units the motor is in. Throws a std::invalid_argument exception if the gear ratio is | ||||
|    * zero. | ||||
|    * | ||||
|    * @param imotor The motor to control. | ||||
|    * @param ipair The gearset. | ||||
|    * @param imaxVelocity The maximum velocity after gearing. | ||||
|    * @param itimeUtil The TimeUtil. | ||||
|    * @param ilogger The logger this instance will log to. | ||||
|    */ | ||||
|   AsyncVelIntegratedController(const std::shared_ptr<AbstractMotor> &imotor, | ||||
|                                const AbstractMotor::GearsetRatioPair &ipair, | ||||
|                                std::int32_t imaxVelocity, | ||||
|                                const TimeUtil &itimeUtil, | ||||
|                                const std::shared_ptr<Logger> &ilogger = Logger::getDefaultLogger()); | ||||
|  | ||||
|   /** | ||||
|    * Sets the target for the controller. | ||||
|    */ | ||||
|   void setTarget(double itarget) override; | ||||
|  | ||||
|   /** | ||||
|    * Gets the last set target, or the default target if none was set. | ||||
|    * | ||||
|    * @return the last target | ||||
|    */ | ||||
|   double getTarget() override; | ||||
|  | ||||
|   /** | ||||
|    * @return The most recent value of the process variable. | ||||
|    */ | ||||
|   double getProcessValue() const override; | ||||
|  | ||||
|   /** | ||||
|    * Returns the last error of the controller. Does not update when disabled. | ||||
|    */ | ||||
|   double getError() const override; | ||||
|  | ||||
|   /** | ||||
|    * Returns whether the controller has settled at the target. Determining what settling means is | ||||
|    * implementation-dependent. | ||||
|    * | ||||
|    * If the controller is disabled, this method must return true. | ||||
|    * | ||||
|    * @return whether the controller is settled | ||||
|    */ | ||||
|   bool isSettled() override; | ||||
|  | ||||
|   /** | ||||
|    * Resets the controller's internal state so it is similar to when it was first initialized, while | ||||
|    * keeping any user-configured information. | ||||
|    */ | ||||
|   void reset() override; | ||||
|  | ||||
|   /** | ||||
|    * Changes whether the controller is off or on. Turning the controller on after it was off will | ||||
|    * cause the controller to move to its last set target, unless it was reset in that time. | ||||
|    */ | ||||
|   void flipDisable() override; | ||||
|  | ||||
|   /** | ||||
|    * Sets whether the controller is off or on. Turning the controller on after it was off will | ||||
|    * cause the controller to move to its last set target, unless it was reset in that time. | ||||
|    * | ||||
|    * @param iisDisabled whether the controller is disabled | ||||
|    */ | ||||
|   void flipDisable(bool iisDisabled) override; | ||||
|  | ||||
|   /** | ||||
|    * Returns whether the controller is currently disabled. | ||||
|    * | ||||
|    * @return whether the controller is currently disabled | ||||
|    */ | ||||
|   bool isDisabled() const override; | ||||
|  | ||||
|   /** | ||||
|    * Blocks the current task until the controller has settled. Determining what settling means is | ||||
|    * implementation-dependent. | ||||
|    */ | ||||
|   void waitUntilSettled() override; | ||||
|  | ||||
|   /** | ||||
|    * Writes the value of the controller output. This method might be automatically called in another | ||||
|    * thread by the controller. The range of input values is expected to be [-1, 1]. | ||||
|    * | ||||
|    * @param ivalue the controller's output in the range [-1, 1] | ||||
|    */ | ||||
|   void controllerSet(double ivalue) override; | ||||
|  | ||||
|   protected: | ||||
|   std::shared_ptr<Logger> logger; | ||||
|   TimeUtil timeUtil; | ||||
|   std::shared_ptr<AbstractMotor> motor; | ||||
|   AbstractMotor::GearsetRatioPair pair; | ||||
|   std::int32_t maxVelocity; | ||||
|   double lastTarget = 0; | ||||
|   bool controllerIsDisabled = false; | ||||
|   bool hasFirstTarget = false; | ||||
|   std::unique_ptr<SettledUtil> settledUtil; | ||||
|  | ||||
|   virtual void resumeMovement(); | ||||
| }; | ||||
| } // namespace okapi | ||||
| @@ -0,0 +1,64 @@ | ||||
| /* | ||||
|  * This Source Code Form is subject to the terms of the Mozilla Public | ||||
|  * License, v. 2.0. If a copy of the MPL was not distributed with this | ||||
|  * file, You can obtain one at http://mozilla.org/MPL/2.0/. | ||||
|  */ | ||||
| #pragma once | ||||
|  | ||||
| #include "okapi/api/control/async/asyncVelocityController.hpp" | ||||
| #include "okapi/api/control/async/asyncWrapper.hpp" | ||||
| #include "okapi/api/control/controllerInput.hpp" | ||||
| #include "okapi/api/control/controllerOutput.hpp" | ||||
| #include "okapi/api/control/iterative/iterativeVelPidController.hpp" | ||||
| #include "okapi/api/util/timeUtil.hpp" | ||||
| #include <memory> | ||||
|  | ||||
| namespace okapi { | ||||
| class AsyncVelPIDController : public AsyncWrapper<double, double>, | ||||
|                               public AsyncVelocityController<double, double> { | ||||
|   public: | ||||
|   /** | ||||
|    * An async velocity PID controller. | ||||
|    * | ||||
|    * @param iinput The controller input. | ||||
|    * @param ioutput The controller output. | ||||
|    * @param itimeUtil The TimeUtil. | ||||
|    * @param ikP The proportional gain. | ||||
|    * @param ikD The derivative gain. | ||||
|    * @param ikF The feed-forward gain. | ||||
|    * @param ikSF A feed-forward gain to counteract static friction. | ||||
|    * @param ivelMath The VelMath used for calculating velocity. | ||||
|    * @param iratio Any external gear ratio. | ||||
|    * @param iderivativeFilter The derivative filter. | ||||
|    */ | ||||
|   AsyncVelPIDController( | ||||
|     const std::shared_ptr<ControllerInput<double>> &iinput, | ||||
|     const std::shared_ptr<ControllerOutput<double>> &ioutput, | ||||
|     const TimeUtil &itimeUtil, | ||||
|     double ikP, | ||||
|     double ikD, | ||||
|     double ikF, | ||||
|     double ikSF, | ||||
|     std::unique_ptr<VelMath> ivelMath, | ||||
|     double iratio = 1, | ||||
|     std::unique_ptr<Filter> iderivativeFilter = std::make_unique<PassthroughFilter>(), | ||||
|     const std::shared_ptr<Logger> &ilogger = Logger::getDefaultLogger()); | ||||
|  | ||||
|   /** | ||||
|    * Set controller gains. | ||||
|    * | ||||
|    * @param igains The new gains. | ||||
|    */ | ||||
|   void setGains(const IterativeVelPIDController::Gains &igains); | ||||
|  | ||||
|   /** | ||||
|    * Gets the current gains. | ||||
|    * | ||||
|    * @return The current gains. | ||||
|    */ | ||||
|   IterativeVelPIDController::Gains getGains() const; | ||||
|  | ||||
|   protected: | ||||
|   std::shared_ptr<IterativeVelPIDController> internalController; | ||||
| }; | ||||
| } // namespace okapi | ||||
| @@ -0,0 +1,14 @@ | ||||
| /* | ||||
|  * This Source Code Form is subject to the terms of the Mozilla Public | ||||
|  * License, v. 2.0. If a copy of the MPL was not distributed with this | ||||
|  * file, You can obtain one at http://mozilla.org/MPL/2.0/. | ||||
|  */ | ||||
| #pragma once | ||||
|  | ||||
| #include "okapi/api/control/async/asyncController.hpp" | ||||
| #include <memory> | ||||
|  | ||||
| namespace okapi { | ||||
| template <typename Input, typename Output> | ||||
| class AsyncVelocityController : virtual public AsyncController<Input, Output> {}; | ||||
| } // namespace okapi | ||||
							
								
								
									
										287
									
								
								SerialTest/include/okapi/api/control/async/asyncWrapper.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										287
									
								
								SerialTest/include/okapi/api/control/async/asyncWrapper.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,287 @@ | ||||
| /* | ||||
|  * This Source Code Form is subject to the terms of the Mozilla Public | ||||
|  * License, v. 2.0. If a copy of the MPL was not distributed with this | ||||
|  * file, You can obtain one at http://mozilla.org/MPL/2.0/. | ||||
|  */ | ||||
| #pragma once | ||||
|  | ||||
| #include "okapi/api/control/async/asyncController.hpp" | ||||
| #include "okapi/api/control/controllerInput.hpp" | ||||
| #include "okapi/api/control/iterative/iterativeController.hpp" | ||||
| #include "okapi/api/control/util/settledUtil.hpp" | ||||
| #include "okapi/api/coreProsAPI.hpp" | ||||
| #include "okapi/api/util/abstractRate.hpp" | ||||
| #include "okapi/api/util/logging.hpp" | ||||
| #include "okapi/api/util/mathUtil.hpp" | ||||
| #include "okapi/api/util/supplier.hpp" | ||||
| #include <atomic> | ||||
| #include <memory> | ||||
|  | ||||
| namespace okapi { | ||||
| template <typename Input, typename Output> | ||||
| class AsyncWrapper : virtual public AsyncController<Input, Output> { | ||||
|   public: | ||||
|   /** | ||||
|    * A wrapper class that transforms an `IterativeController` into an `AsyncController` by running | ||||
|    * it in another task. The input controller will act like an `AsyncController`. | ||||
|    * | ||||
|    * @param iinput controller input, passed to the `IterativeController` | ||||
|    * @param ioutput controller output, written to from the `IterativeController` | ||||
|    * @param icontroller the controller to use | ||||
|    * @param irateSupplier used for rates used in the main loop and in `waitUntilSettled` | ||||
|    * @param iratio Any external gear ratio. | ||||
|    * @param ilogger The logger this instance will log to. | ||||
|    */ | ||||
|   AsyncWrapper(const std::shared_ptr<ControllerInput<Input>> &iinput, | ||||
|                const std::shared_ptr<ControllerOutput<Output>> &ioutput, | ||||
|                const std::shared_ptr<IterativeController<Input, Output>> &icontroller, | ||||
|                const Supplier<std::unique_ptr<AbstractRate>> &irateSupplier, | ||||
|                const double iratio = 1, | ||||
|                std::shared_ptr<Logger> ilogger = Logger::getDefaultLogger()) | ||||
|     : logger(std::move(ilogger)), | ||||
|       rateSupplier(irateSupplier), | ||||
|       input(iinput), | ||||
|       output(ioutput), | ||||
|       controller(icontroller), | ||||
|       ratio(iratio) { | ||||
|   } | ||||
|  | ||||
|   AsyncWrapper(AsyncWrapper<Input, Output> &&other) = delete; | ||||
|  | ||||
|   AsyncWrapper<Input, Output> &operator=(AsyncWrapper<Input, Output> &&other) = delete; | ||||
|  | ||||
|   ~AsyncWrapper() override { | ||||
|     dtorCalled.store(true, std::memory_order_release); | ||||
|     delete task; | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * Sets the target for the controller. | ||||
|    */ | ||||
|   void setTarget(const Input itarget) override { | ||||
|     LOG_INFO("AsyncWrapper: Set target to " + std::to_string(itarget)); | ||||
|     hasFirstTarget = true; | ||||
|     controller->setTarget(itarget * ratio); | ||||
|     lastTarget = itarget; | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * Writes the value of the controller output. This method might be automatically called in another | ||||
|    * thread by the controller. | ||||
|    * | ||||
|    * @param ivalue the controller's output | ||||
|    */ | ||||
|   void controllerSet(const Input ivalue) override { | ||||
|     controller->controllerSet(ivalue); | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * Gets the last set target, or the default target if none was set. | ||||
|    * | ||||
|    * @return the last target | ||||
|    */ | ||||
|   Input getTarget() override { | ||||
|     return controller->getTarget(); | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * @return The most recent value of the process variable. | ||||
|    */ | ||||
|   Input getProcessValue() const override { | ||||
|     return controller->getProcessValue(); | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * Returns the last calculated output of the controller. | ||||
|    */ | ||||
|   Output getOutput() const { | ||||
|     return controller->getOutput(); | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * Returns the last error of the controller. Does not update when disabled. | ||||
|    */ | ||||
|   Output getError() const override { | ||||
|     return controller->getError(); | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * Returns whether the controller has settled at the target. Determining what settling means is | ||||
|    * implementation-dependent. | ||||
|    * | ||||
|    * If the controller is disabled, this method must return true. | ||||
|    * | ||||
|    * @return whether the controller is settled | ||||
|    */ | ||||
|   bool isSettled() override { | ||||
|     return isDisabled() || controller->isSettled(); | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * Set time between loops. | ||||
|    * | ||||
|    * @param isampleTime time between loops | ||||
|    */ | ||||
|   void setSampleTime(const QTime &isampleTime) { | ||||
|     controller->setSampleTime(isampleTime); | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * Set controller output bounds. | ||||
|    * | ||||
|    * @param imax max output | ||||
|    * @param imin min output | ||||
|    */ | ||||
|   void setOutputLimits(const Output imax, const Output imin) { | ||||
|     controller->setOutputLimits(imax, imin); | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * Sets the (soft) limits for the target range that controllerSet() scales into. The target | ||||
|    * computed by controllerSet() is scaled into the range [-itargetMin, itargetMax]. | ||||
|    * | ||||
|    * @param itargetMax The new max target for controllerSet(). | ||||
|    * @param itargetMin The new min target for controllerSet(). | ||||
|    */ | ||||
|   void setControllerSetTargetLimits(double itargetMax, double itargetMin) { | ||||
|     controller->setControllerSetTargetLimits(itargetMax, itargetMin); | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * Get the upper output bound. | ||||
|    * | ||||
|    * @return  the upper output bound | ||||
|    */ | ||||
|   Output getMaxOutput() { | ||||
|     return controller->getMaxOutput(); | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * Get the lower output bound. | ||||
|    * | ||||
|    * @return the lower output bound | ||||
|    */ | ||||
|   Output getMinOutput() { | ||||
|     return controller->getMinOutput(); | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * Resets the controller's internal state so it is similar to when it was first initialized, while | ||||
|    * keeping any user-configured information. | ||||
|    */ | ||||
|   void reset() override { | ||||
|     LOG_INFO_S("AsyncWrapper: Reset"); | ||||
|     controller->reset(); | ||||
|     hasFirstTarget = false; | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * Changes whether the controller is off or on. Turning the controller on after it was off will | ||||
|    * cause the controller to move to its last set target, unless it was reset in that time. | ||||
|    */ | ||||
|   void flipDisable() override { | ||||
|     LOG_INFO("AsyncWrapper: flipDisable " + std::to_string(!controller->isDisabled())); | ||||
|     controller->flipDisable(); | ||||
|     resumeMovement(); | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * Sets whether the controller is off or on. Turning the controller on after it was off will | ||||
|    * cause the controller to move to its last set target, unless it was reset in that time. | ||||
|    * | ||||
|    * @param iisDisabled whether the controller is disabled | ||||
|    */ | ||||
|   void flipDisable(const bool iisDisabled) override { | ||||
|     LOG_INFO("AsyncWrapper: flipDisable " + std::to_string(iisDisabled)); | ||||
|     controller->flipDisable(iisDisabled); | ||||
|     resumeMovement(); | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * Returns whether the controller is currently disabled. | ||||
|    * | ||||
|    * @return whether the controller is currently disabled | ||||
|    */ | ||||
|   bool isDisabled() const override { | ||||
|     return controller->isDisabled(); | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * Blocks the current task until the controller has settled. Determining what settling means is | ||||
|    * implementation-dependent. | ||||
|    */ | ||||
|   void waitUntilSettled() override { | ||||
|     LOG_INFO_S("AsyncWrapper: Waiting to settle"); | ||||
|  | ||||
|     auto rate = rateSupplier.get(); | ||||
|     while (!isSettled()) { | ||||
|       rate->delayUntil(motorUpdateRate); | ||||
|     } | ||||
|  | ||||
|     LOG_INFO_S("AsyncWrapper: Done waiting to settle"); | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * Starts the internal thread. This should not be called by normal users. This method is called | ||||
|    * by the AsyncControllerFactory when making a new instance of this class. | ||||
|    */ | ||||
|   void startThread() { | ||||
|     if (!task) { | ||||
|       task = new CrossplatformThread(trampoline, this, "AsyncWrapper"); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * Returns the underlying thread handle. | ||||
|    * | ||||
|    * @return The underlying thread handle. | ||||
|    */ | ||||
|   CrossplatformThread *getThread() const { | ||||
|     return task; | ||||
|   } | ||||
|  | ||||
|   protected: | ||||
|   std::shared_ptr<Logger> logger; | ||||
|   Supplier<std::unique_ptr<AbstractRate>> rateSupplier; | ||||
|   std::shared_ptr<ControllerInput<Input>> input; | ||||
|   std::shared_ptr<ControllerOutput<Output>> output; | ||||
|   std::shared_ptr<IterativeController<Input, Output>> controller; | ||||
|   bool hasFirstTarget{false}; | ||||
|   Input lastTarget; | ||||
|   double ratio; | ||||
|   std::atomic_bool dtorCalled{false}; | ||||
|   CrossplatformThread *task{nullptr}; | ||||
|  | ||||
|   static void trampoline(void *context) { | ||||
|     if (context) { | ||||
|       static_cast<AsyncWrapper *>(context)->loop(); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   void loop() { | ||||
|     auto rate = rateSupplier.get(); | ||||
|     while (!dtorCalled.load(std::memory_order_acquire) && !task->notifyTake(0)) { | ||||
|       if (!isDisabled()) { | ||||
|         output->controllerSet(controller->step(input->controllerGet())); | ||||
|       } | ||||
|  | ||||
|       rate->delayUntil(controller->getSampleTime()); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * Resumes moving after the controller is reset. Should not cause movement if the controller is | ||||
|    * turned off, reset, and turned back on. | ||||
|    */ | ||||
|   virtual void resumeMovement() { | ||||
|     if (isDisabled()) { | ||||
|       // This will grab the output *when disabled* | ||||
|       output->controllerSet(controller->getOutput()); | ||||
|     } else { | ||||
|       if (hasFirstTarget) { | ||||
|         setTarget(lastTarget); | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| }; | ||||
| } // namespace okapi | ||||
| @@ -0,0 +1,86 @@ | ||||
| /* | ||||
|  * This Source Code Form is subject to the terms of the Mozilla Public | ||||
|  * License, v. 2.0. If a copy of the MPL was not distributed with this | ||||
|  * file, You can obtain one at http://mozilla.org/MPL/2.0/. | ||||
|  */ | ||||
| #pragma once | ||||
|  | ||||
| #include "okapi/api/control/controllerOutput.hpp" | ||||
| #include "okapi/api/units/QTime.hpp" | ||||
|  | ||||
| namespace okapi { | ||||
| /** | ||||
|  * An abstract closed-loop controller. | ||||
|  * | ||||
|  * @tparam Input The target/input type. | ||||
|  * @tparam Output The error/output type. | ||||
|  */ | ||||
| template <typename Input, typename Output> | ||||
| class ClosedLoopController : public ControllerOutput<Input> { | ||||
|   public: | ||||
|   virtual ~ClosedLoopController() = default; | ||||
|  | ||||
|   /** | ||||
|    * Sets the target for the controller. | ||||
|    * | ||||
|    * @param itarget the new target | ||||
|    */ | ||||
|   virtual void setTarget(Input itarget) = 0; | ||||
|  | ||||
|   /** | ||||
|    * Gets the last set target, or the default target if none was set. | ||||
|    * | ||||
|    * @return the last target | ||||
|    */ | ||||
|   virtual Input getTarget() = 0; | ||||
|  | ||||
|   /** | ||||
|    * @return The most recent value of the process variable. | ||||
|    */ | ||||
|   virtual Input getProcessValue() const = 0; | ||||
|  | ||||
|   /** | ||||
|    * Returns the last error of the controller. Does not update when disabled. | ||||
|    * | ||||
|    * @return the last error | ||||
|    */ | ||||
|   virtual Output getError() const = 0; | ||||
|  | ||||
|   /** | ||||
|    * Returns whether the controller has settled at the target. Determining what settling means is | ||||
|    * implementation-dependent. | ||||
|    * | ||||
|    * If the controller is disabled, this method must return `true`. | ||||
|    * | ||||
|    * @return whether the controller is settled | ||||
|    */ | ||||
|   virtual bool isSettled() = 0; | ||||
|  | ||||
|   /** | ||||
|    * Resets the controller's internal state so it is similar to when it was first initialized, while | ||||
|    * keeping any user-configured information. | ||||
|    */ | ||||
|   virtual void reset() = 0; | ||||
|  | ||||
|   /** | ||||
|    * Changes whether the controller is off or on. Turning the controller on after it was off will | ||||
|    * cause the controller to move to its last set target, unless it was reset in that time. | ||||
|    */ | ||||
|   virtual void flipDisable() = 0; | ||||
|  | ||||
|   /** | ||||
|    * Sets whether the controller is off or on. Turning the controller on after it was off will | ||||
|    * cause the controller to move to its last set target, unless it was reset in that time. | ||||
|    * | ||||
|    * @param iisDisabled whether the controller is disabled | ||||
|    */ | ||||
|   virtual void flipDisable(bool iisDisabled) = 0; | ||||
|  | ||||
|   /** | ||||
|    * Returns whether the controller is currently disabled. | ||||
|    * | ||||
|    * @return whether the controller is currently disabled | ||||
|    */ | ||||
|   virtual bool isDisabled() const = 0; | ||||
| }; | ||||
| } // namespace okapi | ||||
							
								
								
									
										19
									
								
								SerialTest/include/okapi/api/control/controllerInput.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								SerialTest/include/okapi/api/control/controllerInput.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,19 @@ | ||||
| /* | ||||
|  * This Source Code Form is subject to the terms of the Mozilla Public | ||||
|  * License, v. 2.0. If a copy of the MPL was not distributed with this | ||||
|  * file, You can obtain one at http://mozilla.org/MPL/2.0/. | ||||
|  */ | ||||
| #pragma once | ||||
|  | ||||
| namespace okapi { | ||||
| template <typename T> class ControllerInput { | ||||
|   public: | ||||
|   /** | ||||
|    * Get the sensor value for use in a control loop. This method might be automatically called in | ||||
|    * another thread by the controller. | ||||
|    * | ||||
|    * @return the current sensor value, or ``PROS_ERR`` on a failure. | ||||
|    */ | ||||
|   virtual T controllerGet() = 0; | ||||
| }; | ||||
| } // namespace okapi | ||||
							
								
								
									
										19
									
								
								SerialTest/include/okapi/api/control/controllerOutput.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								SerialTest/include/okapi/api/control/controllerOutput.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,19 @@ | ||||
| /* | ||||
|  * This Source Code Form is subject to the terms of the Mozilla Public | ||||
|  * License, v. 2.0. If a copy of the MPL was not distributed with this | ||||
|  * file, You can obtain one at http://mozilla.org/MPL/2.0/. | ||||
|  */ | ||||
| #pragma once | ||||
|  | ||||
| namespace okapi { | ||||
| template <typename T> class ControllerOutput { | ||||
|   public: | ||||
|   /** | ||||
|    * Writes the value of the controller output. This method might be automatically called in another | ||||
|    * thread by the controller. The range of input values is expected to be `[-1, 1]`. | ||||
|    * | ||||
|    * @param ivalue the controller's output in the range `[-1, 1]` | ||||
|    */ | ||||
|   virtual void controllerSet(T ivalue) = 0; | ||||
| }; | ||||
| } // namespace okapi | ||||
| @@ -0,0 +1,79 @@ | ||||
| /* | ||||
|  * This Source Code Form is subject to the terms of the Mozilla Public | ||||
|  * License, v. 2.0. If a copy of the MPL was not distributed with this | ||||
|  * file, You can obtain one at http://mozilla.org/MPL/2.0/. | ||||
|  */ | ||||
| #pragma once | ||||
|  | ||||
| #include "okapi/api/control/closedLoopController.hpp" | ||||
| #include "okapi/api/units/QTime.hpp" | ||||
|  | ||||
| namespace okapi { | ||||
| /** | ||||
|  * Closed-loop controller that steps iteratively using the step method below. | ||||
|  * | ||||
|  * `ControllerOutput::controllerSet()` should set the controller's target to the input scaled by | ||||
|  * the output bounds. | ||||
|  */ | ||||
| template <typename Input, typename Output> | ||||
| class IterativeController : public ClosedLoopController<Input, Output> { | ||||
|   public: | ||||
|   /** | ||||
|    * Do one iteration of the controller. | ||||
|    * | ||||
|    * @param ireading A new measurement. | ||||
|    * @return The controller output. | ||||
|    */ | ||||
|   virtual Output step(Input ireading) = 0; | ||||
|  | ||||
|   /** | ||||
|    * Returns the last calculated output of the controller. | ||||
|    */ | ||||
|   virtual Output getOutput() const = 0; | ||||
|  | ||||
|   /** | ||||
|    * Set controller output bounds. | ||||
|    * | ||||
|    * @param imax max output | ||||
|    * @param imin min output | ||||
|    */ | ||||
|   virtual void setOutputLimits(Output imax, Output imin) = 0; | ||||
|  | ||||
|   /** | ||||
|    * Sets the (soft) limits for the target range that controllerSet() scales into. The target | ||||
|    * computed by `controllerSet()` is scaled into the range `[-itargetMin, itargetMax]`. | ||||
|    * | ||||
|    * @param itargetMax The new max target for `controllerSet()`. | ||||
|    * @param itargetMin The new min target for `controllerSet()`. | ||||
|    */ | ||||
|   virtual void setControllerSetTargetLimits(Output itargetMax, Output itargetMin) = 0; | ||||
|  | ||||
|   /** | ||||
|    * Get the upper output bound. | ||||
|    * | ||||
|    * @return  the upper output bound | ||||
|    */ | ||||
|   virtual Output getMaxOutput() = 0; | ||||
|  | ||||
|   /** | ||||
|    * Get the lower output bound. | ||||
|    * | ||||
|    * @return the lower output bound | ||||
|    */ | ||||
|   virtual Output getMinOutput() = 0; | ||||
|  | ||||
|   /** | ||||
|    * Set time between loops. | ||||
|    * | ||||
|    * @param isampleTime time between loops | ||||
|    */ | ||||
|   virtual void setSampleTime(QTime isampleTime) = 0; | ||||
|  | ||||
|   /** | ||||
|    * Get the last set sample time. | ||||
|    * | ||||
|    * @return sample time | ||||
|    */ | ||||
|   virtual QTime getSampleTime() const = 0; | ||||
| }; | ||||
| } // namespace okapi | ||||
| @@ -0,0 +1,150 @@ | ||||
| /* | ||||
|  * This Source Code Form is subject to the terms of the Mozilla Public | ||||
|  * License, v. 2.0. If a copy of the MPL was not distributed with this | ||||
|  * file, You can obtain one at http://mozilla.org/MPL/2.0/. | ||||
|  */ | ||||
| #pragma once | ||||
|  | ||||
| #include "okapi/api/control/iterative/iterativeVelocityController.hpp" | ||||
| #include "okapi/api/device/motor/abstractMotor.hpp" | ||||
| #include <array> | ||||
| #include <memory> | ||||
|  | ||||
| namespace okapi { | ||||
| class IterativeMotorVelocityController : public IterativeVelocityController<double, double> { | ||||
|   public: | ||||
|   /** | ||||
|    * Velocity controller that automatically writes to the motor. | ||||
|    */ | ||||
|   IterativeMotorVelocityController( | ||||
|     const std::shared_ptr<AbstractMotor> &imotor, | ||||
|     const std::shared_ptr<IterativeVelocityController<double, double>> &icontroller); | ||||
|  | ||||
|   /** | ||||
|    * Do one iteration of the controller. | ||||
|    * | ||||
|    * @param inewReading new measurement | ||||
|    * @return controller output | ||||
|    */ | ||||
|   double step(double ireading) override; | ||||
|  | ||||
|   /** | ||||
|    * Sets the target for the controller. | ||||
|    */ | ||||
|   void setTarget(double itarget) override; | ||||
|  | ||||
|   /** | ||||
|    * Writes the value of the controller output. This method might be automatically called in another | ||||
|    * thread by the controller. The range of input values is expected to be `[-1, 1]`. | ||||
|    * | ||||
|    * @param ivalue the controller's output in the range `[-1, 1]` | ||||
|    */ | ||||
|   void controllerSet(double ivalue) override; | ||||
|  | ||||
|   /** | ||||
|    * Gets the last set target, or the default target if none was set. | ||||
|    * | ||||
|    * @return the last target | ||||
|    */ | ||||
|   double getTarget() override; | ||||
|  | ||||
|   /** | ||||
|    * @return The most recent value of the process variable. | ||||
|    */ | ||||
|   double getProcessValue() const override; | ||||
|  | ||||
|   /** | ||||
|    * Returns the last calculated output of the controller. | ||||
|    */ | ||||
|   double getOutput() const override; | ||||
|  | ||||
|   /** | ||||
|    * Get the upper output bound. | ||||
|    * | ||||
|    * @return  the upper output bound | ||||
|    */ | ||||
|   double getMaxOutput() override; | ||||
|  | ||||
|   /** | ||||
|    * Get the lower output bound. | ||||
|    * | ||||
|    * @return the lower output bound | ||||
|    */ | ||||
|   double getMinOutput() override; | ||||
|  | ||||
|   /** | ||||
|    * Returns the last error of the controller. Does not update when disabled. | ||||
|    */ | ||||
|   double getError() const override; | ||||
|  | ||||
|   /** | ||||
|    * Returns whether the controller has settled at the target. Determining what settling means is | ||||
|    * implementation-dependent. | ||||
|    * | ||||
|    * @return whether the controller is settled | ||||
|    */ | ||||
|   bool isSettled() override; | ||||
|  | ||||
|   /** | ||||
|    * Set time between loops in ms. | ||||
|    * | ||||
|    * @param isampleTime time between loops in ms | ||||
|    */ | ||||
|   void setSampleTime(QTime isampleTime) override; | ||||
|  | ||||
|   /** | ||||
|    * Set controller output bounds. | ||||
|    * | ||||
|    * @param imax max output | ||||
|    * @param imin min output | ||||
|    */ | ||||
|   void setOutputLimits(double imax, double imin) override; | ||||
|  | ||||
|   /** | ||||
|    * Sets the (soft) limits for the target range that controllerSet() scales into. The target | ||||
|    * computed by controllerSet() is scaled into the range [-itargetMin, itargetMax]. | ||||
|    * | ||||
|    * @param itargetMax The new max target for controllerSet(). | ||||
|    * @param itargetMin The new min target for controllerSet(). | ||||
|    */ | ||||
|   void setControllerSetTargetLimits(double itargetMax, double itargetMin) override; | ||||
|  | ||||
|   /** | ||||
|    * Resets the controller's internal state so it is similar to when it was first initialized, while | ||||
|    * keeping any user-configured information. | ||||
|    */ | ||||
|   void reset() override; | ||||
|  | ||||
|   /** | ||||
|    * Changes whether the controller is off or on. Turning the controller on after it was off will | ||||
|    * cause the controller to move to its last set target, unless it was reset in that time. | ||||
|    */ | ||||
|   void flipDisable() override; | ||||
|  | ||||
|   /** | ||||
|    * Sets whether the controller is off or on. Turning the controller on after it was off will | ||||
|    * cause the controller to move to its last set target, unless it was reset in that time. | ||||
|    * | ||||
|    * @param iisDisabled whether the controller is disabled | ||||
|    */ | ||||
|   void flipDisable(bool iisDisabled) override; | ||||
|  | ||||
|   /** | ||||
|    * Returns whether the controller is currently disabled. | ||||
|    * | ||||
|    * @return whether the controller is currently disabled | ||||
|    */ | ||||
|   bool isDisabled() const override; | ||||
|  | ||||
|   /** | ||||
|    * Get the last set sample time. | ||||
|    * | ||||
|    * @return sample time | ||||
|    */ | ||||
|   QTime getSampleTime() const override; | ||||
|  | ||||
|   protected: | ||||
|   std::shared_ptr<AbstractMotor> motor; | ||||
|   std::shared_ptr<IterativeVelocityController<double, double>> controller; | ||||
| }; | ||||
| } // namespace okapi | ||||
| @@ -0,0 +1,276 @@ | ||||
| /* | ||||
|  * Based on the Arduino PID controller: https://github.com/br3ttb/Arduino-PID-Library | ||||
|  * | ||||
|  * This Source Code Form is subject to the terms of the Mozilla Public | ||||
|  * License, v. 2.0. If a copy of the MPL was not distributed with this | ||||
|  * file, You can obtain one at http://mozilla.org/MPL/2.0/. | ||||
|  */ | ||||
| #pragma once | ||||
|  | ||||
| #include "okapi/api/control/iterative/iterativePositionController.hpp" | ||||
| #include "okapi/api/control/util/settledUtil.hpp" | ||||
| #include "okapi/api/filter/filter.hpp" | ||||
| #include "okapi/api/filter/passthroughFilter.hpp" | ||||
| #include "okapi/api/util/logging.hpp" | ||||
| #include "okapi/api/util/timeUtil.hpp" | ||||
| #include <limits> | ||||
| #include <memory> | ||||
|  | ||||
| namespace okapi { | ||||
| class IterativePosPIDController : public IterativePositionController<double, double> { | ||||
|   public: | ||||
|   struct Gains { | ||||
|     double kP{0}; | ||||
|     double kI{0}; | ||||
|     double kD{0}; | ||||
|     double kBias{0}; | ||||
|  | ||||
|     bool operator==(const Gains &rhs) const; | ||||
|     bool operator!=(const Gains &rhs) const; | ||||
|   }; | ||||
|  | ||||
|   /** | ||||
|    * Position PID controller. | ||||
|    * | ||||
|    * @param ikP the proportional gain | ||||
|    * @param ikI the integration gain | ||||
|    * @param ikD the derivative gain | ||||
|    * @param ikBias the controller bias | ||||
|    * @param itimeUtil see TimeUtil docs | ||||
|    * @param iderivativeFilter a filter for filtering the derivative term | ||||
|    * @param ilogger The logger this instance will log to. | ||||
|    */ | ||||
|   IterativePosPIDController( | ||||
|     double ikP, | ||||
|     double ikI, | ||||
|     double ikD, | ||||
|     double ikBias, | ||||
|     const TimeUtil &itimeUtil, | ||||
|     std::unique_ptr<Filter> iderivativeFilter = std::make_unique<PassthroughFilter>(), | ||||
|     std::shared_ptr<Logger> ilogger = Logger::getDefaultLogger()); | ||||
|  | ||||
|   /** | ||||
|    * Position PID controller. | ||||
|    * | ||||
|    * @param igains the controller gains | ||||
|    * @param itimeUtil see TimeUtil docs | ||||
|    * @param iderivativeFilter a filter for filtering the derivative term | ||||
|    */ | ||||
|   IterativePosPIDController( | ||||
|     const Gains &igains, | ||||
|     const TimeUtil &itimeUtil, | ||||
|     std::unique_ptr<Filter> iderivativeFilter = std::make_unique<PassthroughFilter>(), | ||||
|     std::shared_ptr<Logger> ilogger = Logger::getDefaultLogger()); | ||||
|  | ||||
|   /** | ||||
|    * Do one iteration of the controller. Returns the reading in the range [-1, 1] unless the | ||||
|    * bounds have been changed with setOutputLimits(). | ||||
|    * | ||||
|    * @param inewReading new measurement | ||||
|    * @return controller output | ||||
|    */ | ||||
|   double step(double inewReading) override; | ||||
|  | ||||
|   /** | ||||
|    * Sets the target for the controller. | ||||
|    * | ||||
|    * @param itarget new target position | ||||
|    */ | ||||
|   void setTarget(double itarget) override; | ||||
|  | ||||
|   /** | ||||
|    * Writes the value of the controller output. This method might be automatically called in another | ||||
|    * thread by the controller. The range of input values is expected to be [-1, 1]. | ||||
|    * | ||||
|    * @param ivalue the controller's output in the range [-1, 1] | ||||
|    */ | ||||
|   void controllerSet(double ivalue) override; | ||||
|  | ||||
|   /** | ||||
|    * Gets the last set target, or the default target if none was set. | ||||
|    * | ||||
|    * @return the last target | ||||
|    */ | ||||
|   double getTarget() override; | ||||
|  | ||||
|   /** | ||||
|    * Gets the last set target, or the default target if none was set. | ||||
|    * | ||||
|    * @return the last target | ||||
|    */ | ||||
|   double getTarget() const; | ||||
|  | ||||
|   /** | ||||
|    * @return The most recent value of the process variable. | ||||
|    */ | ||||
|   double getProcessValue() const override; | ||||
|  | ||||
|   /** | ||||
|    * Returns the last calculated output of the controller. Output is in the range [-1, 1] | ||||
|    * unless the bounds have been changed with setOutputLimits(). | ||||
|    */ | ||||
|   double getOutput() const override; | ||||
|  | ||||
|   /** | ||||
|    * Get the upper output bound. | ||||
|    * | ||||
|    * @return  the upper output bound | ||||
|    */ | ||||
|   double getMaxOutput() override; | ||||
|  | ||||
|   /** | ||||
|    * Get the lower output bound. | ||||
|    * | ||||
|    * @return the lower output bound | ||||
|    */ | ||||
|   double getMinOutput() override; | ||||
|  | ||||
|   /** | ||||
|    * Returns the last error of the controller. Does not update when disabled. | ||||
|    */ | ||||
|   double getError() const override; | ||||
|  | ||||
|   /** | ||||
|    * Returns whether the controller has settled at the target. Determining what settling means is | ||||
|    * implementation-dependent. | ||||
|    * | ||||
|    * If the controller is disabled, this method must return true. | ||||
|    * | ||||
|    * @return whether the controller is settled | ||||
|    */ | ||||
|   bool isSettled() override; | ||||
|  | ||||
|   /** | ||||
|    * Set time between loops in ms. | ||||
|    * | ||||
|    * @param isampleTime time between loops | ||||
|    */ | ||||
|   void setSampleTime(QTime isampleTime) override; | ||||
|  | ||||
|   /** | ||||
|    * Set controller output bounds. Default bounds are [-1, 1]. | ||||
|    * | ||||
|    * @param imax max output | ||||
|    * @param imin min output | ||||
|    */ | ||||
|   void setOutputLimits(double imax, double imin) override; | ||||
|  | ||||
|   /** | ||||
|    * Sets the (soft) limits for the target range that controllerSet() scales into. The target | ||||
|    * computed by controllerSet() is scaled into the range [-itargetMin, itargetMax]. | ||||
|    * | ||||
|    * @param itargetMax The new max target for controllerSet(). | ||||
|    * @param itargetMin The new min target for controllerSet(). | ||||
|    */ | ||||
|   void setControllerSetTargetLimits(double itargetMax, double itargetMin) override; | ||||
|  | ||||
|   /** | ||||
|    * Resets the controller's internal state so it is similar to when it was first initialized, while | ||||
|    * keeping any user-configured information. | ||||
|    */ | ||||
|   void reset() override; | ||||
|  | ||||
|   /** | ||||
|    * Changes whether the controller is off or on. Turning the controller on after it was off will | ||||
|    * cause the controller to move to its last set target, unless it was reset in that time. | ||||
|    */ | ||||
|   void flipDisable() override; | ||||
|  | ||||
|   /** | ||||
|    * Sets whether the controller is off or on. Turning the controller on after it was off will | ||||
|    * cause the controller to move to its last set target, unless it was reset in that time. | ||||
|    * | ||||
|    * @param iisDisabled whether the controller is disabled | ||||
|    */ | ||||
|   void flipDisable(bool iisDisabled) override; | ||||
|  | ||||
|   /** | ||||
|    * Returns whether the controller is currently disabled. | ||||
|    * | ||||
|    * @return whether the controller is currently disabled | ||||
|    */ | ||||
|   bool isDisabled() const override; | ||||
|  | ||||
|   /** | ||||
|    * Get the last set sample time. | ||||
|    * | ||||
|    * @return sample time | ||||
|    */ | ||||
|   QTime getSampleTime() const override; | ||||
|  | ||||
|   /** | ||||
|    * Set integrator bounds. Default bounds are [-1, 1]. | ||||
|    * | ||||
|    * @param imax max integrator value | ||||
|    * @param imin min integrator value | ||||
|    */ | ||||
|   virtual void setIntegralLimits(double imax, double imin); | ||||
|  | ||||
|   /** | ||||
|    * Set the error sum bounds. Default bounds are [0, std::numeric_limits<double>::max()]. Error | ||||
|    * will only be added to the integral term when its absolute value is between these bounds of | ||||
|    * either side of the target. | ||||
|    * | ||||
|    * @param imax max error value that will be summed | ||||
|    * @param imin min error value that will be summed | ||||
|    */ | ||||
|   virtual void setErrorSumLimits(double imax, double imin); | ||||
|  | ||||
|   /** | ||||
|    * Set whether the integrator should be reset when error is 0 or changes sign. | ||||
|    * | ||||
|    * @param iresetOnZero true to reset | ||||
|    */ | ||||
|   virtual void setIntegratorReset(bool iresetOnZero); | ||||
|  | ||||
|   /** | ||||
|    * Set controller gains. | ||||
|    * | ||||
|    * @param igains The new gains. | ||||
|    */ | ||||
|   virtual void setGains(const Gains &igains); | ||||
|  | ||||
|   /** | ||||
|    * Gets the current gains. | ||||
|    * | ||||
|    * @return The current gains. | ||||
|    */ | ||||
|   Gains getGains() const; | ||||
|  | ||||
|   protected: | ||||
|   std::shared_ptr<Logger> logger; | ||||
|   double kP, kI, kD, kBias; | ||||
|   QTime sampleTime{10_ms}; | ||||
|   double target{0}; | ||||
|   double lastReading{0}; | ||||
|   double error{0}; | ||||
|   double lastError{0}; | ||||
|   std::unique_ptr<Filter> derivativeFilter; | ||||
|  | ||||
|   // Integral bounds | ||||
|   double integral{0}; | ||||
|   double integralMax{1}; | ||||
|   double integralMin{-1}; | ||||
|  | ||||
|   // Error will only be added to the integral term within these bounds on either side of the target | ||||
|   double errorSumMin{0}; | ||||
|   double errorSumMax{std::numeric_limits<double>::max()}; | ||||
|  | ||||
|   double derivative{0}; | ||||
|  | ||||
|   // Output bounds | ||||
|   double output{0}; | ||||
|   double outputMax{1}; | ||||
|   double outputMin{-1}; | ||||
|   double controllerSetTargetMax{1}; | ||||
|   double controllerSetTargetMin{-1}; | ||||
|  | ||||
|   // Reset the integrated when the controller crosses 0 or not | ||||
|   bool shouldResetOnCross{true}; | ||||
|  | ||||
|   bool controllerIsDisabled{false}; | ||||
|  | ||||
|   std::unique_ptr<AbstractTimer> loopDtTimer; | ||||
|   std::unique_ptr<SettledUtil> settledUtil; | ||||
| }; | ||||
| } // namespace okapi | ||||
| @@ -0,0 +1,13 @@ | ||||
| /* | ||||
|  * This Source Code Form is subject to the terms of the Mozilla Public | ||||
|  * License, v. 2.0. If a copy of the MPL was not distributed with this | ||||
|  * file, You can obtain one at http://mozilla.org/MPL/2.0/. | ||||
|  */ | ||||
| #pragma once | ||||
|  | ||||
| #include "okapi/api/control/iterative/iterativeController.hpp" | ||||
|  | ||||
| namespace okapi { | ||||
| template <typename Input, typename Output> | ||||
| class IterativePositionController : public IterativeController<Input, Output> {}; | ||||
| } // namespace okapi | ||||
| @@ -0,0 +1,255 @@ | ||||
| /* | ||||
|  * This Source Code Form is subject to the terms of the Mozilla Public | ||||
|  * License, v. 2.0. If a copy of the MPL was not distributed with this | ||||
|  * file, You can obtain one at http://mozilla.org/MPL/2.0/. | ||||
|  */ | ||||
| #pragma once | ||||
|  | ||||
| #include "okapi/api/control/iterative/iterativeVelocityController.hpp" | ||||
| #include "okapi/api/control/util/settledUtil.hpp" | ||||
| #include "okapi/api/filter/passthroughFilter.hpp" | ||||
| #include "okapi/api/filter/velMath.hpp" | ||||
| #include "okapi/api/util/logging.hpp" | ||||
| #include "okapi/api/util/timeUtil.hpp" | ||||
|  | ||||
| namespace okapi { | ||||
| class IterativeVelPIDController : public IterativeVelocityController<double, double> { | ||||
|   public: | ||||
|   struct Gains { | ||||
|     double kP{0}; | ||||
|     double kD{0}; | ||||
|     double kF{0}; | ||||
|     double kSF{0}; | ||||
|  | ||||
|     bool operator==(const Gains &rhs) const; | ||||
|     bool operator!=(const Gains &rhs) const; | ||||
|   }; | ||||
|  | ||||
|   /** | ||||
|    * Velocity PD controller. | ||||
|    * | ||||
|    * @param ikP the proportional gain | ||||
|    * @param ikD the derivative gain | ||||
|    * @param ikF the feed-forward gain | ||||
|    * @param ikSF a feed-forward gain to counteract static friction | ||||
|    * @param ivelMath The VelMath used for calculating velocity. | ||||
|    * @param itimeUtil see TimeUtil docs | ||||
|    * @param iderivativeFilter a filter for filtering the derivative term | ||||
|    * @param ilogger The logger this instance will log to. | ||||
|    */ | ||||
|   IterativeVelPIDController( | ||||
|     double ikP, | ||||
|     double ikD, | ||||
|     double ikF, | ||||
|     double ikSF, | ||||
|     std::unique_ptr<VelMath> ivelMath, | ||||
|     const TimeUtil &itimeUtil, | ||||
|     std::unique_ptr<Filter> iderivativeFilter = std::make_unique<PassthroughFilter>(), | ||||
|     std::shared_ptr<Logger> ilogger = Logger::getDefaultLogger()); | ||||
|  | ||||
|   /** | ||||
|    * Velocity PD controller. | ||||
|    * | ||||
|    * @param igains The controller gains. | ||||
|    * @param ivelMath The VelMath used for calculating velocity. | ||||
|    * @param itimeUtil see TimeUtil docs | ||||
|    * @param iderivativeFilter a filter for filtering the derivative term | ||||
|    * @param ilogger The logger this instance will log to. | ||||
|    */ | ||||
|   IterativeVelPIDController( | ||||
|     const Gains &igains, | ||||
|     std::unique_ptr<VelMath> ivelMath, | ||||
|     const TimeUtil &itimeUtil, | ||||
|     std::unique_ptr<Filter> iderivativeFilter = std::make_unique<PassthroughFilter>(), | ||||
|     std::shared_ptr<Logger> ilogger = Logger::getDefaultLogger()); | ||||
|  | ||||
|   /** | ||||
|    * Do one iteration of the controller. Returns the reading in the range [-1, 1] unless the | ||||
|    * bounds have been changed with setOutputLimits(). | ||||
|    * | ||||
|    * @param inewReading new measurement | ||||
|    * @return controller output | ||||
|    */ | ||||
|   double step(double inewReading) override; | ||||
|  | ||||
|   /** | ||||
|    * Sets the target for the controller. | ||||
|    * | ||||
|    * @param itarget new target velocity | ||||
|    */ | ||||
|   void setTarget(double itarget) override; | ||||
|  | ||||
|   /** | ||||
|    * Writes the value of the controller output. This method might be automatically called in another | ||||
|    * thread by the controller. The range of input values is expected to be [-1, 1]. | ||||
|    * | ||||
|    * @param ivalue the controller's output in the range [-1, 1] | ||||
|    */ | ||||
|   void controllerSet(double ivalue) override; | ||||
|  | ||||
|   /** | ||||
|    * Gets the last set target, or the default target if none was set. | ||||
|    * | ||||
|    * @return the last target | ||||
|    */ | ||||
|   double getTarget() override; | ||||
|  | ||||
|   /** | ||||
|    * Gets the last set target, or the default target if none was set. | ||||
|    * | ||||
|    * @return the last target | ||||
|    */ | ||||
|   double getTarget() const; | ||||
|  | ||||
|   /** | ||||
|    * @return The most recent value of the process variable. | ||||
|    */ | ||||
|   double getProcessValue() const override; | ||||
|  | ||||
|   /** | ||||
|    * Returns the last calculated output of the controller. | ||||
|    */ | ||||
|   double getOutput() const override; | ||||
|  | ||||
|   /** | ||||
|    * Get the upper output bound. | ||||
|    * | ||||
|    * @return  the upper output bound | ||||
|    */ | ||||
|   double getMaxOutput() override; | ||||
|  | ||||
|   /** | ||||
|    * Get the lower output bound. | ||||
|    * | ||||
|    * @return the lower output bound | ||||
|    */ | ||||
|   double getMinOutput() override; | ||||
|  | ||||
|   /** | ||||
|    * Returns the last error of the controller. Does not update when disabled. | ||||
|    */ | ||||
|   double getError() const override; | ||||
|  | ||||
|   /** | ||||
|    * Returns whether the controller has settled at the target. Determining what settling means is | ||||
|    * implementation-dependent. | ||||
|    * | ||||
|    * If the controller is disabled, this method must return true. | ||||
|    * | ||||
|    * @return whether the controller is settled | ||||
|    */ | ||||
|   bool isSettled() override; | ||||
|  | ||||
|   /** | ||||
|    * Set time between loops in ms. | ||||
|    * | ||||
|    * @param isampleTime time between loops | ||||
|    */ | ||||
|   void setSampleTime(QTime isampleTime) override; | ||||
|  | ||||
|   /** | ||||
|    * Set controller output bounds. Default bounds are [-1, 1]. | ||||
|    * | ||||
|    * @param imax max output | ||||
|    * @param imin min output | ||||
|    */ | ||||
|   void setOutputLimits(double imax, double imin) override; | ||||
|  | ||||
|   /** | ||||
|    * Sets the (soft) limits for the target range that controllerSet() scales into. The target | ||||
|    * computed by controllerSet() is scaled into the range [-itargetMin, itargetMax]. | ||||
|    * | ||||
|    * @param itargetMax The new max target for controllerSet(). | ||||
|    * @param itargetMin The new min target for controllerSet(). | ||||
|    */ | ||||
|   void setControllerSetTargetLimits(double itargetMax, double itargetMin) override; | ||||
|  | ||||
|   /** | ||||
|    * Resets the controller's internal state so it is similar to when it was first initialized, while | ||||
|    * keeping any user-configured information. | ||||
|    */ | ||||
|   void reset() override; | ||||
|  | ||||
|   /** | ||||
|    * Changes whether the controller is off or on. Turning the controller on after it was off will | ||||
|    * cause the controller to move to its last set target, unless it was reset in that time. | ||||
|    */ | ||||
|   void flipDisable() override; | ||||
|  | ||||
|   /** | ||||
|    * Sets whether the controller is off or on. Turning the controller on after it was off will | ||||
|    * cause the controller to move to its last set target, unless it was reset in that time. | ||||
|    * | ||||
|    * @param iisDisabled whether the controller is disabled | ||||
|    */ | ||||
|   void flipDisable(bool iisDisabled) override; | ||||
|  | ||||
|   /** | ||||
|    * Returns whether the controller is currently disabled. | ||||
|    * | ||||
|    * @return whether the controller is currently disabled | ||||
|    */ | ||||
|   bool isDisabled() const override; | ||||
|  | ||||
|   /** | ||||
|    * Get the last set sample time. | ||||
|    * | ||||
|    * @return sample time | ||||
|    */ | ||||
|   QTime getSampleTime() const override; | ||||
|  | ||||
|   /** | ||||
|    * Do one iteration of velocity calculation. | ||||
|    * | ||||
|    * @param inewReading new measurement | ||||
|    * @return filtered velocity | ||||
|    */ | ||||
|   virtual QAngularSpeed stepVel(double inewReading); | ||||
|  | ||||
|   /** | ||||
|    * Set controller gains. | ||||
|    * | ||||
|    * @param igains The new gains. | ||||
|    */ | ||||
|   virtual void setGains(const Gains &igains); | ||||
|  | ||||
|   /** | ||||
|    * Gets the current gains. | ||||
|    * | ||||
|    * @return The current gains. | ||||
|    */ | ||||
|   Gains getGains() const; | ||||
|  | ||||
|   /** | ||||
|    * Sets the number of encoder ticks per revolution. Default is 1800. | ||||
|    * | ||||
|    * @param tpr number of measured units per revolution | ||||
|    */ | ||||
|   virtual void setTicksPerRev(double tpr); | ||||
|  | ||||
|   /** | ||||
|    * Returns the current velocity. | ||||
|    */ | ||||
|   virtual QAngularSpeed getVel() const; | ||||
|  | ||||
|   protected: | ||||
|   std::shared_ptr<Logger> logger; | ||||
|   double kP, kD, kF, kSF; | ||||
|   QTime sampleTime{10_ms}; | ||||
|   double error{0}; | ||||
|   double derivative{0}; | ||||
|   double target{0}; | ||||
|   double outputSum{0}; | ||||
|   double output{0}; | ||||
|   double outputMax{1}; | ||||
|   double outputMin{-1}; | ||||
|   double controllerSetTargetMax{1}; | ||||
|   double controllerSetTargetMin{-1}; | ||||
|   bool controllerIsDisabled{false}; | ||||
|  | ||||
|   std::unique_ptr<VelMath> velMath; | ||||
|   std::unique_ptr<Filter> derivativeFilter; | ||||
|   std::unique_ptr<AbstractTimer> loopDtTimer; | ||||
|   std::unique_ptr<SettledUtil> settledUtil; | ||||
| }; | ||||
| } // namespace okapi | ||||
| @@ -0,0 +1,13 @@ | ||||
| /* | ||||
|  * This Source Code Form is subject to the terms of the Mozilla Public | ||||
|  * License, v. 2.0. If a copy of the MPL was not distributed with this | ||||
|  * file, You can obtain one at http://mozilla.org/MPL/2.0/. | ||||
|  */ | ||||
| #pragma once | ||||
|  | ||||
| #include "okapi/api/control/iterative/iterativeController.hpp" | ||||
|  | ||||
| namespace okapi { | ||||
| template <typename Input, typename Output> | ||||
| class IterativeVelocityController : public IterativeController<Input, Output> {}; | ||||
| } // namespace okapi | ||||
| @@ -0,0 +1,41 @@ | ||||
| /* | ||||
|  * This Source Code Form is subject to the terms of the Mozilla Public | ||||
|  * License, v. 2.0. If a copy of the MPL was not distributed with this | ||||
|  * file, You can obtain one at http://mozilla.org/MPL/2.0/. | ||||
|  */ | ||||
| #pragma once | ||||
|  | ||||
| #include "okapi/api/control/controllerInput.hpp" | ||||
| #include <memory> | ||||
|  | ||||
| namespace okapi { | ||||
| class OffsetableControllerInput : public ControllerInput<double> { | ||||
|   public: | ||||
|   /** | ||||
|    * A ControllerInput which can be tared to change the zero position. | ||||
|    * | ||||
|    * @param iinput The ControllerInput to reference. | ||||
|    */ | ||||
|   explicit OffsetableControllerInput(const std::shared_ptr<ControllerInput<double>> &iinput); | ||||
|  | ||||
|   virtual ~OffsetableControllerInput(); | ||||
|  | ||||
|   /** | ||||
|    * Get the sensor value for use in a control loop. This method might be automatically called in | ||||
|    * another thread by the controller. | ||||
|    * | ||||
|    * @return the current sensor value, or PROS_ERR on a failure. | ||||
|    */ | ||||
|   double controllerGet() override; | ||||
|  | ||||
|   /** | ||||
|    * Sets the "absolute" zero position of this controller input to its current position. This does | ||||
|    * nothing if the underlying controller input returns PROS_ERR. | ||||
|    */ | ||||
|   virtual void tarePosition(); | ||||
|  | ||||
|   protected: | ||||
|   std::shared_ptr<ControllerInput<double>> input; | ||||
|   double offset{0}; | ||||
| }; | ||||
| } // namespace okapi | ||||
							
								
								
									
										131
									
								
								SerialTest/include/okapi/api/control/util/controllerRunner.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										131
									
								
								SerialTest/include/okapi/api/control/util/controllerRunner.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,131 @@ | ||||
| /* | ||||
|  * This Source Code Form is subject to the terms of the Mozilla Public | ||||
|  * License, v. 2.0. If a copy of the MPL was not distributed with this | ||||
|  * file, You can obtain one at http://mozilla.org/MPL/2.0/. | ||||
|  */ | ||||
| #pragma once | ||||
|  | ||||
| #include "okapi/api/control/async/asyncController.hpp" | ||||
| #include "okapi/api/control/controllerOutput.hpp" | ||||
| #include "okapi/api/control/iterative/iterativeController.hpp" | ||||
| #include "okapi/api/util/abstractRate.hpp" | ||||
| #include "okapi/api/util/logging.hpp" | ||||
| #include "okapi/api/util/timeUtil.hpp" | ||||
| #include <memory> | ||||
|  | ||||
| namespace okapi { | ||||
| template <typename Input, typename Output> class ControllerRunner { | ||||
|   public: | ||||
|   /** | ||||
|    * A utility class that runs a closed-loop controller. | ||||
|    * | ||||
|    * @param itimeUtil The TimeUtil. | ||||
|    * @param ilogger The logger this instance will log to. | ||||
|    */ | ||||
|   explicit ControllerRunner(const TimeUtil &itimeUtil, | ||||
|                             const std::shared_ptr<Logger> &ilogger = Logger::getDefaultLogger()) | ||||
|     : logger(ilogger), rate(itimeUtil.getRate()) { | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * Runs the controller until it has settled. | ||||
|    * | ||||
|    * @param itarget the new target | ||||
|    * @param icontroller the controller to run | ||||
|    * @return the error when settled | ||||
|    */ | ||||
|   virtual Output runUntilSettled(const Input itarget, AsyncController<Input, Output> &icontroller) { | ||||
|     LOG_INFO("ControllerRunner: runUntilSettled(AsyncController): Set target to " + | ||||
|              std::to_string(itarget)); | ||||
|     icontroller.setTarget(itarget); | ||||
|  | ||||
|     while (!icontroller.isSettled()) { | ||||
|       rate->delayUntil(10_ms); | ||||
|     } | ||||
|  | ||||
|     LOG_INFO("ControllerRunner: runUntilSettled(AsyncController): Done waiting to settle"); | ||||
|     return icontroller.getError(); | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * Runs the controller until it has settled. | ||||
|    * | ||||
|    * @param itarget the new target | ||||
|    * @param icontroller the controller to run | ||||
|    * @param ioutput the output to write to | ||||
|    * @return the error when settled | ||||
|    */ | ||||
|   virtual Output runUntilSettled(const Input itarget, | ||||
|                                  IterativeController<Input, Output> &icontroller, | ||||
|                                  ControllerOutput<Output> &ioutput) { | ||||
|     LOG_INFO("ControllerRunner: runUntilSettled(IterativeController): Set target to " + | ||||
|              std::to_string(itarget)); | ||||
|     icontroller.setTarget(itarget); | ||||
|  | ||||
|     while (!icontroller.isSettled()) { | ||||
|       ioutput.controllerSet(icontroller.getOutput()); | ||||
|       rate->delayUntil(10_ms); | ||||
|     } | ||||
|  | ||||
|     LOG_INFO("ControllerRunner: runUntilSettled(IterativeController): Done waiting to settle"); | ||||
|     return icontroller.getError(); | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * Runs the controller until it has reached its target, but not necessarily settled. | ||||
|    * | ||||
|    * @param itarget the new target | ||||
|    * @param icontroller the controller to run | ||||
|    * @return the error when settled | ||||
|    */ | ||||
|   virtual Output runUntilAtTarget(const Input itarget, | ||||
|                                   AsyncController<Input, Output> &icontroller) { | ||||
|     LOG_INFO("ControllerRunner: runUntilAtTarget(AsyncController): Set target to " + | ||||
|              std::to_string(itarget)); | ||||
|     icontroller.setTarget(itarget); | ||||
|  | ||||
|     double error = icontroller.getError(); | ||||
|     double lastError = error; | ||||
|     while (error != 0 && std::copysign(1.0, error) == std::copysign(1.0, lastError)) { | ||||
|       lastError = error; | ||||
|       rate->delayUntil(10_ms); | ||||
|       error = icontroller.getError(); | ||||
|     } | ||||
|  | ||||
|     LOG_INFO("ControllerRunner: runUntilAtTarget(AsyncController): Done waiting to settle"); | ||||
|     return icontroller.getError(); | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * Runs the controller until it has reached its target, but not necessarily settled. | ||||
|    * | ||||
|    * @param itarget the new target | ||||
|    * @param icontroller the controller to run | ||||
|    * @param ioutput the output to write to | ||||
|    * @return the error when settled | ||||
|    */ | ||||
|   virtual Output runUntilAtTarget(const Input itarget, | ||||
|                                   IterativeController<Input, Output> &icontroller, | ||||
|                                   ControllerOutput<Output> &ioutput) { | ||||
|     LOG_INFO("ControllerRunner: runUntilAtTarget(IterativeController): Set target to " + | ||||
|              std::to_string(itarget)); | ||||
|     icontroller.setTarget(itarget); | ||||
|  | ||||
|     double error = icontroller.getError(); | ||||
|     double lastError = error; | ||||
|     while (error != 0 && std::copysign(1.0, error) == std::copysign(1.0, lastError)) { | ||||
|       ioutput.controllerSet(icontroller.getOutput()); | ||||
|       lastError = error; | ||||
|       rate->delayUntil(10_ms); | ||||
|       error = icontroller.getError(); | ||||
|     } | ||||
|  | ||||
|     LOG_INFO("ControllerRunner: runUntilAtTarget(IterativeController): Done waiting to settle"); | ||||
|     return icontroller.getError(); | ||||
|   } | ||||
|  | ||||
|   protected: | ||||
|   std::shared_ptr<Logger> logger; | ||||
|   std::unique_ptr<AbstractRate> rate; | ||||
| }; | ||||
| } // namespace okapi | ||||
							
								
								
									
										156
									
								
								SerialTest/include/okapi/api/control/util/flywheelSimulator.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										156
									
								
								SerialTest/include/okapi/api/control/util/flywheelSimulator.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,156 @@ | ||||
| /* | ||||
|  * This Source Code Form is subject to the terms of the Mozilla Public | ||||
|  * License, v. 2.0. If a copy of the MPL was not distributed with this | ||||
|  * file, You can obtain one at http://mozilla.org/MPL/2.0/. | ||||
|  */ | ||||
| #pragma once | ||||
|  | ||||
| #include <functional> | ||||
|  | ||||
| namespace okapi { | ||||
| class FlywheelSimulator { | ||||
|   public: | ||||
|   /** | ||||
|    * A simulator for an inverted pendulum. The center of mass of the system changes as the link | ||||
|    * rotates (by default, you can set a new torque function with setExternalTorqueFunction()). | ||||
|    */ | ||||
|   explicit FlywheelSimulator(double imass = 0.01, | ||||
|                              double ilinkLen = 1, | ||||
|                              double imuStatic = 0.1, | ||||
|                              double imuDynamic = 0.9, | ||||
|                              double itimestep = 0.01); | ||||
|  | ||||
|   virtual ~FlywheelSimulator(); | ||||
|  | ||||
|   /** | ||||
|    * Step the simulation by the timestep. | ||||
|    * | ||||
|    * @return the current angle | ||||
|    */ | ||||
|   double step(); | ||||
|  | ||||
|   /** | ||||
|    * Step the simulation by the timestep. | ||||
|    * | ||||
|    * @param itorque new input torque | ||||
|    * @return the current angle | ||||
|    */ | ||||
|   double step(double itorque); | ||||
|  | ||||
|   /** | ||||
|    * Sets the torque function used to calculate the torque due to external forces. This torque gets | ||||
|    * summed with the input torque. | ||||
|    * | ||||
|    * For example, the default torque function has the torque due to gravity vary as the link swings: | ||||
|    * [](double angle, double mass, double linkLength) { | ||||
|    *   return (linkLength * std::cos(angle)) * (mass * -1 * gravity); | ||||
|    * } | ||||
|    * | ||||
|    * @param itorqueFunc the torque function. The return value is the torque due to external forces | ||||
|    */ | ||||
|   void setExternalTorqueFunction( | ||||
|     std::function<double(double angle, double mass, double linkLength)> itorqueFunc); | ||||
|  | ||||
|   /** | ||||
|    * Sets the input torque. The input will be bounded by the max torque. | ||||
|    * | ||||
|    * @param itorque new input torque | ||||
|    */ | ||||
|   void setTorque(double itorque); | ||||
|  | ||||
|   /** | ||||
|    * Sets the max torque. The input torque cannot exceed this maximum torque. | ||||
|    * | ||||
|    * @param imaxTorque new maximum torque | ||||
|    */ | ||||
|   void setMaxTorque(double imaxTorque); | ||||
|  | ||||
|   /** | ||||
|    * Sets the current angle. | ||||
|    * | ||||
|    * @param iangle new angle | ||||
|    **/ | ||||
|   void setAngle(double iangle); | ||||
|  | ||||
|   /** | ||||
|    * Sets the mass (kg). | ||||
|    * | ||||
|    * @param imass new mass | ||||
|    */ | ||||
|   void setMass(double imass); | ||||
|  | ||||
|   /** | ||||
|    * Sets the link length (m). | ||||
|    * | ||||
|    * @param ilinkLen new link length | ||||
|    */ | ||||
|   void setLinkLength(double ilinkLen); | ||||
|  | ||||
|   /** | ||||
|    * Sets the static friction (N*m). | ||||
|    * | ||||
|    * @param imuStatic new static friction | ||||
|    */ | ||||
|   void setStaticFriction(double imuStatic); | ||||
|  | ||||
|   /** | ||||
|    * Sets the dynamic friction (N*m). | ||||
|    * | ||||
|    * @param imuDynamic new dynamic friction | ||||
|    */ | ||||
|   void setDynamicFriction(double imuDynamic); | ||||
|  | ||||
|   /** | ||||
|    * Sets the timestep (sec). | ||||
|    * | ||||
|    * @param itimestep new timestep | ||||
|    */ | ||||
|   void setTimestep(double itimestep); | ||||
|  | ||||
|   /** | ||||
|    * Returns the current angle (angle in rad). | ||||
|    * | ||||
|    * @return the current angle | ||||
|    */ | ||||
|   double getAngle() const; | ||||
|  | ||||
|   /** | ||||
|    * Returns the current omgea (angular velocity in rad / sec). | ||||
|    * | ||||
|    * @return the current omega | ||||
|    */ | ||||
|   double getOmega() const; | ||||
|  | ||||
|   /** | ||||
|    * Returns the current acceleration (angular acceleration in rad / sec^2). | ||||
|    * | ||||
|    * @return the current acceleration | ||||
|    */ | ||||
|   double getAcceleration() const; | ||||
|  | ||||
|   /** | ||||
|    * Returns the maximum torque input. | ||||
|    * | ||||
|    * @return the max torque input | ||||
|    */ | ||||
|   double getMaxTorque() const; | ||||
|  | ||||
|   protected: | ||||
|   double inputTorque = 0;    // N*m | ||||
|   double maxTorque = 0.5649; // N*m | ||||
|   double angle = 0;          // rad | ||||
|   double omega = 0;          // rad / sec | ||||
|   double accel = 0;          // rad / sec^2 | ||||
|   double mass;               // kg | ||||
|   double linkLen;            // m | ||||
|   double muStatic;           // N*m | ||||
|   double muDynamic;          // N*m | ||||
|   double timestep;           // sec | ||||
|   double I = 0;              // moment of inertia | ||||
|   std::function<double(double, double, double)> torqueFunc; | ||||
|  | ||||
|   const double minTimestep = 0.000001; // 1 us | ||||
|  | ||||
|   virtual double stepImpl(); | ||||
| }; | ||||
| } // namespace okapi | ||||
							
								
								
									
										23
									
								
								SerialTest/include/okapi/api/control/util/pathfinderUtil.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								SerialTest/include/okapi/api/control/util/pathfinderUtil.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,23 @@ | ||||
| /* | ||||
|  * This Source Code Form is subject to the terms of the Mozilla Public | ||||
|  * License, v. 2.0. If a copy of the MPL was not distributed with this | ||||
|  * file, You can obtain one at http://mozilla.org/MPL/2.0/. | ||||
|  */ | ||||
| #pragma once | ||||
|  | ||||
| #include "okapi/api/units/QAngle.hpp" | ||||
| #include "okapi/api/units/QLength.hpp" | ||||
|  | ||||
| namespace okapi { | ||||
| struct PathfinderPoint { | ||||
|   QLength x;    // X coordinate relative to the start of the movement | ||||
|   QLength y;    // Y coordinate relative to the start of the movement | ||||
|   QAngle theta; // Exit angle relative to the start of the movement | ||||
| }; | ||||
|  | ||||
| struct PathfinderLimits { | ||||
|   double maxVel;   // Maximum robot velocity in m/s | ||||
|   double maxAccel; // Maximum robot acceleration in m/s/s | ||||
|   double maxJerk;  // Maximum robot jerk in m/s/s/s | ||||
| }; | ||||
| } // namespace okapi | ||||
							
								
								
									
										80
									
								
								SerialTest/include/okapi/api/control/util/pidTuner.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										80
									
								
								SerialTest/include/okapi/api/control/util/pidTuner.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,80 @@ | ||||
| /* | ||||
|  * This Source Code Form is subject to the terms of the Mozilla Public | ||||
|  * License, v. 2.0. If a copy of the MPL was not distributed with this | ||||
|  * file, You can obtain one at http://mozilla.org/MPL/2.0/. | ||||
|  */ | ||||
| #pragma once | ||||
|  | ||||
| #include "okapi/api/control/controllerInput.hpp" | ||||
| #include "okapi/api/control/controllerOutput.hpp" | ||||
| #include "okapi/api/control/iterative/iterativePosPidController.hpp" | ||||
| #include "okapi/api/units/QTime.hpp" | ||||
| #include "okapi/api/util/logging.hpp" | ||||
| #include "okapi/api/util/timeUtil.hpp" | ||||
| #include <memory> | ||||
| #include <vector> | ||||
|  | ||||
| namespace okapi { | ||||
| class PIDTuner { | ||||
|   public: | ||||
|   struct Output { | ||||
|     double kP, kI, kD; | ||||
|   }; | ||||
|  | ||||
|   PIDTuner(const std::shared_ptr<ControllerInput<double>> &iinput, | ||||
|            const std::shared_ptr<ControllerOutput<double>> &ioutput, | ||||
|            const TimeUtil &itimeUtil, | ||||
|            QTime itimeout, | ||||
|            std::int32_t igoal, | ||||
|            double ikPMin, | ||||
|            double ikPMax, | ||||
|            double ikIMin, | ||||
|            double ikIMax, | ||||
|            double ikDMin, | ||||
|            double ikDMax, | ||||
|            std::size_t inumIterations = 5, | ||||
|            std::size_t inumParticles = 16, | ||||
|            double ikSettle = 1, | ||||
|            double ikITAE = 2, | ||||
|            const std::shared_ptr<Logger> &ilogger = Logger::getDefaultLogger()); | ||||
|  | ||||
|   virtual ~PIDTuner(); | ||||
|  | ||||
|   virtual Output autotune(); | ||||
|  | ||||
|   protected: | ||||
|   static constexpr double inertia = 0.5;   // Particle inertia | ||||
|   static constexpr double confSelf = 1.1;  // Self confidence | ||||
|   static constexpr double confSwarm = 1.2; // Particle swarm confidence | ||||
|   static constexpr int increment = 5; | ||||
|   static constexpr int divisor = 5; | ||||
|   static constexpr QTime loopDelta = 10_ms; // NOLINT | ||||
|  | ||||
|   struct Particle { | ||||
|     double pos, vel, best; | ||||
|   }; | ||||
|  | ||||
|   struct ParticleSet { | ||||
|     Particle kP, kI, kD; | ||||
|     double bestError; | ||||
|   }; | ||||
|  | ||||
|   std::shared_ptr<Logger> logger; | ||||
|   TimeUtil timeUtil; | ||||
|   std::shared_ptr<ControllerInput<double>> input; | ||||
|   std::shared_ptr<ControllerOutput<double>> output; | ||||
|  | ||||
|   const QTime timeout; | ||||
|   const std::int32_t goal; | ||||
|   const double kPMin; | ||||
|   const double kPMax; | ||||
|   const double kIMin; | ||||
|   const double kIMax; | ||||
|   const double kDMin; | ||||
|   const double kDMax; | ||||
|   const std::size_t numIterations; | ||||
|   const std::size_t numParticles; | ||||
|   const double kSettle; | ||||
|   const double kITAE; | ||||
| }; | ||||
| } // namespace okapi | ||||
							
								
								
									
										51
									
								
								SerialTest/include/okapi/api/control/util/settledUtil.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										51
									
								
								SerialTest/include/okapi/api/control/util/settledUtil.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,51 @@ | ||||
| /* | ||||
|  * This Source Code Form is subject to the terms of the Mozilla Public | ||||
|  * License, v. 2.0. If a copy of the MPL was not distributed with this | ||||
|  * file, You can obtain one at http://mozilla.org/MPL/2.0/. | ||||
|  */ | ||||
| #pragma once | ||||
|  | ||||
| #include "okapi/api/units/QTime.hpp" | ||||
| #include "okapi/api/util/abstractTimer.hpp" | ||||
| #include <memory> | ||||
|  | ||||
| namespace okapi { | ||||
| class SettledUtil { | ||||
|   public: | ||||
|   /** | ||||
|    * A utility class to determine if a control loop has settled based on error. A control loop is | ||||
|    * settled if the error is within `iatTargetError` and `iatTargetDerivative` for `iatTargetTime`. | ||||
|    * | ||||
|    * @param iatTargetTimer A timer used to track `iatTargetTime`. | ||||
|    * @param iatTargetError The minimum error to be considered settled. | ||||
|    * @param iatTargetDerivative The minimum error derivative to be considered settled. | ||||
|    * @param iatTargetTime The minimum time within atTargetError to be considered settled. | ||||
|    */ | ||||
|   explicit SettledUtil(std::unique_ptr<AbstractTimer> iatTargetTimer, | ||||
|                        double iatTargetError = 50, | ||||
|                        double iatTargetDerivative = 5, | ||||
|                        QTime iatTargetTime = 250_ms); | ||||
|  | ||||
|   virtual ~SettledUtil(); | ||||
|  | ||||
|   /** | ||||
|    * Returns whether the controller is settled. | ||||
|    * | ||||
|    * @param ierror The current error. | ||||
|    * @return Whether the controller is settled. | ||||
|    */ | ||||
|   virtual bool isSettled(double ierror); | ||||
|  | ||||
|   /** | ||||
|    * Resets the "at target" timer and clears the previous error. | ||||
|    */ | ||||
|   virtual void reset(); | ||||
|  | ||||
|   protected: | ||||
|   double atTargetError = 50; | ||||
|   double atTargetDerivative = 5; | ||||
|   QTime atTargetTime = 250_ms; | ||||
|   std::unique_ptr<AbstractTimer> atTargetTimer; | ||||
|   double lastError = 0; | ||||
| }; | ||||
| } // namespace okapi | ||||
							
								
								
									
										131
									
								
								SerialTest/include/okapi/api/coreProsAPI.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										131
									
								
								SerialTest/include/okapi/api/coreProsAPI.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,131 @@ | ||||
| /* | ||||
|  * This Source Code Form is subject to the terms of the Mozilla Public | ||||
|  * License, v. 2.0. If a copy of the MPL was not distributed with this | ||||
|  * file, You can obtain one at http://mozilla.org/MPL/2.0/. | ||||
|  */ | ||||
| #pragma once | ||||
|  | ||||
| #include <cmath> | ||||
| #include <cstdbool> | ||||
| #include <cstddef> | ||||
| #include <cstdint> | ||||
| #include <cstdio> | ||||
| #include <cstdlib> | ||||
| #include <functional> | ||||
| #include <sstream> | ||||
|  | ||||
| #ifdef THREADS_STD | ||||
| #include <thread> | ||||
| #define CROSSPLATFORM_THREAD_T std::thread | ||||
|  | ||||
| #include <mutex> | ||||
| #define CROSSPLATFORM_MUTEX_T std::mutex | ||||
| #else | ||||
| #include "api.h" | ||||
| #include "pros/apix.h" | ||||
| #define CROSSPLATFORM_THREAD_T pros::task_t | ||||
| #define CROSSPLATFORM_MUTEX_T pros::Mutex | ||||
| #endif | ||||
|  | ||||
| #define NOT_INITIALIZE_TASK                                                                        \ | ||||
|   (strcmp(pros::c::task_get_name(pros::c::task_get_current()), "User Initialization (PROS)") != 0) | ||||
|  | ||||
| #define NOT_COMP_INITIALIZE_TASK                                                                   \ | ||||
|   (strcmp(pros::c::task_get_name(pros::c::task_get_current()), "User Comp. Init. (PROS)") != 0) | ||||
|  | ||||
| class CrossplatformThread { | ||||
|   public: | ||||
| #ifdef THREADS_STD | ||||
|   CrossplatformThread(void (*ptr)(void *), | ||||
|                       void *params, | ||||
|                       const char *const = "OkapiLibCrossplatformTask") | ||||
| #else | ||||
|   CrossplatformThread(void (*ptr)(void *), | ||||
|                       void *params, | ||||
|                       const char *const name = "OkapiLibCrossplatformTask") | ||||
| #endif | ||||
|     : | ||||
| #ifdef THREADS_STD | ||||
|       thread(ptr, params) | ||||
| #else | ||||
|       thread( | ||||
|         pros::c::task_create(ptr, params, TASK_PRIORITY_DEFAULT, TASK_STACK_DEPTH_DEFAULT, name)) | ||||
| #endif | ||||
|   { | ||||
|   } | ||||
|  | ||||
|   ~CrossplatformThread() { | ||||
| #ifdef THREADS_STD | ||||
|     thread.join(); | ||||
| #else | ||||
|     if (pros::c::task_get_state(thread) != pros::E_TASK_STATE_DELETED) { | ||||
|       pros::c::task_delete(thread); | ||||
|     } | ||||
| #endif | ||||
|   } | ||||
|  | ||||
| #ifdef THREADS_STD | ||||
|   void notifyWhenDeleting(CrossplatformThread *) { | ||||
|   } | ||||
| #else | ||||
|   void notifyWhenDeleting(CrossplatformThread *parent) { | ||||
|     pros::c::task_notify_when_deleting(parent->thread, thread, 1, pros::E_NOTIFY_ACTION_INCR); | ||||
|   } | ||||
| #endif | ||||
|  | ||||
| #ifdef THREADS_STD | ||||
|   void notifyWhenDeletingRaw(CROSSPLATFORM_THREAD_T *) { | ||||
|   } | ||||
| #else | ||||
|   void notifyWhenDeletingRaw(CROSSPLATFORM_THREAD_T parent) { | ||||
|     pros::c::task_notify_when_deleting(parent, thread, 1, pros::E_NOTIFY_ACTION_INCR); | ||||
|   } | ||||
| #endif | ||||
|  | ||||
| #ifdef THREADS_STD | ||||
|   std::uint32_t notifyTake(const std::uint32_t) { | ||||
|     return 0; | ||||
|   } | ||||
| #else | ||||
|   std::uint32_t notifyTake(const std::uint32_t itimeout) { | ||||
|     return pros::c::task_notify_take(true, itimeout); | ||||
|   } | ||||
| #endif | ||||
|  | ||||
|   static std::string getName() { | ||||
| #ifdef THREADS_STD | ||||
|     std::ostringstream ss; | ||||
|     ss << std::this_thread::get_id(); | ||||
|     return ss.str(); | ||||
| #else | ||||
|     return std::string(pros::c::task_get_name(NULL)); | ||||
| #endif | ||||
|   } | ||||
|  | ||||
|   CROSSPLATFORM_THREAD_T thread; | ||||
| }; | ||||
|  | ||||
| class CrossplatformMutex { | ||||
|   public: | ||||
|   CrossplatformMutex() = default; | ||||
|  | ||||
|   void lock() { | ||||
| #ifdef THREADS_STD | ||||
|     mutex.lock(); | ||||
| #else | ||||
|     while (!mutex.take(1)) { | ||||
|     } | ||||
| #endif | ||||
|   } | ||||
|  | ||||
|   void unlock() { | ||||
| #ifdef THREADS_STD | ||||
|     mutex.unlock(); | ||||
| #else | ||||
|     mutex.give(); | ||||
| #endif | ||||
|   } | ||||
|  | ||||
|   protected: | ||||
|   CROSSPLATFORM_MUTEX_T mutex; | ||||
| }; | ||||
| @@ -0,0 +1,46 @@ | ||||
| /* | ||||
|  * This Source Code Form is subject to the terms of the Mozilla Public | ||||
|  * License, v. 2.0. If a copy of the MPL was not distributed with this | ||||
|  * file, You can obtain one at http://mozilla.org/MPL/2.0/. | ||||
|  */ | ||||
| #pragma once | ||||
|  | ||||
| #include "okapi/api/control/controllerInput.hpp" | ||||
|  | ||||
| namespace okapi { | ||||
| class AbstractButton : public ControllerInput<bool> { | ||||
|   public: | ||||
|   virtual ~AbstractButton(); | ||||
|  | ||||
|   /** | ||||
|    * Return whether the button is currently pressed. | ||||
|    **/ | ||||
|   virtual bool isPressed() = 0; | ||||
|  | ||||
|   /** | ||||
|    * Return whether the state of the button changed since the last time this method was | ||||
|    * called. | ||||
|    **/ | ||||
|   virtual bool changed() = 0; | ||||
|  | ||||
|   /** | ||||
|    * Return whether the state of the button changed to being pressed since the last time this method | ||||
|    * was called. | ||||
|    **/ | ||||
|   virtual bool changedToPressed() = 0; | ||||
|  | ||||
|   /** | ||||
|    * Return whether the state of the button to being not pressed changed since the last time this | ||||
|    * method was called. | ||||
|    **/ | ||||
|   virtual bool changedToReleased() = 0; | ||||
|  | ||||
|   /** | ||||
|    * Get the sensor value for use in a control loop. This method might be automatically called in | ||||
|    * another thread by the controller. | ||||
|    * | ||||
|    * @return the current sensor value. This is the same as the output of the pressed() method. | ||||
|    */ | ||||
|   virtual bool controllerGet() override; | ||||
| }; | ||||
| } // namespace okapi | ||||
							
								
								
									
										52
									
								
								SerialTest/include/okapi/api/device/button/buttonBase.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										52
									
								
								SerialTest/include/okapi/api/device/button/buttonBase.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,52 @@ | ||||
| /* | ||||
|  * This Source Code Form is subject to the terms of the Mozilla Public | ||||
|  * License, v. 2.0. If a copy of the MPL was not distributed with this | ||||
|  * file, You can obtain one at http://mozilla.org/MPL/2.0/. | ||||
|  */ | ||||
| #pragma once | ||||
|  | ||||
| #include "okapi/api/device/button/abstractButton.hpp" | ||||
|  | ||||
| namespace okapi { | ||||
| class ButtonBase : public AbstractButton { | ||||
|   public: | ||||
|   /** | ||||
|    * @param iinverted Whether the button is inverted (`true` meaning default pressed and `false` | ||||
|    * meaning default not pressed). | ||||
|    */ | ||||
|   explicit ButtonBase(bool iinverted = false); | ||||
|  | ||||
|   /** | ||||
|    * Return whether the button is currently pressed. | ||||
|    **/ | ||||
|   bool isPressed() override; | ||||
|  | ||||
|   /** | ||||
|    * Return whether the state of the button changed since the last time this method was called. | ||||
|    **/ | ||||
|   bool changed() override; | ||||
|  | ||||
|   /** | ||||
|    * Return whether the state of the button changed to pressed since the last time this method was | ||||
|    *called. | ||||
|    **/ | ||||
|   bool changedToPressed() override; | ||||
|  | ||||
|   /** | ||||
|    * Return whether the state of the button to not pressed since the last time this method was | ||||
|    *called. | ||||
|    **/ | ||||
|   bool changedToReleased() override; | ||||
|  | ||||
|   protected: | ||||
|   bool inverted{false}; | ||||
|   bool wasPressedLast_c{false}; | ||||
|   bool wasPressedLast_ctp{false}; | ||||
|   bool wasPressedLast_ctr{false}; | ||||
|  | ||||
|   virtual bool currentlyPressed() = 0; | ||||
|  | ||||
|   private: | ||||
|   bool changedImpl(bool &prevState); | ||||
| }; | ||||
| } // namespace okapi | ||||
							
								
								
									
										537
									
								
								SerialTest/include/okapi/api/device/motor/abstractMotor.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										537
									
								
								SerialTest/include/okapi/api/device/motor/abstractMotor.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,537 @@ | ||||
| /* | ||||
|  * This Source Code Form is subject to the terms of the Mozilla Public | ||||
|  * License, v. 2.0. If a copy of the MPL was not distributed with this | ||||
|  * file, You can obtain one at http://mozilla.org/MPL/2.0/. | ||||
|  */ | ||||
| #pragma once | ||||
|  | ||||
| #include "okapi/api/control/controllerOutput.hpp" | ||||
| #include "okapi/api/device/rotarysensor/continuousRotarySensor.hpp" | ||||
| #include <memory> | ||||
|  | ||||
| namespace okapi { | ||||
| class AbstractMotor : public ControllerOutput<double> { | ||||
|   public: | ||||
|   /** | ||||
|    * Indicates the 'brake mode' of a motor. | ||||
|    */ | ||||
|   enum class brakeMode { | ||||
|     coast = 0, ///< Motor coasts when stopped, traditional behavior | ||||
|     brake = 1, ///< Motor brakes when stopped | ||||
|     hold = 2,  ///< Motor actively holds position when stopped | ||||
|     invalid = INT32_MAX | ||||
|   }; | ||||
|  | ||||
|   /** | ||||
|    * Indicates the units used by the motor encoders. | ||||
|    */ | ||||
|   enum class encoderUnits { | ||||
|     degrees = 0,        ///< degrees | ||||
|     rotations = 1,      ///< rotations | ||||
|     counts = 2,         ///< counts | ||||
|     invalid = INT32_MAX ///< invalid | ||||
|   }; | ||||
|  | ||||
|   /** | ||||
|    * Indicates the internal gear ratio of a motor. | ||||
|    */ | ||||
|   enum class gearset { | ||||
|     red = 100,   ///< 36:1, 100 RPM, Red gear set | ||||
|     green = 200, ///< 18:1, 200 RPM, Green gear set | ||||
|     blue = 600,  ///< 6:1,  600 RPM, Blue gear set | ||||
|     invalid = INT32_MAX | ||||
|   }; | ||||
|  | ||||
|   /** | ||||
|    * A simple structure representing the full ratio between motor and wheel. | ||||
|    */ | ||||
|   struct GearsetRatioPair { | ||||
|     /** | ||||
|      * A simple structure representing the full ratio between motor and wheel. | ||||
|      * | ||||
|      * The ratio is `motor rotation : wheel rotation`, e.x., if one motor rotation | ||||
|      * corresponds to two wheel rotations, the ratio is `1.0/2.0`. | ||||
|      * | ||||
|      * @param igearset The gearset in the motor. | ||||
|      * @param iratio The ratio of motor rotation to wheel rotation. | ||||
|      */ | ||||
|     GearsetRatioPair(const gearset igearset, const double iratio = 1) | ||||
|       : internalGearset(igearset), ratio(iratio) { | ||||
|     } | ||||
|  | ||||
|     ~GearsetRatioPair() = default; | ||||
|  | ||||
|     gearset internalGearset; | ||||
|     double ratio = 1; | ||||
|   }; | ||||
|  | ||||
|   virtual ~AbstractMotor(); | ||||
|  | ||||
|   /******************************************************************************/ | ||||
|   /**                         Motor movement functions                         **/ | ||||
|   /**                                                                          **/ | ||||
|   /**          These functions allow programmers to make motors move           **/ | ||||
|   /******************************************************************************/ | ||||
|  | ||||
|   /** | ||||
|    * Sets the target absolute position for the motor to move to. | ||||
|    * | ||||
|    * This movement is relative to the position of the motor when initialized or | ||||
|    * the position when it was most recently reset with setZeroPosition(). | ||||
|    * | ||||
|    * @note This function simply sets the target for the motor, it does not block program execution | ||||
|    * until the movement finishes. | ||||
|    * | ||||
|    * This function uses the following values of errno when an error state is reached: | ||||
|    * EACCES - Another resource is currently trying to access the port. | ||||
|    * | ||||
|    * @param iposition The absolute position to move to in the motor's encoder units | ||||
|    * @param ivelocity The maximum allowable velocity for the movement in RPM | ||||
|    * @return 1 if the operation was successful or PROS_ERR if the operation failed, setting errno. | ||||
|    */ | ||||
|   virtual std::int32_t moveAbsolute(double iposition, std::int32_t ivelocity) = 0; | ||||
|  | ||||
|   /** | ||||
|    * Sets the relative target position for the motor to move to. | ||||
|    * | ||||
|    * This movement is relative to the current position of the motor. Providing 10.0 as the position | ||||
|    * parameter would result in the motor moving clockwise 10 units, no matter what the current | ||||
|    * position is. | ||||
|    * | ||||
|    * @note This function simply sets the target for the motor, it does not block program execution | ||||
|    * until the movement finishes. | ||||
|    * | ||||
|    * This function uses the following values of errno when an error state is reached: | ||||
|    * EACCES - Another resource is currently trying to access the port. | ||||
|    * | ||||
|    * @param iposition The relative position to move to in the motor's encoder units | ||||
|    * @param ivelocity The maximum allowable velocity for the movement in RPM | ||||
|    * @return 1 if the operation was successful or PROS_ERR if the operation failed, setting errno. | ||||
|    */ | ||||
|   virtual std::int32_t moveRelative(double iposition, std::int32_t ivelocity) = 0; | ||||
|  | ||||
|   /** | ||||
|    * Sets the velocity for the motor. | ||||
|    * | ||||
|    * This velocity corresponds to different actual speeds depending on the gearset | ||||
|    * used for the motor. This results in a range of +-100 for pros::c::red, | ||||
|    * +-200 for green, and +-600 for blue. The velocity | ||||
|    * is held with PID to ensure consistent speed, as opposed to setting the motor's | ||||
|    * voltage. | ||||
|    * | ||||
|    * This function uses the following values of errno when an error state is reached: | ||||
|    * EACCES - Another resource is currently trying to access the port. | ||||
|    * | ||||
|    * @param ivelocity The new motor velocity from -+-100, +-200, or +-600 depending on the motor's | ||||
|    * gearset | ||||
|    * @return 1 if the operation was successful or PROS_ERR if the operation failed, setting errno. | ||||
|    */ | ||||
|   virtual std::int32_t moveVelocity(std::int16_t ivelocity) = 0; | ||||
|  | ||||
|   /** | ||||
|    * Sets the voltage for the motor from -12000 to 12000. | ||||
|    * | ||||
|    * This function uses the following values of errno when an error state is reached: | ||||
|    * EACCES - Another resource is currently trying to access the port. | ||||
|    * | ||||
|    * @param ivoltage The new voltage value from -12000 to 12000 | ||||
|    * @return 1 if the operation was successful or PROS_ERR if the operation failed, setting errno. | ||||
|    */ | ||||
|   virtual std::int32_t moveVoltage(std::int16_t ivoltage) = 0; | ||||
|  | ||||
|   /** | ||||
|    * Changes the output velocity for a profiled movement (moveAbsolute or moveRelative). This will | ||||
|    * have no effect if the motor is not following a profiled movement. | ||||
|    * | ||||
|    * This function uses the following values of errno when an error state is reached: | ||||
|    * EACCES - Another resource is currently trying to access the port. | ||||
|    * | ||||
|    * @param ivelocity The new motor velocity from -+-100, +-200, or +-600 depending on the motor's | ||||
|    * gearset | ||||
|    * @return 1 if the operation was successful or PROS_ERR if the operation failed, setting errno. | ||||
|    */ | ||||
|   virtual std::int32_t modifyProfiledVelocity(std::int32_t ivelocity) = 0; | ||||
|  | ||||
|   /******************************************************************************/ | ||||
|   /**                        Motor telemetry functions                         **/ | ||||
|   /**                                                                          **/ | ||||
|   /**    These functions allow programmers to collect telemetry from motors    **/ | ||||
|   /******************************************************************************/ | ||||
|  | ||||
|   /** | ||||
|    * Gets the target position set for the motor by the user. | ||||
|    * | ||||
|    * This function uses the following values of errno when an error state is reached: | ||||
|    * EACCES - Another resource is currently trying to access the port. | ||||
|    * | ||||
|    * @return The target position in its encoder units or PROS_ERR_F if the operation failed, | ||||
|    * setting errno. | ||||
|    */ | ||||
|   virtual double getTargetPosition() = 0; | ||||
|  | ||||
|   /** | ||||
|    * Gets the absolute position of the motor in its encoder units. | ||||
|    * | ||||
|    * This function uses the following values of errno when an error state is reached: | ||||
|    * EACCES - Another resource is currently trying to access the port. | ||||
|    * | ||||
|    * @return The motor's absolute position in its encoder units or PROS_ERR_F if the operation | ||||
|    * failed, setting errno. | ||||
|    */ | ||||
|   virtual double getPosition() = 0; | ||||
|  | ||||
|   /** | ||||
|    * Gets the positional error (target position minus actual position) of the motor in its encoder | ||||
|    * units. | ||||
|    * | ||||
|    * This function uses the following values of errno when an error state is reached: | ||||
|    * EACCES - Another resource is currently trying to access the port. | ||||
|    * | ||||
|    * @return The motor's positional error in its encoder units or PROS_ERR_F if the operation | ||||
|    * failed, setting errno. | ||||
|    */ | ||||
|   double getPositionError(); | ||||
|  | ||||
|   /** | ||||
|    * Sets the "absolute" zero position of the motor to its current position. | ||||
|    * | ||||
|    * This function uses the following values of errno when an error state is reached: | ||||
|    * EACCES - Another resource is currently trying to access the port. | ||||
|    * | ||||
|    * @return 1 if the operation was successful or PROS_ERR if the operation failed, setting errno. | ||||
|    */ | ||||
|   virtual std::int32_t tarePosition() = 0; | ||||
|  | ||||
|   /** | ||||
|    * Gets the velocity commanded to the motor by the user. | ||||
|    * | ||||
|    * This function uses the following values of errno when an error state is reached: | ||||
|    * EACCES - Another resource is currently trying to access the port. | ||||
|    * | ||||
|    * @return The commanded motor velocity from +-100, +-200, or +-600, or PROS_ERR if the operation | ||||
|    * failed, setting errno. | ||||
|    */ | ||||
|   virtual std::int32_t getTargetVelocity() = 0; | ||||
|  | ||||
|   /** | ||||
|    * Gets the actual velocity of the motor. | ||||
|    * | ||||
|    * This function uses the following values of errno when an error state is reached: | ||||
|    * EACCES - Another resource is currently trying to access the port. | ||||
|    * | ||||
|    * @return The motor's actual velocity in RPM or PROS_ERR_F if the operation failed, setting | ||||
|    * errno. | ||||
|    */ | ||||
|   virtual double getActualVelocity() = 0; | ||||
|  | ||||
|   /** | ||||
|    * Gets the difference between the target velocity of the motor and the actual velocity of the | ||||
|    * motor. | ||||
|    * | ||||
|    * This function uses the following values of errno when an error state is reached: | ||||
|    * EACCES - Another resource is currently trying to access the port. | ||||
|    * | ||||
|    * @return The motor's velocity error in RPM or PROS_ERR_F if the operation failed, setting | ||||
|    * errno. | ||||
|    */ | ||||
|   double getVelocityError(); | ||||
|  | ||||
|   /** | ||||
|    * Gets the current drawn by the motor in mA. | ||||
|    * | ||||
|    * This function uses the following values of errno when an error state is | ||||
|    * reached: | ||||
|    * EACCES - Another resource is currently trying to access the port. | ||||
|    * | ||||
|    * @return The motor's current in mA or PROS_ERR if the operation failed, setting errno. | ||||
|    */ | ||||
|   virtual std::int32_t getCurrentDraw() = 0; | ||||
|  | ||||
|   /** | ||||
|    * Gets the direction of movement for the motor. | ||||
|    * | ||||
|    * This function uses the following values of errno when an error state is | ||||
|    * reached: | ||||
|    * EACCES - Another resource is currently trying to access the port. | ||||
|    * | ||||
|    * @return 1 for moving in the positive direction, -1 for moving in the negative direction, and | ||||
|    * PROS_ERR if the operation failed, setting errno. | ||||
|    */ | ||||
|   virtual std::int32_t getDirection() = 0; | ||||
|  | ||||
|   /** | ||||
|    * Gets the efficiency of the motor in percent. | ||||
|    * | ||||
|    * An efficiency of 100% means that the motor is moving electrically while | ||||
|    * drawing no electrical power, and an efficiency of 0% means that the motor | ||||
|    * is drawing power but not moving. | ||||
|    * | ||||
|    * This function uses the following values of errno when an error state is | ||||
|    * reached: | ||||
|    * EACCES - Another resource is currently trying to access the port. | ||||
|    * | ||||
|    * @return The motor's efficiency in percent or PROS_ERR_F if the operation failed, setting errno. | ||||
|    */ | ||||
|   virtual double getEfficiency() = 0; | ||||
|  | ||||
|   /** | ||||
|    * Checks if the motor is drawing over its current limit. | ||||
|    * | ||||
|    * This function uses the following values of errno when an error state is | ||||
|    * reached: | ||||
|    * EACCES - Another resource is currently trying to access the port. | ||||
|    * | ||||
|    * @return 1 if the motor's current limit is being exceeded and 0 if the current limit is not | ||||
|    * exceeded, or PROS_ERR if the operation failed, setting errno. | ||||
|    */ | ||||
|   virtual std::int32_t isOverCurrent() = 0; | ||||
|  | ||||
|   /** | ||||
|    * Checks if the motor's temperature is above its limit. | ||||
|    * | ||||
|    * This function uses the following values of errno when an error state is | ||||
|    * reached: | ||||
|    * EACCES - Another resource is currently trying to access the port. | ||||
|    * | ||||
|    * @return 1 if the temperature limit is exceeded and 0 if the the temperature is below the limit, | ||||
|    * or PROS_ERR if the operation failed, setting errno. | ||||
|    */ | ||||
|   virtual std::int32_t isOverTemp() = 0; | ||||
|  | ||||
|   /** | ||||
|    * Checks if the motor is stopped. | ||||
|    * | ||||
|    * Although this function forwards data from the motor, the motor presently does not provide any | ||||
|    * value. This function returns PROS_ERR with errno set to ENOSYS. | ||||
|    * | ||||
|    * @return 1 if the motor is not moving, 0 if the motor is moving, or PROS_ERR if the operation | ||||
|    * failed, setting errno | ||||
|    */ | ||||
|   virtual std::int32_t isStopped() = 0; | ||||
|  | ||||
|   /** | ||||
|    * Checks if the motor is at its zero position. | ||||
|    * | ||||
|    * Although this function forwards data from the motor, the motor presently does not provide any | ||||
|    * value. This function returns PROS_ERR with errno set to ENOSYS. | ||||
|    * | ||||
|    * @return 1 if the motor is at zero absolute position, 0 if the motor has moved from its absolute | ||||
|    * zero, or PROS_ERR if the operation failed, setting errno | ||||
|    */ | ||||
|   virtual std::int32_t getZeroPositionFlag() = 0; | ||||
|  | ||||
|   /** | ||||
|    * Gets the faults experienced by the motor. Compare this bitfield to the bitmasks in | ||||
|    * pros::motor_fault_e_t. | ||||
|    * | ||||
|    * This function uses the following values of errno when an error state is | ||||
|    * reached: | ||||
|    * EACCES - Another resource is currently trying to access the port. | ||||
|    * | ||||
|    * @return A currently unknown bitfield containing the motor's faults. 0b00000100 = Current Limit | ||||
|    * Hit | ||||
|    */ | ||||
|   virtual uint32_t getFaults() = 0; | ||||
|  | ||||
|   /** | ||||
|    * Gets the flags set by the motor's operation. Compare this bitfield to the bitmasks in | ||||
|    * pros::motor_flag_e_t. | ||||
|    * | ||||
|    * This function uses the following values of errno when an error state is | ||||
|    * reached: | ||||
|    * EACCES - Another resource is currently trying to access the port. | ||||
|    * | ||||
|    * @return A currently unknown bitfield containing the motor's flags. These seem to be unrelated | ||||
|    * to the individual get_specific_flag functions | ||||
|    */ | ||||
|   virtual uint32_t getFlags() = 0; | ||||
|  | ||||
|   /** | ||||
|    * Gets the raw encoder count of the motor at a given timestamp. | ||||
|    * | ||||
|    * This function uses the following values of errno when an error state is | ||||
|    * reached: | ||||
|    * EACCES - Another resource is currently trying to access the port. | ||||
|    * | ||||
|    * @param timestamp A pointer to a time in milliseconds for which the encoder count will be | ||||
|    * returned. If NULL, the timestamp at which the encoder count was read will not be supplied | ||||
|    * | ||||
|    * @return The raw encoder count at the given timestamp or PROS_ERR if the operation failed. | ||||
|    */ | ||||
|   virtual std::int32_t getRawPosition(std::uint32_t *timestamp) = 0; | ||||
|  | ||||
|   /** | ||||
|    * Gets the power drawn by the motor in Watts. | ||||
|    * | ||||
|    * This function uses the following values of errno when an error state is | ||||
|    * reached: | ||||
|    * EACCES - Another resource is currently trying to access the port. | ||||
|    * | ||||
|    * @return The motor's power draw in Watts or PROS_ERR_F if the operation failed, setting errno. | ||||
|    */ | ||||
|   virtual double getPower() = 0; | ||||
|  | ||||
|   /** | ||||
|    * Gets the temperature of the motor in degrees Celsius. | ||||
|    * | ||||
|    * This function uses the following values of errno when an error state is | ||||
|    * reached: | ||||
|    * EACCES - Another resource is currently trying to access the port. | ||||
|    * | ||||
|    * @return The motor's temperature in degrees Celsius or PROS_ERR_F if the operation failed, | ||||
|    * setting errno. | ||||
|    */ | ||||
|   virtual double getTemperature() = 0; | ||||
|  | ||||
|   /** | ||||
|    * Gets the torque generated by the motor in Newton Metres (Nm). | ||||
|    * | ||||
|    * This function uses the following values of errno when an error state is | ||||
|    * reached: | ||||
|    * EACCES - Another resource is currently trying to access the port. | ||||
|    * | ||||
|    * @return The motor's torque in NM or PROS_ERR_F if the operation failed, setting errno. | ||||
|    */ | ||||
|   virtual double getTorque() = 0; | ||||
|  | ||||
|   /** | ||||
|    * Gets the voltage delivered to the motor in millivolts. | ||||
|    * | ||||
|    * This function uses the following values of errno when an error state is | ||||
|    * reached: | ||||
|    * EACCES - Another resource is currently trying to access the port. | ||||
|    * | ||||
|    * @return The motor's voltage in V or PROS_ERR_F if the operation failed, setting errno. | ||||
|    */ | ||||
|   virtual std::int32_t getVoltage() = 0; | ||||
|  | ||||
|   /******************************************************************************/ | ||||
|   /**                      Motor configuration functions                       **/ | ||||
|   /**                                                                          **/ | ||||
|   /**  These functions allow programmers to configure the behavior of motors   **/ | ||||
|   /******************************************************************************/ | ||||
|  | ||||
|   /** | ||||
|    * Sets one of brakeMode to the motor. | ||||
|    * | ||||
|    * This function uses the following values of errno when an error state is reached: | ||||
|    * EACCES - Another resource is currently trying to access the port. | ||||
|    * | ||||
|    * @param imode The new motor brake mode to set for the motor | ||||
|    * @return 1 if the operation was successful or PROS_ERR if the operation failed, setting errno. | ||||
|    */ | ||||
|   virtual std::int32_t setBrakeMode(brakeMode imode) = 0; | ||||
|  | ||||
|   /** | ||||
|    * Gets the brake mode that was set for the motor. | ||||
|    * | ||||
|    * This function uses the following values of errno when an error state is reached: | ||||
|    * EACCES - Another resource is currently trying to access the port. | ||||
|    * | ||||
|    * @return One of brakeMode, according to what was set for the motor, or brakeMode::invalid if the | ||||
|    * operation failed, setting errno. | ||||
|    */ | ||||
|   virtual brakeMode getBrakeMode() = 0; | ||||
|  | ||||
|   /** | ||||
|    * Sets the current limit for the motor in mA. | ||||
|    * | ||||
|    * This function uses the following values of errno when an error state is reached: | ||||
|    * EACCES - Another resource is currently trying to access the port. | ||||
|    * | ||||
|    * @param ilimit The new current limit in mA | ||||
|    * @return 1 if the operation was successful or PROS_ERR if the operation failed, setting errno. | ||||
|    */ | ||||
|   virtual std::int32_t setCurrentLimit(std::int32_t ilimit) = 0; | ||||
|  | ||||
|   /** | ||||
|    * Gets the current limit for the motor in mA. | ||||
|    * | ||||
|    * The default value is 2500 mA. | ||||
|    * | ||||
|    * This function uses the following values of errno when an error state is reached: | ||||
|    * EACCES - Another resource is currently trying to access the port. | ||||
|    * | ||||
|    * @return The motor's current limit in mA or PROS_ERR if the operation failed, setting errno. | ||||
|    */ | ||||
|   virtual std::int32_t getCurrentLimit() = 0; | ||||
|  | ||||
|   /** | ||||
|    * Sets one of encoderUnits for the motor encoder. | ||||
|    * | ||||
|    * This function uses the following values of errno when an error state is reached: | ||||
|    * EACCES - Another resource is currently trying to access the port. | ||||
|    * | ||||
|    * @param iunits The new motor encoder units | ||||
|    * @return 1 if the operation was successful or PROS_ERR if the operation failed, setting errno. | ||||
|    */ | ||||
|   virtual std::int32_t setEncoderUnits(encoderUnits iunits) = 0; | ||||
|  | ||||
|   /** | ||||
|    * Gets the encoder units that were set for the motor. | ||||
|    * | ||||
|    * This function uses the following values of errno when an error state is reached: | ||||
|    * EACCES - Another resource is currently trying to access the port. | ||||
|    * | ||||
|    * @return One of encoderUnits according to what is set for the motor or encoderUnits::invalid if | ||||
|    * the operation failed. | ||||
|    */ | ||||
|   virtual encoderUnits getEncoderUnits() = 0; | ||||
|  | ||||
|   /** | ||||
|    * Sets one of gearset for the motor. | ||||
|    * | ||||
|    * This function uses the following values of errno when an error state is reached: | ||||
|    * EACCES - Another resource is currently trying to access the port. | ||||
|    * | ||||
|    * @param igearset The new motor gearset | ||||
|    * @return 1 if the operation was successful or PROS_ERR if the operation failed, setting errno. | ||||
|    */ | ||||
|   virtual std::int32_t setGearing(gearset igearset) = 0; | ||||
|  | ||||
|   /** | ||||
|    * Gets the gearset that was set for the motor. | ||||
|    * | ||||
|    * This function uses the following values of errno when an error state is reached: | ||||
|    * EACCES - Another resource is currently trying to access the port. | ||||
|    * | ||||
|    * @return One of gearset according to what is set for the motor, or gearset::invalid if the | ||||
|    * operation failed. | ||||
|    */ | ||||
|   virtual gearset getGearing() = 0; | ||||
|  | ||||
|   /** | ||||
|    * Sets the reverse flag for the motor. | ||||
|    * | ||||
|    * This will invert its movements and the values returned for its position. | ||||
|    * | ||||
|    * This function uses the following values of errno when an error state is reached: | ||||
|    * EACCES - Another resource is currently trying to access the port. | ||||
|    * | ||||
|    * @param ireverse True reverses the motor, false is default | ||||
|    * @return 1 if the operation was successful or PROS_ERR if the operation failed, setting errno. | ||||
|    */ | ||||
|   virtual std::int32_t setReversed(bool ireverse) = 0; | ||||
|  | ||||
|   /** | ||||
|    * Sets the voltage limit for the motor in Volts. | ||||
|    * | ||||
|    * This function uses the following values of errno when an error state is reached: | ||||
|    * EACCES - Another resource is currently trying to access the port. | ||||
|    * | ||||
|    * @param ilimit The new voltage limit in Volts | ||||
|    * @return 1 if the operation was successful or PROS_ERR if the operation failed, setting errno. | ||||
|    */ | ||||
|   virtual std::int32_t setVoltageLimit(std::int32_t ilimit) = 0; | ||||
|  | ||||
|   /** | ||||
|    * Returns the encoder associated with this motor. | ||||
|    * | ||||
|    * @return the encoder for this motor | ||||
|    */ | ||||
|   virtual std::shared_ptr<ContinuousRotarySensor> getEncoder() = 0; | ||||
| }; | ||||
|  | ||||
| AbstractMotor::GearsetRatioPair operator*(AbstractMotor::gearset gearset, double ratio); | ||||
|  | ||||
| } // namespace okapi | ||||
| @@ -0,0 +1,20 @@ | ||||
| /* | ||||
|  * This Source Code Form is subject to the terms of the Mozilla Public | ||||
|  * License, v. 2.0. If a copy of the MPL was not distributed with this | ||||
|  * file, You can obtain one at http://mozilla.org/MPL/2.0/. | ||||
|  */ | ||||
| #pragma once | ||||
|  | ||||
| #include "okapi/api/device/rotarysensor/rotarySensor.hpp" | ||||
|  | ||||
| namespace okapi { | ||||
| class ContinuousRotarySensor : public RotarySensor { | ||||
|   public: | ||||
|   /** | ||||
|    * Reset the sensor to zero. | ||||
|    * | ||||
|    * @return `1` on success, `PROS_ERR` on fail | ||||
|    */ | ||||
|   virtual std::int32_t reset() = 0; | ||||
| }; | ||||
| } // namespace okapi | ||||
| @@ -0,0 +1,23 @@ | ||||
| /* | ||||
|  * This Source Code Form is subject to the terms of the Mozilla Public | ||||
|  * License, v. 2.0. If a copy of the MPL was not distributed with this | ||||
|  * file, You can obtain one at http://mozilla.org/MPL/2.0/. | ||||
|  */ | ||||
| #pragma once | ||||
|  | ||||
| #include "okapi/api/control/controllerInput.hpp" | ||||
| #include "okapi/api/coreProsAPI.hpp" | ||||
|  | ||||
| namespace okapi { | ||||
| class RotarySensor : public ControllerInput<double> { | ||||
|   public: | ||||
|   virtual ~RotarySensor(); | ||||
|  | ||||
|   /** | ||||
|    * Get the current sensor value. | ||||
|    * | ||||
|    * @return the current sensor value, or `PROS_ERR` on a failure. | ||||
|    */ | ||||
|   virtual double get() const = 0; | ||||
| }; | ||||
| } // namespace okapi | ||||
							
								
								
									
										59
									
								
								SerialTest/include/okapi/api/filter/averageFilter.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										59
									
								
								SerialTest/include/okapi/api/filter/averageFilter.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,59 @@ | ||||
| /* | ||||
|  * This Source Code Form is subject to the terms of the Mozilla Public | ||||
|  * License, v. 2.0. If a copy of the MPL was not distributed with this | ||||
|  * file, You can obtain one at http://mozilla.org/MPL/2.0/. | ||||
|  */ | ||||
| #pragma once | ||||
|  | ||||
| #include "okapi/api/filter/filter.hpp" | ||||
| #include <array> | ||||
| #include <cstddef> | ||||
|  | ||||
| namespace okapi { | ||||
| /** | ||||
|  * A filter which returns the average of a list of values. | ||||
|  * | ||||
|  * @tparam n number of taps in the filter | ||||
|  */ | ||||
| template <std::size_t n> class AverageFilter : public Filter { | ||||
|   public: | ||||
|   /** | ||||
|    * Averaging filter. | ||||
|    */ | ||||
|   AverageFilter() = default; | ||||
|  | ||||
|   /** | ||||
|    * Filters a value, like a sensor reading. | ||||
|    * | ||||
|    * @param ireading new measurement | ||||
|    * @return filtered result | ||||
|    */ | ||||
|   double filter(const double ireading) override { | ||||
|     data[index++] = ireading; | ||||
|     if (index >= n) { | ||||
|       index = 0; | ||||
|     } | ||||
|  | ||||
|     output = 0.0; | ||||
|     for (size_t i = 0; i < n; i++) | ||||
|       output += data[i]; | ||||
|     output /= (double)n; | ||||
|  | ||||
|     return output; | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * Returns the previous output from filter. | ||||
|    * | ||||
|    * @return the previous output from filter | ||||
|    */ | ||||
|   double getOutput() const override { | ||||
|     return output; | ||||
|   } | ||||
|  | ||||
|   protected: | ||||
|   std::array<double, n> data{0}; | ||||
|   std::size_t index = 0; | ||||
|   double output = 0; | ||||
| }; | ||||
| } // namespace okapi | ||||
							
								
								
									
										50
									
								
								SerialTest/include/okapi/api/filter/composableFilter.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										50
									
								
								SerialTest/include/okapi/api/filter/composableFilter.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,50 @@ | ||||
| /* | ||||
|  * This Source Code Form is subject to the terms of the Mozilla Public | ||||
|  * License, v. 2.0. If a copy of the MPL was not distributed with this | ||||
|  * file, You can obtain one at http://mozilla.org/MPL/2.0/. | ||||
|  */ | ||||
| #pragma once | ||||
|  | ||||
| #include "okapi/api/filter/filter.hpp" | ||||
| #include <functional> | ||||
| #include <initializer_list> | ||||
| #include <memory> | ||||
| #include <vector> | ||||
|  | ||||
| namespace okapi { | ||||
| class ComposableFilter : public Filter { | ||||
|   public: | ||||
|   /** | ||||
|    * A composable filter is a filter that consists of other filters. The input signal is passed | ||||
|    * through each filter in sequence. The final output of this filter is the output of the last | ||||
|    * filter. | ||||
|    * | ||||
|    * @param ilist The filters to use in sequence. | ||||
|    */ | ||||
|   ComposableFilter(const std::initializer_list<std::shared_ptr<Filter>> &ilist); | ||||
|  | ||||
|   /** | ||||
|    * Filters a value. | ||||
|    * | ||||
|    * @param ireading A new measurement. | ||||
|    * @return The filtered result. | ||||
|    */ | ||||
|   double filter(double ireading) override; | ||||
|  | ||||
|   /** | ||||
|    * @return The previous output from filter. | ||||
|    */ | ||||
|   double getOutput() const override; | ||||
|  | ||||
|   /** | ||||
|    * Adds a filter to the end of the sequence. | ||||
|    * | ||||
|    * @param ifilter The filter to add. | ||||
|    */ | ||||
|   virtual void addFilter(std::shared_ptr<Filter> ifilter); | ||||
|  | ||||
|   protected: | ||||
|   std::vector<std::shared_ptr<Filter>> filters; | ||||
|   double output = 0; | ||||
| }; | ||||
| } // namespace okapi | ||||
							
								
								
									
										52
									
								
								SerialTest/include/okapi/api/filter/demaFilter.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										52
									
								
								SerialTest/include/okapi/api/filter/demaFilter.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,52 @@ | ||||
| /* | ||||
|  * This Source Code Form is subject to the terms of the Mozilla Public | ||||
|  * License, v. 2.0. If a copy of the MPL was not distributed with this | ||||
|  * file, You can obtain one at http://mozilla.org/MPL/2.0/. | ||||
|  */ | ||||
| #pragma once | ||||
|  | ||||
| #include "okapi/api/filter/filter.hpp" | ||||
| #include <ratio> | ||||
|  | ||||
| namespace okapi { | ||||
| class DemaFilter : public Filter { | ||||
|   public: | ||||
|   /** | ||||
|    * Double exponential moving average filter. | ||||
|    * | ||||
|    * @param ialpha alpha gain | ||||
|    * @param ibeta beta gain | ||||
|    */ | ||||
|   DemaFilter(double ialpha, double ibeta); | ||||
|  | ||||
|   /** | ||||
|    * Filters a value, like a sensor reading. | ||||
|    * | ||||
|    * @param reading new measurement | ||||
|    * @return filtered result | ||||
|    */ | ||||
|   double filter(double ireading) override; | ||||
|  | ||||
|   /** | ||||
|    * Returns the previous output from filter. | ||||
|    * | ||||
|    * @return the previous output from filter | ||||
|    */ | ||||
|   double getOutput() const override; | ||||
|  | ||||
|   /** | ||||
|    * Set filter gains. | ||||
|    * | ||||
|    * @param ialpha alpha gain | ||||
|    * @param ibeta beta gain | ||||
|    */ | ||||
|   virtual void setGains(double ialpha, double ibeta); | ||||
|  | ||||
|   protected: | ||||
|   double alpha, beta; | ||||
|   double outputS = 0; | ||||
|   double lastOutputS = 0; | ||||
|   double outputB = 0; | ||||
|   double lastOutputB = 0; | ||||
| }; | ||||
| } // namespace okapi | ||||
							
								
								
									
										71
									
								
								SerialTest/include/okapi/api/filter/ekfFilter.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										71
									
								
								SerialTest/include/okapi/api/filter/ekfFilter.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,71 @@ | ||||
| /* | ||||
|  * This Source Code Form is subject to the terms of the Mozilla Public | ||||
|  * License, v. 2.0. If a copy of the MPL was not distributed with this | ||||
|  * file, You can obtain one at http://mozilla.org/MPL/2.0/. | ||||
|  */ | ||||
| #pragma once | ||||
|  | ||||
| #include "okapi/api/filter/filter.hpp" | ||||
| #include "okapi/api/util/mathUtil.hpp" | ||||
|  | ||||
| namespace okapi { | ||||
| class EKFFilter : public Filter { | ||||
|   public: | ||||
|   /** | ||||
|    * One dimensional extended Kalman filter. The default arguments should work fine for most signal | ||||
|    * filtering. It won't hurt to graph your signal and the filtered result, and check if the filter | ||||
|    * is doing its job. | ||||
|    * | ||||
|    * Q is the covariance of the process noise and R is the | ||||
|    * covariance of the observation noise. The default values for Q and R should be a modest balance | ||||
|    * between trust in the sensor and FIR filtering. | ||||
|    * | ||||
|    * Think of R as how noisy your sensor is. Its value can be found mathematically by computing the | ||||
|    * standard deviation of your sensor reading vs. "truth" (of course, "truth" is still an estimate; | ||||
|    * try to calibrate your robot in a controlled setting where you can minimize the error in what | ||||
|    * "truth" is). | ||||
|    * | ||||
|    * Think of Q as how noisy your model is. It decides how much "smoothing" the filter does and how | ||||
|    * far it lags behind the true signal. This parameter is most often used as a "tuning" parameter | ||||
|    * to adjust the response of the filter. | ||||
|    * | ||||
|    * @param iQ process noise covariance | ||||
|    * @param iR measurement noise covariance | ||||
|    */ | ||||
|   explicit EKFFilter(double iQ = 0.0001, double iR = ipow(0.2, 2)); | ||||
|  | ||||
|   /** | ||||
|    * Filters a value, like a sensor reading. Assumes the control input is zero. | ||||
|    * | ||||
|    * @param ireading new measurement | ||||
|    * @return filtered result | ||||
|    */ | ||||
|   double filter(double ireading) override; | ||||
|  | ||||
|   /** | ||||
|    * Filters a reading with a control input. | ||||
|    * | ||||
|    * @param ireading new measurement | ||||
|    * @param icontrol control input | ||||
|    * @return filtered result | ||||
|    */ | ||||
|   virtual double filter(double ireading, double icontrol); | ||||
|  | ||||
|   /** | ||||
|    * Returns the previous output from filter. | ||||
|    * | ||||
|    * @return the previous output from filter | ||||
|    */ | ||||
|   double getOutput() const override; | ||||
|  | ||||
|   protected: | ||||
|   const double Q, R; | ||||
|   double xHat = 0; | ||||
|   double xHatPrev = 0; | ||||
|   double xHatMinus = 0; | ||||
|   double P = 0; | ||||
|   double Pprev = 1; | ||||
|   double Pminus = 0; | ||||
|   double K = 0; | ||||
| }; | ||||
| } // namespace okapi | ||||
							
								
								
									
										47
									
								
								SerialTest/include/okapi/api/filter/emaFilter.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										47
									
								
								SerialTest/include/okapi/api/filter/emaFilter.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,47 @@ | ||||
| /* | ||||
|  * This Source Code Form is subject to the terms of the Mozilla Public | ||||
|  * License, v. 2.0. If a copy of the MPL was not distributed with this | ||||
|  * file, You can obtain one at http://mozilla.org/MPL/2.0/. | ||||
|  */ | ||||
| #pragma once | ||||
|  | ||||
| #include "okapi/api/filter/filter.hpp" | ||||
|  | ||||
| namespace okapi { | ||||
| class EmaFilter : public Filter { | ||||
|   public: | ||||
|   /** | ||||
|    * Exponential moving average filter. | ||||
|    * | ||||
|    * @param ialpha alpha gain | ||||
|    */ | ||||
|   explicit EmaFilter(double ialpha); | ||||
|  | ||||
|   /** | ||||
|    * Filters a value, like a sensor reading. | ||||
|    * | ||||
|    * @param reading new measurement | ||||
|    * @return filtered result | ||||
|    */ | ||||
|   double filter(double ireading) override; | ||||
|  | ||||
|   /** | ||||
|    * Returns the previous output from filter. | ||||
|    * | ||||
|    * @return the previous output from filter | ||||
|    */ | ||||
|   double getOutput() const override; | ||||
|  | ||||
|   /** | ||||
|    * Set filter gains. | ||||
|    * | ||||
|    * @param ialpha alpha gain | ||||
|    */ | ||||
|   virtual void setGains(double ialpha); | ||||
|  | ||||
|   protected: | ||||
|   double alpha; | ||||
|   double output = 0; | ||||
|   double lastOutput = 0; | ||||
| }; | ||||
| } // namespace okapi | ||||
							
								
								
									
										28
									
								
								SerialTest/include/okapi/api/filter/filter.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								SerialTest/include/okapi/api/filter/filter.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,28 @@ | ||||
| /* | ||||
|  * This Source Code Form is subject to the terms of the Mozilla Public | ||||
|  * License, v. 2.0. If a copy of the MPL was not distributed with this | ||||
|  * file, You can obtain one at http://mozilla.org/MPL/2.0/. | ||||
|  */ | ||||
| #pragma once | ||||
|  | ||||
| namespace okapi { | ||||
| class Filter { | ||||
|   public: | ||||
|   virtual ~Filter(); | ||||
|  | ||||
|   /** | ||||
|    * Filters a value, like a sensor reading. | ||||
|    * | ||||
|    * @param ireading new measurement | ||||
|    * @return filtered result | ||||
|    */ | ||||
|   virtual double filter(double ireading) = 0; | ||||
|  | ||||
|   /** | ||||
|    * Returns the previous output from filter. | ||||
|    * | ||||
|    * @return the previous output from filter | ||||
|    */ | ||||
|   virtual double getOutput() const = 0; | ||||
| }; | ||||
| } // namespace okapi | ||||
| @@ -0,0 +1,48 @@ | ||||
| /* | ||||
|  * This Source Code Form is subject to the terms of the Mozilla Public | ||||
|  * License, v. 2.0. If a copy of the MPL was not distributed with this | ||||
|  * file, You can obtain one at http://mozilla.org/MPL/2.0/. | ||||
|  */ | ||||
| #pragma once | ||||
|  | ||||
| #include "okapi/api/control/controllerInput.hpp" | ||||
| #include "okapi/api/filter/filter.hpp" | ||||
| #include <memory> | ||||
|  | ||||
| namespace okapi { | ||||
| /** | ||||
|  * A ControllerInput with a filter built in. | ||||
|  * | ||||
|  * @tparam InputType the type of the ControllerInput | ||||
|  * @tparam FilterType the type of the Filter | ||||
|  */ | ||||
| template <typename InputType, typename FilterType> | ||||
| class FilteredControllerInput : public ControllerInput<double> { | ||||
|   public: | ||||
|   /** | ||||
|    * A filtered controller input. Applies a filter to the controller input. Useful if you want to | ||||
|    * place a filter between a control input and a control loop. | ||||
|    * | ||||
|    * @param iinput ControllerInput type | ||||
|    * @param ifilter Filter type | ||||
|    */ | ||||
|   FilteredControllerInput(std::unique_ptr<ControllerInput<InputType>> iinput, | ||||
|                           std::unique_ptr<FilterType> ifilter) | ||||
|     : input(std::move(iinput)), filter(std::move(ifilter)) { | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * Gets the sensor value for use in a control loop. This method might be automatically called in | ||||
|    * another thread by the controller. | ||||
|    * | ||||
|    * @return the current filtered sensor value. | ||||
|    */ | ||||
|   double controllerGet() override { | ||||
|     return filter->filter(input->controllerGet()); | ||||
|   } | ||||
|  | ||||
|   protected: | ||||
|   std::unique_ptr<ControllerInput<InputType>> input; | ||||
|   std::unique_ptr<FilterType> filter; | ||||
| }; | ||||
| } // namespace okapi | ||||
							
								
								
									
										94
									
								
								SerialTest/include/okapi/api/filter/medianFilter.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										94
									
								
								SerialTest/include/okapi/api/filter/medianFilter.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,94 @@ | ||||
| /* | ||||
|  * Uses the median filter algorithm from N. Wirth’s book, implementation by N. Devillard. | ||||
|  * | ||||
|  * This Source Code Form is subject to the terms of the Mozilla Public | ||||
|  * License, v. 2.0. If a copy of the MPL was not distributed with this | ||||
|  * file, You can obtain one at http://mozilla.org/MPL/2.0/. | ||||
|  */ | ||||
| #pragma once | ||||
|  | ||||
| #include "okapi/api/filter/filter.hpp" | ||||
| #include <algorithm> | ||||
| #include <array> | ||||
| #include <cstddef> | ||||
|  | ||||
| namespace okapi { | ||||
| /** | ||||
|  * A filter which returns the median value of list of values. | ||||
|  * | ||||
|  * @tparam n number of taps in the filter | ||||
|  */ | ||||
| template <std::size_t n> class MedianFilter : public Filter { | ||||
|   public: | ||||
|   MedianFilter() : middleIndex((((n)&1) ? ((n) / 2) : (((n) / 2) - 1))) { | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * Filters a value, like a sensor reading. | ||||
|    * | ||||
|    * @param ireading new measurement | ||||
|    * @return filtered result | ||||
|    */ | ||||
|   double filter(const double ireading) override { | ||||
|     data[index++] = ireading; | ||||
|     if (index >= n) { | ||||
|       index = 0; | ||||
|     } | ||||
|  | ||||
|     output = kth_smallset(); | ||||
|     return output; | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * Returns the previous output from filter. | ||||
|    * | ||||
|    * @return the previous output from filter | ||||
|    */ | ||||
|   double getOutput() const override { | ||||
|     return output; | ||||
|   } | ||||
|  | ||||
|   protected: | ||||
|   std::array<double, n> data{0}; | ||||
|   std::size_t index = 0; | ||||
|   double output = 0; | ||||
|   const size_t middleIndex; | ||||
|  | ||||
|   /** | ||||
|    * Algorithm from N. Wirth’s book, implementation by N. Devillard. | ||||
|    */ | ||||
|   double kth_smallset() { | ||||
|     std::array<double, n> dataCopy = data; | ||||
|     size_t j, l, m; | ||||
|     l = 0; | ||||
|     m = n - 1; | ||||
|  | ||||
|     while (l < m) { | ||||
|       double x = dataCopy[middleIndex]; | ||||
|       size_t i = l; | ||||
|       j = m; | ||||
|       do { | ||||
|         while (dataCopy[i] < x) { | ||||
|           i++; | ||||
|         } | ||||
|         while (x < dataCopy[j]) { | ||||
|           j--; | ||||
|         } | ||||
|         if (i <= j) { | ||||
|           const double t = dataCopy[i]; | ||||
|           dataCopy[i] = dataCopy[j]; | ||||
|           dataCopy[j] = t; | ||||
|           i++; | ||||
|           j--; | ||||
|         } | ||||
|       } while (i <= j); | ||||
|       if (j < middleIndex) | ||||
|         l = i; | ||||
|       if (middleIndex < i) | ||||
|         m = j; | ||||
|     } | ||||
|  | ||||
|     return dataCopy[middleIndex]; | ||||
|   } | ||||
| }; | ||||
| } // namespace okapi | ||||
							
								
								
									
										36
									
								
								SerialTest/include/okapi/api/filter/passthroughFilter.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										36
									
								
								SerialTest/include/okapi/api/filter/passthroughFilter.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,36 @@ | ||||
| /* | ||||
|  * This Source Code Form is subject to the terms of the Mozilla Public | ||||
|  * License, v. 2.0. If a copy of the MPL was not distributed with this | ||||
|  * file, You can obtain one at http://mozilla.org/MPL/2.0/. | ||||
|  */ | ||||
| #pragma once | ||||
|  | ||||
| #include "okapi/api/filter/filter.hpp" | ||||
|  | ||||
| namespace okapi { | ||||
| class PassthroughFilter : public Filter { | ||||
|   public: | ||||
|   /** | ||||
|    * A simple filter that does no filtering and just passes the input through. | ||||
|    */ | ||||
|   PassthroughFilter(); | ||||
|  | ||||
|   /** | ||||
|    * Filters a value, like a sensor reading. | ||||
|    * | ||||
|    * @param ireading new measurement | ||||
|    * @return filtered result | ||||
|    */ | ||||
|   double filter(double ireading) override; | ||||
|  | ||||
|   /** | ||||
|    * Returns the previous output from filter. | ||||
|    * | ||||
|    * @return the previous output from filter | ||||
|    */ | ||||
|   double getOutput() const override; | ||||
|  | ||||
|   protected: | ||||
|   double lastOutput = 0; | ||||
| }; | ||||
| } // namespace okapi | ||||
							
								
								
									
										74
									
								
								SerialTest/include/okapi/api/filter/velMath.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										74
									
								
								SerialTest/include/okapi/api/filter/velMath.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,74 @@ | ||||
| /* | ||||
|  * This Source Code Form is subject to the terms of the Mozilla Public | ||||
|  * License, v. 2.0. If a copy of the MPL was not distributed with this | ||||
|  * file, You can obtain one at http://mozilla.org/MPL/2.0/. | ||||
|  */ | ||||
| #pragma once | ||||
|  | ||||
| #include "okapi/api/filter/composableFilter.hpp" | ||||
| #include "okapi/api/units/QAngularAcceleration.hpp" | ||||
| #include "okapi/api/units/QAngularSpeed.hpp" | ||||
| #include "okapi/api/units/QTime.hpp" | ||||
| #include "okapi/api/util/abstractTimer.hpp" | ||||
| #include "okapi/api/util/logging.hpp" | ||||
| #include <memory> | ||||
|  | ||||
| namespace okapi { | ||||
| class VelMath { | ||||
|   public: | ||||
|   /** | ||||
|    * Velocity math helper. Calculates filtered velocity. Throws a `std::invalid_argument` exception | ||||
|    * if `iticksPerRev` is zero. | ||||
|    * | ||||
|    * @param iticksPerRev The number of ticks per revolution (or whatever units you are using). | ||||
|    * @param ifilter The filter used for filtering the calculated velocity. | ||||
|    * @param isampleTime The minimum time between velocity measurements. | ||||
|    * @param ilogger The logger this instance will log to. | ||||
|    */ | ||||
|   VelMath(double iticksPerRev, | ||||
|           std::unique_ptr<Filter> ifilter, | ||||
|           QTime isampleTime, | ||||
|           std::unique_ptr<AbstractTimer> iloopDtTimer, | ||||
|           std::shared_ptr<Logger> ilogger = Logger::getDefaultLogger()); | ||||
|  | ||||
|   virtual ~VelMath(); | ||||
|  | ||||
|   /** | ||||
|    * Calculates the current velocity and acceleration. Returns the (filtered) velocity. | ||||
|    * | ||||
|    * @param inewPos The new position measurement. | ||||
|    * @return The new velocity estimate. | ||||
|    */ | ||||
|   virtual QAngularSpeed step(double inewPos); | ||||
|  | ||||
|   /** | ||||
|    * Sets ticks per revolution (or whatever units you are using). Throws a `std::invalid_argument` | ||||
|    * exception if iticksPerRev is zero. | ||||
|    * | ||||
|    * @param iTPR The number of ticks per revolution. | ||||
|    */ | ||||
|   virtual void setTicksPerRev(double iTPR); | ||||
|  | ||||
|   /** | ||||
|    * @return The last calculated velocity. | ||||
|    */ | ||||
|   virtual QAngularSpeed getVelocity() const; | ||||
|  | ||||
|   /** | ||||
|    * @return The last calculated acceleration. | ||||
|    */ | ||||
|   virtual QAngularAcceleration getAccel() const; | ||||
|  | ||||
|   protected: | ||||
|   std::shared_ptr<Logger> logger; | ||||
|   QAngularSpeed vel{0_rpm}; | ||||
|   QAngularSpeed lastVel{0_rpm}; | ||||
|   QAngularAcceleration accel{0.0}; | ||||
|   double lastPos{0}; | ||||
|   double ticksPerRev; | ||||
|  | ||||
|   QTime sampleTime; | ||||
|   std::unique_ptr<AbstractTimer> loopDtTimer; | ||||
|   std::unique_ptr<Filter> filter; | ||||
| }; | ||||
| } // namespace okapi | ||||
							
								
								
									
										95
									
								
								SerialTest/include/okapi/api/odometry/odomMath.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										95
									
								
								SerialTest/include/okapi/api/odometry/odomMath.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,95 @@ | ||||
| /* | ||||
|  * This Source Code Form is subject to the terms of the Mozilla Public | ||||
|  * License, v. 2.0. If a copy of the MPL was not distributed with this | ||||
|  * file, You can obtain one at http://mozilla.org/MPL/2.0/. | ||||
|  */ | ||||
| #pragma once | ||||
|  | ||||
| #include "okapi/api/odometry/odomState.hpp" | ||||
| #include "okapi/api/odometry/point.hpp" | ||||
| #include "okapi/api/util/logging.hpp" | ||||
| #include <tuple> | ||||
|  | ||||
| namespace okapi { | ||||
| class OdomMath { | ||||
|   public: | ||||
|   /** | ||||
|    * Computes the distance from the given Odometry state to the given point. The point and the | ||||
|    * OdomState must be in `StateMode::FRAME_TRANSFORMATION`. | ||||
|    * | ||||
|    * @param ipoint The point. | ||||
|    * @param istate The Odometry state. | ||||
|    * @return The distance between the Odometry state and the point. | ||||
|    */ | ||||
|   static QLength computeDistanceToPoint(const Point &ipoint, const OdomState &istate); | ||||
|  | ||||
|   /** | ||||
|    * Computes the angle from the given Odometry state to the given point. The point and the | ||||
|    * OdomState must be in `StateMode::FRAME_TRANSFORMATION`. | ||||
|    * | ||||
|    * @param ipoint The point. | ||||
|    * @param istate The Odometry state. | ||||
|    * @return The angle between the Odometry state and the point. | ||||
|    */ | ||||
|   static QAngle computeAngleToPoint(const Point &ipoint, const OdomState &istate); | ||||
|  | ||||
|   /** | ||||
|    * Computes the distance and angle from the given Odometry state to the given point. The point and | ||||
|    * the OdomState must be in `StateMode::FRAME_TRANSFORMATION`. | ||||
|    * | ||||
|    * @param ipoint The point. | ||||
|    * @param istate The Odometry state. | ||||
|    * @return The distance and angle between the Odometry state and the point. | ||||
|    */ | ||||
|   static std::pair<QLength, QAngle> computeDistanceAndAngleToPoint(const Point &ipoint, | ||||
|                                                                    const OdomState &istate); | ||||
|  | ||||
|   /** | ||||
|    * Constraints the angle to [0,360] degrees. | ||||
|    * | ||||
|    * @param angle The input angle. | ||||
|    * @return The angle normalized to [0,360] degrees. | ||||
|    */ | ||||
|   static QAngle constrainAngle360(const QAngle &angle); | ||||
|  | ||||
|   /** | ||||
|    * Constraints the angle to [-180,180) degrees. | ||||
|    * | ||||
|    * @param angle The input angle. | ||||
|    * @return The angle normalized to [-180,180) degrees. | ||||
|    */ | ||||
|   static QAngle constrainAngle180(const QAngle &angle); | ||||
|  | ||||
|   private: | ||||
|   OdomMath(); | ||||
|   ~OdomMath(); | ||||
|  | ||||
|   /** | ||||
|    * Computes the x and y diffs in meters between the points. | ||||
|    * | ||||
|    * @param ipoint The point. | ||||
|    * @param istate The Odometry state. | ||||
|    * @return The diffs in the order `{xDiff, yDiff}`. | ||||
|    */ | ||||
|   static std::pair<double, double> computeDiffs(const Point &ipoint, const OdomState &istate); | ||||
|  | ||||
|   /** | ||||
|    * Computes the distance between the points. | ||||
|    * | ||||
|    * @param xDiff The x-axis diff in meters. | ||||
|    * @param yDiff The y-axis diff in meters. | ||||
|    * @return The cartesian distance in meters. | ||||
|    */ | ||||
|   static double computeDistance(double xDiff, double yDiff); | ||||
|  | ||||
|   /** | ||||
|    * Compites the angle between the points. | ||||
|    * | ||||
|    * @param xDiff The x-axis diff in meters. | ||||
|    * @param yDiff The y-axis diff in meters. | ||||
|    * @param theta The current robot's theta in radians. | ||||
|    * @return The angle in radians. | ||||
|    */ | ||||
|   static double computeAngle(double xDiff, double yDiff, double theta); | ||||
| }; | ||||
| } // namespace okapi | ||||
							
								
								
									
										57
									
								
								SerialTest/include/okapi/api/odometry/odomState.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										57
									
								
								SerialTest/include/okapi/api/odometry/odomState.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,57 @@ | ||||
| /* | ||||
|  * This Source Code Form is subject to the terms of the Mozilla Public | ||||
|  * License, v. 2.0. If a copy of the MPL was not distributed with this | ||||
|  * file, You can obtain one at http://mozilla.org/MPL/2.0/. | ||||
|  */ | ||||
| #pragma once | ||||
|  | ||||
| #include "okapi/api/units/QAngle.hpp" | ||||
| #include "okapi/api/units/QLength.hpp" | ||||
| #include "okapi/api/units/RQuantityName.hpp" | ||||
| #include <string> | ||||
|  | ||||
| namespace okapi { | ||||
| struct OdomState { | ||||
|   QLength x{0_m}; | ||||
|   QLength y{0_m}; | ||||
|   QAngle theta{0_deg}; | ||||
|  | ||||
|   /** | ||||
|    * Get a string for the current odometry state (optionally with the specified units). | ||||
|    * | ||||
|    * Examples: | ||||
|    *   - `OdomState::str(1_m, 1_deg)`: The default (no arguments specified). | ||||
|    *   - `OdomState::str(1_tile, 1_radian)`: distance tiles and angle radians. | ||||
|    * | ||||
|    * Throws std::domain_error if the units passed are undefined. | ||||
|    * | ||||
|    * @param idistanceUnit The units you want your distance to be in. This must be an exact, predefined QLength (such as foot, meter, inch, tile etc.). | ||||
|    * @param iangleUnit The units you want your angle to be in. This must be an exact, predefined QAngle (degree or radian). | ||||
|    * @return A string representing the state. | ||||
|    */ | ||||
|   std::string str(QLength idistanceUnit, QAngle iangleUnit) const; | ||||
|  | ||||
|   /** | ||||
|    * Get a string for the current odometry state (optionally with the specified units). | ||||
|    * | ||||
|    * Examples: | ||||
|    *   - `OdomState::str(1_m, "_m", 1_deg, "_deg")`: The default (no arguments specified), prints in meters and degrees. | ||||
|    *   - `OdomState::str(1_in, "_in", 1_deg, "_deg")` or `OdomState::str(1_in, "\"", 1_deg, "°")`: to print values in inches and degrees with different suffixes. | ||||
|    *   - `OdomState::str(6_tile / 100, "%", 360_deg / 100, "%")` to get the distance values in % of the vex field, and angle values in % of a full rotation. | ||||
|    * | ||||
|    * @param idistanceUnit The units you want your distance to be in. The x or y position will be output in multiples of this length. | ||||
|    * @param distUnitName The suffix you as your distance unit. | ||||
|    * @param iangleUnit The units you want your angle to be in. The angle will be output in multiples of this unit. | ||||
|    * @param angleUnitName The suffix you want as your angle unit. | ||||
|    * @return A string representing the state. | ||||
|    */ | ||||
|   std::string str(QLength idistanceUnit = meter, | ||||
|                   std::string distUnitName = "_m", | ||||
|                   QAngle iangleUnit = degree, | ||||
|                   std::string angleUnitName = "_deg") const; | ||||
|  | ||||
|   bool operator==(const OdomState &rhs) const; | ||||
|  | ||||
|   bool operator!=(const OdomState &rhs) const; | ||||
| }; | ||||
| } // namespace okapi | ||||
							
								
								
									
										61
									
								
								SerialTest/include/okapi/api/odometry/odometry.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										61
									
								
								SerialTest/include/okapi/api/odometry/odometry.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,61 @@ | ||||
| /* | ||||
|  * This Source Code Form is subject to the terms of the Mozilla Public | ||||
|  * License, v. 2.0. If a copy of the MPL was not distributed with this | ||||
|  * file, You can obtain one at http://mozilla.org/MPL/2.0/. | ||||
|  */ | ||||
| #pragma once | ||||
|  | ||||
| #include "okapi/api/chassis/controller/chassisScales.hpp" | ||||
| #include "okapi/api/chassis/model/readOnlyChassisModel.hpp" | ||||
| #include "okapi/api/odometry/odomState.hpp" | ||||
| #include "okapi/api/odometry/stateMode.hpp" | ||||
|  | ||||
| namespace okapi { | ||||
| class Odometry { | ||||
|   public: | ||||
|   /** | ||||
|    * Odometry. Tracks the movement of the robot and estimates its position in coordinates | ||||
|    * relative to the start (assumed to be (0, 0, 0)). | ||||
|    */ | ||||
|   explicit Odometry() = default; | ||||
|  | ||||
|   virtual ~Odometry() = default; | ||||
|  | ||||
|   /** | ||||
|    * Sets the drive and turn scales. | ||||
|    */ | ||||
|   virtual void setScales(const ChassisScales &ichassisScales) = 0; | ||||
|  | ||||
|   /** | ||||
|    * Do one odometry step. | ||||
|    */ | ||||
|   virtual void step() = 0; | ||||
|  | ||||
|   /** | ||||
|    * Returns the current state. | ||||
|    * | ||||
|    * @param imode The mode to return the state in. | ||||
|    * @return The current state in the given format. | ||||
|    */ | ||||
|   virtual OdomState getState(const StateMode &imode = StateMode::FRAME_TRANSFORMATION) const = 0; | ||||
|  | ||||
|   /** | ||||
|    * Sets a new state to be the current state. | ||||
|    * | ||||
|    * @param istate The new state in the given format. | ||||
|    * @param imode The mode to treat the input state as. | ||||
|    */ | ||||
|   virtual void setState(const OdomState &istate, | ||||
|                         const StateMode &imode = StateMode::FRAME_TRANSFORMATION) = 0; | ||||
|  | ||||
|   /** | ||||
|    * @return The internal ChassisModel. | ||||
|    */ | ||||
|   virtual std::shared_ptr<ReadOnlyChassisModel> getModel() = 0; | ||||
|  | ||||
|   /** | ||||
|    * @return The internal ChassisScales. | ||||
|    */ | ||||
|   virtual ChassisScales getScales() = 0; | ||||
| }; | ||||
| } // namespace okapi | ||||
							
								
								
									
										30
									
								
								SerialTest/include/okapi/api/odometry/point.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								SerialTest/include/okapi/api/odometry/point.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,30 @@ | ||||
| /* | ||||
|  * This Source Code Form is subject to the terms of the Mozilla Public | ||||
|  * License, v. 2.0. If a copy of the MPL was not distributed with this | ||||
|  * file, You can obtain one at http://mozilla.org/MPL/2.0/. | ||||
|  */ | ||||
| #pragma once | ||||
|  | ||||
| #include "okapi/api/odometry/stateMode.hpp" | ||||
| #include "okapi/api/units/QLength.hpp" | ||||
|  | ||||
| namespace okapi { | ||||
| struct Point { | ||||
|   QLength x{0_m}; | ||||
|   QLength y{0_m}; | ||||
|  | ||||
|   /** | ||||
|    * Computes the value of this point in `StateMode::FRAME_TRANSFORMATION`. | ||||
|    * | ||||
|    * @param imode The StateMode this Point is currently specified in. | ||||
|    * @return This point specified in `StateMode::FRAME_TRANSFORMATION`. | ||||
|    */ | ||||
|   Point inFT(const StateMode &imode) const { | ||||
|     if (imode == StateMode::FRAME_TRANSFORMATION) { | ||||
|       return *this; | ||||
|     } else { | ||||
|       return {y, x}; | ||||
|     } | ||||
|   } | ||||
| }; | ||||
| } // namespace okapi | ||||
							
								
								
									
										17
									
								
								SerialTest/include/okapi/api/odometry/stateMode.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								SerialTest/include/okapi/api/odometry/stateMode.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,17 @@ | ||||
| /* | ||||
|  * This Source Code Form is subject to the terms of the Mozilla Public | ||||
|  * License, v. 2.0. If a copy of the MPL was not distributed with this | ||||
|  * file, You can obtain one at http://mozilla.org/MPL/2.0/. | ||||
|  */ | ||||
| #pragma once | ||||
|  | ||||
| namespace okapi { | ||||
| /** | ||||
|  * The mode for the OdomState calculated by Odometry. | ||||
|  */ | ||||
| enum class StateMode { | ||||
|   FRAME_TRANSFORMATION, ///< +x is forward, +y is right, 0 degrees is along +x | ||||
|   CARTESIAN             ///< +x is right, +y is forward, 0 degrees is along +y | ||||
| }; | ||||
|  | ||||
| } // namespace okapi | ||||
| @@ -0,0 +1,43 @@ | ||||
| /* | ||||
|  * This Source Code Form is subject to the terms of the Mozilla Public | ||||
|  * License, v. 2.0. If a copy of the MPL was not distributed with this | ||||
|  * file, You can obtain one at http://mozilla.org/MPL/2.0/. | ||||
|  */ | ||||
| #pragma once | ||||
|  | ||||
| #include "okapi/api/chassis/model/threeEncoderSkidSteerModel.hpp" | ||||
| #include "okapi/api/odometry/twoEncoderOdometry.hpp" | ||||
| #include "okapi/api/util/timeUtil.hpp" | ||||
| #include <functional> | ||||
|  | ||||
| namespace okapi { | ||||
| class ThreeEncoderOdometry : public TwoEncoderOdometry { | ||||
|   public: | ||||
|   /** | ||||
|    * Odometry. Tracks the movement of the robot and estimates its position in coordinates | ||||
|    * relative to the start (assumed to be (0, 0)). | ||||
|    * | ||||
|    * @param itimeUtil The TimeUtil. | ||||
|    * @param imodel The chassis model for reading sensors. | ||||
|    * @param ichassisScales See ChassisScales docs (the middle wheel scale is the third member) | ||||
|    * @param iwheelVelDelta The maximum delta between wheel velocities to consider the robot as | ||||
|    * driving straight. | ||||
|    * @param ilogger The logger this instance will log to. | ||||
|    */ | ||||
|   ThreeEncoderOdometry(const TimeUtil &itimeUtil, | ||||
|                        const std::shared_ptr<ReadOnlyChassisModel> &imodel, | ||||
|                        const ChassisScales &ichassisScales, | ||||
|                        const std::shared_ptr<Logger> &ilogger = Logger::getDefaultLogger()); | ||||
|  | ||||
|   protected: | ||||
|   /** | ||||
|    * Does the math, side-effect free, for one odom step. | ||||
|    * | ||||
|    * @param itickDiff The tick difference from the previous step to this step. | ||||
|    * @param ideltaT The time difference from the previous step to this step. | ||||
|    * @return The newly computed OdomState. | ||||
|    */ | ||||
|   OdomState odomMathStep(const std::valarray<std::int32_t> &itickDiff, | ||||
|                          const QTime &ideltaT) override; | ||||
| }; | ||||
| } // namespace okapi | ||||
							
								
								
									
										93
									
								
								SerialTest/include/okapi/api/odometry/twoEncoderOdometry.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										93
									
								
								SerialTest/include/okapi/api/odometry/twoEncoderOdometry.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,93 @@ | ||||
| /* | ||||
|  * This Source Code Form is subject to the terms of the Mozilla Public | ||||
|  * License, v. 2.0. If a copy of the MPL was not distributed with this | ||||
|  * file, You can obtain one at http://mozilla.org/MPL/2.0/. | ||||
|  */ | ||||
| #pragma once | ||||
|  | ||||
| #include "okapi/api/odometry/odometry.hpp" | ||||
| #include "okapi/api/units/QSpeed.hpp" | ||||
| #include "okapi/api/util/abstractRate.hpp" | ||||
| #include "okapi/api/util/logging.hpp" | ||||
| #include "okapi/api/util/timeUtil.hpp" | ||||
| #include <atomic> | ||||
| #include <memory> | ||||
| #include <valarray> | ||||
|  | ||||
| namespace okapi { | ||||
| class TwoEncoderOdometry : public Odometry { | ||||
|   public: | ||||
|   /** | ||||
|    * TwoEncoderOdometry. Tracks the movement of the robot and estimates its position in coordinates | ||||
|    * relative to the start (assumed to be (0, 0, 0)). | ||||
|    * | ||||
|    * @param itimeUtil The TimeUtil. | ||||
|    * @param imodel The chassis model for reading sensors. | ||||
|    * @param ichassisScales The chassis dimensions. | ||||
|    * @param ilogger The logger this instance will log to. | ||||
|    */ | ||||
|   TwoEncoderOdometry(const TimeUtil &itimeUtil, | ||||
|                      const std::shared_ptr<ReadOnlyChassisModel> &imodel, | ||||
|                      const ChassisScales &ichassisScales, | ||||
|                      const std::shared_ptr<Logger> &ilogger = Logger::getDefaultLogger()); | ||||
|  | ||||
|   virtual ~TwoEncoderOdometry() = default; | ||||
|  | ||||
|   /** | ||||
|    * Sets the drive and turn scales. | ||||
|    */ | ||||
|   void setScales(const ChassisScales &ichassisScales) override; | ||||
|  | ||||
|   /** | ||||
|    * Do one odometry step. | ||||
|    */ | ||||
|   void step() override; | ||||
|  | ||||
|   /** | ||||
|    * Returns the current state. | ||||
|    * | ||||
|    * @param imode The mode to return the state in. | ||||
|    * @return The current state in the given format. | ||||
|    */ | ||||
|   OdomState getState(const StateMode &imode = StateMode::FRAME_TRANSFORMATION) const override; | ||||
|  | ||||
|   /** | ||||
|    * Sets a new state to be the current state. | ||||
|    * | ||||
|    * @param istate The new state in the given format. | ||||
|    * @param imode The mode to treat the input state as. | ||||
|    */ | ||||
|   void setState(const OdomState &istate, | ||||
|                 const StateMode &imode = StateMode::FRAME_TRANSFORMATION) override; | ||||
|  | ||||
|   /** | ||||
|    * @return The internal ChassisModel. | ||||
|    */ | ||||
|   std::shared_ptr<ReadOnlyChassisModel> getModel() override; | ||||
|  | ||||
|   /** | ||||
|    * @return The internal ChassisScales. | ||||
|    */ | ||||
|   ChassisScales getScales() override; | ||||
|  | ||||
|   protected: | ||||
|   std::shared_ptr<Logger> logger; | ||||
|   std::unique_ptr<AbstractRate> rate; | ||||
|   std::unique_ptr<AbstractTimer> timer; | ||||
|   std::shared_ptr<ReadOnlyChassisModel> model; | ||||
|   ChassisScales chassisScales; | ||||
|   OdomState state; | ||||
|   std::valarray<std::int32_t> newTicks{0, 0, 0}, tickDiff{0, 0, 0}, lastTicks{0, 0, 0}; | ||||
|   const std::int32_t maximumTickDiff{1000}; | ||||
|  | ||||
|   /** | ||||
|    * Does the math, side-effect free, for one odom step. | ||||
|    * | ||||
|    * @param itickDiff The tick difference from the previous step to this step. | ||||
|    * @param ideltaT The time difference from the previous step to this step. | ||||
|    * @return The newly computed OdomState. | ||||
|    */ | ||||
|   virtual OdomState odomMathStep(const std::valarray<std::int32_t> &itickDiff, | ||||
|                                  const QTime &ideltaT); | ||||
| }; | ||||
| } // namespace okapi | ||||
							
								
								
									
										36
									
								
								SerialTest/include/okapi/api/units/QAcceleration.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										36
									
								
								SerialTest/include/okapi/api/units/QAcceleration.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,36 @@ | ||||
| /* | ||||
|  * This code is a modified version of Benjamin Jurke's work in 2015. You can read his blog post | ||||
|  * here: | ||||
|  * https://benjaminjurke.com/content/articles/2015/compile-time-numerical-unit-dimension-checking/ | ||||
|  * | ||||
|  * This Source Code Form is subject to the terms of the Mozilla Public | ||||
|  * License, v. 2.0. If a copy of the MPL was not distributed with this | ||||
|  * file, You can obtain one at http://mozilla.org/MPL/2.0/. | ||||
|  */ | ||||
| #pragma once | ||||
|  | ||||
| #include "okapi/api/units/QLength.hpp" | ||||
| #include "okapi/api/units/QTime.hpp" | ||||
| #include "okapi/api/units/RQuantity.hpp" | ||||
|  | ||||
| namespace okapi { | ||||
| QUANTITY_TYPE(0, 1, -2, 0, QAcceleration) | ||||
|  | ||||
| constexpr QAcceleration mps2 = meter / (second * second); | ||||
| constexpr QAcceleration G = 9.80665 * mps2; | ||||
|  | ||||
| inline namespace literals { | ||||
| constexpr QAcceleration operator"" _mps2(long double x) { | ||||
|   return QAcceleration(x); | ||||
| } | ||||
| constexpr QAcceleration operator"" _mps2(unsigned long long int x) { | ||||
|   return QAcceleration(static_cast<double>(x)); | ||||
| } | ||||
| constexpr QAcceleration operator"" _G(long double x) { | ||||
|   return static_cast<double>(x) * G; | ||||
| } | ||||
| constexpr QAcceleration operator"" _G(unsigned long long int x) { | ||||
|   return static_cast<double>(x) * G; | ||||
| } | ||||
| } // namespace literals | ||||
| } // namespace okapi | ||||
							
								
								
									
										35
									
								
								SerialTest/include/okapi/api/units/QAngle.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								SerialTest/include/okapi/api/units/QAngle.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,35 @@ | ||||
| /* | ||||
|  * This code is a modified version of Benjamin Jurke's work in 2015. You can read his blog post | ||||
|  * here: | ||||
|  * https://benjaminjurke.com/content/articles/2015/compile-time-numerical-unit-dimension-checking/ | ||||
|  * | ||||
|  * This Source Code Form is subject to the terms of the Mozilla Public | ||||
|  * License, v. 2.0. If a copy of the MPL was not distributed with this | ||||
|  * file, You can obtain one at http://mozilla.org/MPL/2.0/. | ||||
|  */ | ||||
| #pragma once | ||||
|  | ||||
| #include "okapi/api/units/RQuantity.hpp" | ||||
| #include <cmath> | ||||
|  | ||||
| namespace okapi { | ||||
| QUANTITY_TYPE(0, 0, 0, 1, QAngle) | ||||
|  | ||||
| constexpr QAngle radian(1.0); | ||||
| constexpr QAngle degree = static_cast<double>(2_pi / 360.0) * radian; | ||||
|  | ||||
| inline namespace literals { | ||||
| constexpr QAngle operator"" _rad(long double x) { | ||||
|   return QAngle(x); | ||||
| } | ||||
| constexpr QAngle operator"" _rad(unsigned long long int x) { | ||||
|   return QAngle(static_cast<double>(x)); | ||||
| } | ||||
| constexpr QAngle operator"" _deg(long double x) { | ||||
|   return static_cast<double>(x) * degree; | ||||
| } | ||||
| constexpr QAngle operator"" _deg(unsigned long long int x) { | ||||
|   return static_cast<double>(x) * degree; | ||||
| } | ||||
| } // namespace literals | ||||
| } // namespace okapi | ||||
							
								
								
									
										16
									
								
								SerialTest/include/okapi/api/units/QAngularAcceleration.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								SerialTest/include/okapi/api/units/QAngularAcceleration.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,16 @@ | ||||
| /* | ||||
|  * This code is a modified version of Benjamin Jurke's work in 2015. You can read his blog post | ||||
|  * here: | ||||
|  * https://benjaminjurke.com/content/articles/2015/compile-time-numerical-unit-dimension-checking/ | ||||
|  * | ||||
|  * This Source Code Form is subject to the terms of the Mozilla Public | ||||
|  * License, v. 2.0. If a copy of the MPL was not distributed with this | ||||
|  * file, You can obtain one at http://mozilla.org/MPL/2.0/. | ||||
|  */ | ||||
| #pragma once | ||||
|  | ||||
| #include "okapi/api/units/RQuantity.hpp" | ||||
|  | ||||
| namespace okapi { | ||||
| QUANTITY_TYPE(0, 0, -2, 1, QAngularAcceleration) | ||||
| } | ||||
							
								
								
									
										16
									
								
								SerialTest/include/okapi/api/units/QAngularJerk.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								SerialTest/include/okapi/api/units/QAngularJerk.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,16 @@ | ||||
| /* | ||||
|  * This code is a modified version of Benjamin Jurke's work in 2015. You can read his blog post | ||||
|  * here: | ||||
|  * https://benjaminjurke.com/content/articles/2015/compile-time-numerical-unit-dimension-checking/ | ||||
|  * | ||||
|  * This Source Code Form is subject to the terms of the Mozilla Public | ||||
|  * License, v. 2.0. If a copy of the MPL was not distributed with this | ||||
|  * file, You can obtain one at http://mozilla.org/MPL/2.0/. | ||||
|  */ | ||||
| #pragma once | ||||
|  | ||||
| #include "okapi/api/units/RQuantity.hpp" | ||||
|  | ||||
| namespace okapi { | ||||
| QUANTITY_TYPE(0, 0, -3, 1, QAngularJerk) | ||||
| } | ||||
							
								
								
									
										39
									
								
								SerialTest/include/okapi/api/units/QAngularSpeed.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								SerialTest/include/okapi/api/units/QAngularSpeed.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,39 @@ | ||||
| /* | ||||
|  * This code is a modified version of Benjamin Jurke's work in 2015. You can read his blog post | ||||
|  * here: | ||||
|  * https://benjaminjurke.com/content/articles/2015/compile-time-numerical-unit-dimension-checking/ | ||||
|  * | ||||
|  * This Source Code Form is subject to the terms of the Mozilla Public | ||||
|  * License, v. 2.0. If a copy of the MPL was not distributed with this | ||||
|  * file, You can obtain one at http://mozilla.org/MPL/2.0/. | ||||
|  */ | ||||
| #pragma once | ||||
|  | ||||
| #include "okapi/api/units/QAngle.hpp" | ||||
| #include "okapi/api/units/QFrequency.hpp" | ||||
| #include "okapi/api/units/QTime.hpp" | ||||
| #include "okapi/api/units/RQuantity.hpp" | ||||
|  | ||||
| namespace okapi { | ||||
| QUANTITY_TYPE(0, 0, -1, 1, QAngularSpeed) | ||||
|  | ||||
| constexpr QAngularSpeed radps = radian / second; | ||||
| constexpr QAngularSpeed rpm = (360 * degree) / minute; | ||||
| constexpr QAngularSpeed cps = (0.01 * degree) / second; // centidegree per second | ||||
|  | ||||
| #pragma GCC diagnostic push | ||||
| #pragma GCC diagnostic ignored "-Wunused-function" | ||||
| static QAngularSpeed convertHertzToRadPerSec(QFrequency in) { | ||||
|   return (in.convert(Hz) / 2_pi) * radps; | ||||
| } | ||||
| #pragma GCC diagnostic pop | ||||
|  | ||||
| inline namespace literals { | ||||
| constexpr QAngularSpeed operator"" _rpm(long double x) { | ||||
|   return x * rpm; | ||||
| } | ||||
| constexpr QAngularSpeed operator"" _rpm(unsigned long long int x) { | ||||
|   return static_cast<double>(x) * rpm; | ||||
| } | ||||
| } // namespace literals | ||||
| } // namespace okapi | ||||
							
								
								
									
										26
									
								
								SerialTest/include/okapi/api/units/QArea.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								SerialTest/include/okapi/api/units/QArea.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,26 @@ | ||||
| /* | ||||
|  * This code is a modified version of Benjamin Jurke's work in 2015. You can read his blog post | ||||
|  * here: | ||||
|  * https://benjaminjurke.com/content/articles/2015/compile-time-numerical-unit-dimension-checking/ | ||||
|  * | ||||
|  * This Source Code Form is subject to the terms of the Mozilla Public | ||||
|  * License, v. 2.0. If a copy of the MPL was not distributed with this | ||||
|  * file, You can obtain one at http://mozilla.org/MPL/2.0/. | ||||
|  */ | ||||
| #pragma once | ||||
|  | ||||
| #include "okapi/api/units/QLength.hpp" | ||||
| #include "okapi/api/units/RQuantity.hpp" | ||||
|  | ||||
| namespace okapi { | ||||
| QUANTITY_TYPE(0, 2, 0, 0, QArea) | ||||
|  | ||||
| constexpr QArea kilometer2 = kilometer * kilometer; | ||||
| constexpr QArea meter2 = meter * meter; | ||||
| constexpr QArea decimeter2 = decimeter * decimeter; | ||||
| constexpr QArea centimeter2 = centimeter * centimeter; | ||||
| constexpr QArea millimeter2 = millimeter * millimeter; | ||||
| constexpr QArea inch2 = inch * inch; | ||||
| constexpr QArea foot2 = foot * foot; | ||||
| constexpr QArea mile2 = mile * mile; | ||||
| } // namespace okapi | ||||
							
								
								
									
										43
									
								
								SerialTest/include/okapi/api/units/QForce.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										43
									
								
								SerialTest/include/okapi/api/units/QForce.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,43 @@ | ||||
| /* | ||||
|  * This code is a modified version of Benjamin Jurke's work in 2015. You can read his blog post | ||||
|  * here: | ||||
|  * https://benjaminjurke.com/content/articles/2015/compile-time-numerical-unit-dimension-checking/ | ||||
|  * | ||||
|  * This Source Code Form is subject to the terms of the Mozilla Public | ||||
|  * License, v. 2.0. If a copy of the MPL was not distributed with this | ||||
|  * file, You can obtain one at http://mozilla.org/MPL/2.0/. | ||||
|  */ | ||||
| #pragma once | ||||
|  | ||||
| #include "okapi/api/units/QAcceleration.hpp" | ||||
| #include "okapi/api/units/QMass.hpp" | ||||
| #include "okapi/api/units/RQuantity.hpp" | ||||
|  | ||||
| namespace okapi { | ||||
| QUANTITY_TYPE(1, 1, -2, 0, QForce) | ||||
|  | ||||
| constexpr QForce newton = (kg * meter) / (second * second); | ||||
| constexpr QForce poundforce = pound * G; | ||||
| constexpr QForce kilopond = kg * G; | ||||
|  | ||||
| inline namespace literals { | ||||
| constexpr QForce operator"" _n(long double x) { | ||||
|   return QForce(x); | ||||
| } | ||||
| constexpr QForce operator"" _n(unsigned long long int x) { | ||||
|   return QForce(static_cast<double>(x)); | ||||
| } | ||||
| constexpr QForce operator"" _lbf(long double x) { | ||||
|   return static_cast<double>(x) * poundforce; | ||||
| } | ||||
| constexpr QForce operator"" _lbf(unsigned long long int x) { | ||||
|   return static_cast<double>(x) * poundforce; | ||||
| } | ||||
| constexpr QForce operator"" _kp(long double x) { | ||||
|   return static_cast<double>(x) * kilopond; | ||||
| } | ||||
| constexpr QForce operator"" _kp(unsigned long long int x) { | ||||
|   return static_cast<double>(x) * kilopond; | ||||
| } | ||||
| } // namespace literals | ||||
| } // namespace okapi | ||||
							
								
								
									
										27
									
								
								SerialTest/include/okapi/api/units/QFrequency.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								SerialTest/include/okapi/api/units/QFrequency.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,27 @@ | ||||
| /* | ||||
|  * This code is a modified version of Benjamin Jurke's work in 2015. You can read his blog post | ||||
|  * here: | ||||
|  * https://benjaminjurke.com/content/articles/2015/compile-time-numerical-unit-dimension-checking/ | ||||
|  * | ||||
|  * This Source Code Form is subject to the terms of the Mozilla Public | ||||
|  * License, v. 2.0. If a copy of the MPL was not distributed with this | ||||
|  * file, You can obtain one at http://mozilla.org/MPL/2.0/. | ||||
|  */ | ||||
| #pragma once | ||||
|  | ||||
| #include "okapi/api/units/RQuantity.hpp" | ||||
|  | ||||
| namespace okapi { | ||||
| QUANTITY_TYPE(0, 0, -1, 0, QFrequency) | ||||
|  | ||||
| constexpr QFrequency Hz(1.0); | ||||
|  | ||||
| inline namespace literals { | ||||
| constexpr QFrequency operator"" _Hz(long double x) { | ||||
|   return QFrequency(x); | ||||
| } | ||||
| constexpr QFrequency operator"" _Hz(unsigned long long int x) { | ||||
|   return QFrequency(static_cast<long double>(x)); | ||||
| } | ||||
| } // namespace literals | ||||
| } // namespace okapi | ||||
							
								
								
									
										18
									
								
								SerialTest/include/okapi/api/units/QJerk.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								SerialTest/include/okapi/api/units/QJerk.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,18 @@ | ||||
| /* | ||||
|  * This code is a modified version of Benjamin Jurke's work in 2015. You can read his blog post | ||||
|  * here: | ||||
|  * https://benjaminjurke.com/content/articles/2015/compile-time-numerical-unit-dimension-checking/ | ||||
|  * | ||||
|  * This Source Code Form is subject to the terms of the Mozilla Public | ||||
|  * License, v. 2.0. If a copy of the MPL was not distributed with this | ||||
|  * file, You can obtain one at http://mozilla.org/MPL/2.0/. | ||||
|  */ | ||||
| #pragma once | ||||
|  | ||||
| #include "okapi/api/units/QLength.hpp" | ||||
| #include "okapi/api/units/QTime.hpp" | ||||
| #include "okapi/api/units/RQuantity.hpp" | ||||
|  | ||||
| namespace okapi { | ||||
| QUANTITY_TYPE(0, 1, -3, 0, QJerk) | ||||
| } | ||||
							
								
								
									
										84
									
								
								SerialTest/include/okapi/api/units/QLength.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										84
									
								
								SerialTest/include/okapi/api/units/QLength.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,84 @@ | ||||
| /* | ||||
|  * This code is a modified version of Benjamin Jurke's work in 2015. You can read his blog post | ||||
|  * here: | ||||
|  * https://benjaminjurke.com/content/articles/2015/compile-time-numerical-unit-dimension-checking/ | ||||
|  * | ||||
|  * This Source Code Form is subject to the terms of the Mozilla Public | ||||
|  * License, v. 2.0. If a copy of the MPL was not distributed with this | ||||
|  * file, You can obtain one at http://mozilla.org/MPL/2.0/. | ||||
|  */ | ||||
| #pragma once | ||||
|  | ||||
| #include "okapi/api/units/RQuantity.hpp" | ||||
|  | ||||
| namespace okapi { | ||||
| QUANTITY_TYPE(0, 1, 0, 0, QLength) | ||||
|  | ||||
| constexpr QLength meter(1.0); // SI base unit | ||||
| constexpr QLength decimeter = meter / 10; | ||||
| constexpr QLength centimeter = meter / 100; | ||||
| constexpr QLength millimeter = meter / 1000; | ||||
| constexpr QLength kilometer = 1000 * meter; | ||||
| constexpr QLength inch = 2.54 * centimeter; | ||||
| constexpr QLength foot = 12 * inch; | ||||
| constexpr QLength yard = 3 * foot; | ||||
| constexpr QLength mile = 5280 * foot; | ||||
| constexpr QLength tile = 24 * inch; | ||||
|  | ||||
| inline namespace literals { | ||||
| constexpr QLength operator"" _mm(long double x) { | ||||
|   return static_cast<double>(x) * millimeter; | ||||
| } | ||||
| constexpr QLength operator"" _cm(long double x) { | ||||
|   return static_cast<double>(x) * centimeter; | ||||
| } | ||||
| constexpr QLength operator"" _m(long double x) { | ||||
|   return static_cast<double>(x) * meter; | ||||
| } | ||||
| constexpr QLength operator"" _km(long double x) { | ||||
|   return static_cast<double>(x) * kilometer; | ||||
| } | ||||
| constexpr QLength operator"" _mi(long double x) { | ||||
|   return static_cast<double>(x) * mile; | ||||
| } | ||||
| constexpr QLength operator"" _yd(long double x) { | ||||
|   return static_cast<double>(x) * yard; | ||||
| } | ||||
| constexpr QLength operator"" _ft(long double x) { | ||||
|   return static_cast<double>(x) * foot; | ||||
| } | ||||
| constexpr QLength operator"" _in(long double x) { | ||||
|   return static_cast<double>(x) * inch; | ||||
| } | ||||
| constexpr QLength operator"" _tile(long double x) { | ||||
|   return static_cast<double>(x) * tile; | ||||
| } | ||||
| constexpr QLength operator"" _mm(unsigned long long int x) { | ||||
|   return static_cast<double>(x) * millimeter; | ||||
| } | ||||
| constexpr QLength operator"" _cm(unsigned long long int x) { | ||||
|   return static_cast<double>(x) * centimeter; | ||||
| } | ||||
| constexpr QLength operator"" _m(unsigned long long int x) { | ||||
|   return static_cast<double>(x) * meter; | ||||
| } | ||||
| constexpr QLength operator"" _km(unsigned long long int x) { | ||||
|   return static_cast<double>(x) * kilometer; | ||||
| } | ||||
| constexpr QLength operator"" _mi(unsigned long long int x) { | ||||
|   return static_cast<double>(x) * mile; | ||||
| } | ||||
| constexpr QLength operator"" _yd(unsigned long long int x) { | ||||
|   return static_cast<double>(x) * yard; | ||||
| } | ||||
| constexpr QLength operator"" _ft(unsigned long long int x) { | ||||
|   return static_cast<double>(x) * foot; | ||||
| } | ||||
| constexpr QLength operator"" _in(unsigned long long int x) { | ||||
|   return static_cast<double>(x) * inch; | ||||
| } | ||||
| constexpr QLength operator"" _tile(unsigned long long int x) { | ||||
|   return static_cast<double>(x) * tile; | ||||
| } | ||||
| } // namespace literals | ||||
| } // namespace okapi | ||||
							
								
								
									
										62
									
								
								SerialTest/include/okapi/api/units/QMass.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										62
									
								
								SerialTest/include/okapi/api/units/QMass.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,62 @@ | ||||
| /* | ||||
|  * This code is a modified version of Benjamin Jurke's work in 2015. You can read his blog post | ||||
|  * here: | ||||
|  * https://benjaminjurke.com/content/articles/2015/compile-time-numerical-unit-dimension-checking/ | ||||
|  * | ||||
|  * This Source Code Form is subject to the terms of the Mozilla Public | ||||
|  * License, v. 2.0. If a copy of the MPL was not distributed with this | ||||
|  * file, You can obtain one at http://mozilla.org/MPL/2.0/. | ||||
|  */ | ||||
| #pragma once | ||||
|  | ||||
| #include "okapi/api/units/RQuantity.hpp" | ||||
|  | ||||
| namespace okapi { | ||||
| QUANTITY_TYPE(1, 0, 0, 0, QMass) | ||||
|  | ||||
| constexpr QMass kg(1.0); // SI base unit | ||||
| constexpr QMass gramme = 0.001 * kg; | ||||
| constexpr QMass tonne = 1000 * kg; | ||||
| constexpr QMass ounce = 0.028349523125 * kg; | ||||
| constexpr QMass pound = 16 * ounce; | ||||
| constexpr QMass stone = 14 * pound; | ||||
|  | ||||
| inline namespace literals { | ||||
| constexpr QMass operator"" _kg(long double x) { | ||||
|   return QMass(x); | ||||
| } | ||||
| constexpr QMass operator"" _g(long double x) { | ||||
|   return static_cast<double>(x) * gramme; | ||||
| } | ||||
| constexpr QMass operator"" _t(long double x) { | ||||
|   return static_cast<double>(x) * tonne; | ||||
| } | ||||
| constexpr QMass operator"" _oz(long double x) { | ||||
|   return static_cast<double>(x) * ounce; | ||||
| } | ||||
| constexpr QMass operator"" _lb(long double x) { | ||||
|   return static_cast<double>(x) * pound; | ||||
| } | ||||
| constexpr QMass operator"" _st(long double x) { | ||||
|   return static_cast<double>(x) * stone; | ||||
| } | ||||
| constexpr QMass operator"" _kg(unsigned long long int x) { | ||||
|   return QMass(static_cast<double>(x)); | ||||
| } | ||||
| constexpr QMass operator"" _g(unsigned long long int x) { | ||||
|   return static_cast<double>(x) * gramme; | ||||
| } | ||||
| constexpr QMass operator"" _t(unsigned long long int x) { | ||||
|   return static_cast<double>(x) * tonne; | ||||
| } | ||||
| constexpr QMass operator"" _oz(unsigned long long int x) { | ||||
|   return static_cast<double>(x) * ounce; | ||||
| } | ||||
| constexpr QMass operator"" _lb(unsigned long long int x) { | ||||
|   return static_cast<double>(x) * pound; | ||||
| } | ||||
| constexpr QMass operator"" _st(unsigned long long int x) { | ||||
|   return static_cast<double>(x) * stone; | ||||
| } | ||||
| } // namespace literals | ||||
| } // namespace okapi | ||||
							
								
								
									
										44
									
								
								SerialTest/include/okapi/api/units/QPressure.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										44
									
								
								SerialTest/include/okapi/api/units/QPressure.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,44 @@ | ||||
| /* | ||||
|  * This code is a modified version of Benjamin Jurke's work in 2015. You can read his blog post | ||||
|  * here: | ||||
|  * https://benjaminjurke.com/content/articles/2015/compile-time-numerical-unit-dimension-checking/ | ||||
|  * | ||||
|  * This Source Code Form is subject to the terms of the Mozilla Public | ||||
|  * License, v. 2.0. If a copy of the MPL was not distributed with this | ||||
|  * file, You can obtain one at http://mozilla.org/MPL/2.0/. | ||||
|  */ | ||||
| #pragma once | ||||
|  | ||||
| #include "okapi/api/units/QAcceleration.hpp" | ||||
| #include "okapi/api/units/QArea.hpp" | ||||
| #include "okapi/api/units/QMass.hpp" | ||||
| #include "okapi/api/units/RQuantity.hpp" | ||||
|  | ||||
| namespace okapi { | ||||
| QUANTITY_TYPE(1, -1, -2, 0, QPressure) | ||||
|  | ||||
| constexpr QPressure pascal(1.0); | ||||
| constexpr QPressure bar = 100000 * pascal; | ||||
| constexpr QPressure psi = pound * G / inch2; | ||||
|  | ||||
| inline namespace literals { | ||||
| constexpr QPressure operator"" _Pa(long double x) { | ||||
|   return QPressure(x); | ||||
| } | ||||
| constexpr QPressure operator"" _Pa(unsigned long long int x) { | ||||
|   return QPressure(static_cast<double>(x)); | ||||
| } | ||||
| constexpr QPressure operator"" _bar(long double x) { | ||||
|   return static_cast<double>(x) * bar; | ||||
| } | ||||
| constexpr QPressure operator"" _bar(unsigned long long int x) { | ||||
|   return static_cast<double>(x) * bar; | ||||
| } | ||||
| constexpr QPressure operator"" _psi(long double x) { | ||||
|   return static_cast<double>(x) * psi; | ||||
| } | ||||
| constexpr QPressure operator"" _psi(unsigned long long int x) { | ||||
|   return static_cast<double>(x) * psi; | ||||
| } | ||||
| } // namespace literals | ||||
| } // namespace okapi | ||||
							
								
								
									
										43
									
								
								SerialTest/include/okapi/api/units/QSpeed.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										43
									
								
								SerialTest/include/okapi/api/units/QSpeed.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,43 @@ | ||||
| /* | ||||
|  * This code is a modified version of Benjamin Jurke's work in 2015. You can read his blog post | ||||
|  * here: | ||||
|  * https://benjaminjurke.com/content/articles/2015/compile-time-numerical-unit-dimension-checking/ | ||||
|  * | ||||
|  * This Source Code Form is subject to the terms of the Mozilla Public | ||||
|  * License, v. 2.0. If a copy of the MPL was not distributed with this | ||||
|  * file, You can obtain one at http://mozilla.org/MPL/2.0/. | ||||
|  */ | ||||
| #pragma once | ||||
|  | ||||
| #include "okapi/api/units/QLength.hpp" | ||||
| #include "okapi/api/units/QTime.hpp" | ||||
| #include "okapi/api/units/RQuantity.hpp" | ||||
|  | ||||
| namespace okapi { | ||||
| QUANTITY_TYPE(0, 1, -1, 0, QSpeed) | ||||
|  | ||||
| constexpr QSpeed mps = meter / second; | ||||
| constexpr QSpeed miph = mile / hour; | ||||
| constexpr QSpeed kmph = kilometer / hour; | ||||
|  | ||||
| inline namespace literals { | ||||
| constexpr QSpeed operator"" _mps(long double x) { | ||||
|   return static_cast<double>(x) * mps; | ||||
| } | ||||
| constexpr QSpeed operator"" _miph(long double x) { | ||||
|   return static_cast<double>(x) * mile / hour; | ||||
| } | ||||
| constexpr QSpeed operator"" _kmph(long double x) { | ||||
|   return static_cast<double>(x) * kilometer / hour; | ||||
| } | ||||
| constexpr QSpeed operator"" _mps(unsigned long long int x) { | ||||
|   return static_cast<double>(x) * mps; | ||||
| } | ||||
| constexpr QSpeed operator"" _miph(unsigned long long int x) { | ||||
|   return static_cast<double>(x) * mile / hour; | ||||
| } | ||||
| constexpr QSpeed operator"" _kmph(unsigned long long int x) { | ||||
|   return static_cast<double>(x) * kilometer / hour; | ||||
| } | ||||
| } // namespace literals | ||||
| } // namespace okapi | ||||
							
								
								
									
										55
									
								
								SerialTest/include/okapi/api/units/QTime.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										55
									
								
								SerialTest/include/okapi/api/units/QTime.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,55 @@ | ||||
| /* | ||||
|  * This code is a modified version of Benjamin Jurke's work in 2015. You can read his blog post | ||||
|  * here: | ||||
|  * https://benjaminjurke.com/content/articles/2015/compile-time-numerical-unit-dimension-checking/ | ||||
|  * | ||||
|  * This Source Code Form is subject to the terms of the Mozilla Public | ||||
|  * License, v. 2.0. If a copy of the MPL was not distributed with this | ||||
|  * file, You can obtain one at http://mozilla.org/MPL/2.0/. | ||||
|  */ | ||||
| #pragma once | ||||
|  | ||||
| #include "okapi/api/units/RQuantity.hpp" | ||||
|  | ||||
| namespace okapi { | ||||
| QUANTITY_TYPE(0, 0, 1, 0, QTime) | ||||
|  | ||||
| constexpr QTime second(1.0); // SI base unit | ||||
| constexpr QTime millisecond = second / 1000; | ||||
| constexpr QTime minute = 60 * second; | ||||
| constexpr QTime hour = 60 * minute; | ||||
| constexpr QTime day = 24 * hour; | ||||
|  | ||||
| inline namespace literals { | ||||
| constexpr QTime operator"" _s(long double x) { | ||||
|   return QTime(x); | ||||
| } | ||||
| constexpr QTime operator"" _ms(long double x) { | ||||
|   return static_cast<double>(x) * millisecond; | ||||
| } | ||||
| constexpr QTime operator"" _min(long double x) { | ||||
|   return static_cast<double>(x) * minute; | ||||
| } | ||||
| constexpr QTime operator"" _h(long double x) { | ||||
|   return static_cast<double>(x) * hour; | ||||
| } | ||||
| constexpr QTime operator"" _day(long double x) { | ||||
|   return static_cast<double>(x) * day; | ||||
| } | ||||
| constexpr QTime operator"" _s(unsigned long long int x) { | ||||
|   return QTime(static_cast<double>(x)); | ||||
| } | ||||
| constexpr QTime operator"" _ms(unsigned long long int x) { | ||||
|   return static_cast<double>(x) * millisecond; | ||||
| } | ||||
| constexpr QTime operator"" _min(unsigned long long int x) { | ||||
|   return static_cast<double>(x) * minute; | ||||
| } | ||||
| constexpr QTime operator"" _h(unsigned long long int x) { | ||||
|   return static_cast<double>(x) * hour; | ||||
| } | ||||
| constexpr QTime operator"" _day(unsigned long long int x) { | ||||
|   return static_cast<double>(x) * day; | ||||
| } | ||||
| } // namespace literals | ||||
| } // namespace okapi | ||||
							
								
								
									
										43
									
								
								SerialTest/include/okapi/api/units/QTorque.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										43
									
								
								SerialTest/include/okapi/api/units/QTorque.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,43 @@ | ||||
| /* | ||||
|  * This code is a modified version of Benjamin Jurke's work in 2015. You can read his blog post | ||||
|  * here: | ||||
|  * https://benjaminjurke.com/content/articles/2015/compile-time-numerical-unit-dimension-checking/ | ||||
|  * | ||||
|  * This Source Code Form is subject to the terms of the Mozilla Public | ||||
|  * License, v. 2.0. If a copy of the MPL was not distributed with this | ||||
|  * file, You can obtain one at http://mozilla.org/MPL/2.0/. | ||||
|  */ | ||||
| #pragma once | ||||
|  | ||||
| #include "okapi/api/units/QForce.hpp" | ||||
| #include "okapi/api/units/QLength.hpp" | ||||
| #include "okapi/api/units/RQuantity.hpp" | ||||
|  | ||||
| namespace okapi { | ||||
| QUANTITY_TYPE(1, 2, -2, 0, QTorque) | ||||
|  | ||||
| constexpr QTorque newtonMeter = newton * meter; | ||||
| constexpr QTorque footPound = 1.355817948 * newtonMeter; | ||||
| constexpr QTorque inchPound = 0.083333333 * footPound; | ||||
|  | ||||
| inline namespace literals { | ||||
| constexpr QTorque operator"" _nM(long double x) { | ||||
|   return QTorque(x); | ||||
| } | ||||
| constexpr QTorque operator"" _nM(unsigned long long int x) { | ||||
|   return QTorque(static_cast<double>(x)); | ||||
| } | ||||
| constexpr QTorque operator"" _inLb(long double x) { | ||||
|   return static_cast<double>(x) * inchPound; | ||||
| } | ||||
| constexpr QTorque operator"" _inLb(unsigned long long int x) { | ||||
|   return static_cast<double>(x) * inchPound; | ||||
| } | ||||
| constexpr QTorque operator"" _ftLb(long double x) { | ||||
|   return static_cast<double>(x) * footPound; | ||||
| } | ||||
| constexpr QTorque operator"" _ftLb(unsigned long long int x) { | ||||
|   return static_cast<double>(x) * footPound; | ||||
| } | ||||
| } // namespace literals | ||||
| } // namespace okapi | ||||
							
								
								
									
										28
									
								
								SerialTest/include/okapi/api/units/QVolume.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								SerialTest/include/okapi/api/units/QVolume.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,28 @@ | ||||
| /* | ||||
|  * This code is a modified version of Benjamin Jurke's work in 2015. You can read his blog post | ||||
|  * here: | ||||
|  * https://benjaminjurke.com/content/articles/2015/compile-time-numerical-unit-dimension-checking/ | ||||
|  * | ||||
|  * This Source Code Form is subject to the terms of the Mozilla Public | ||||
|  * License, v. 2.0. If a copy of the MPL was not distributed with this | ||||
|  * file, You can obtain one at http://mozilla.org/MPL/2.0/. | ||||
|  */ | ||||
| #pragma once | ||||
|  | ||||
| #include "okapi/api/units/QArea.hpp" | ||||
| #include "okapi/api/units/QLength.hpp" | ||||
| #include "okapi/api/units/RQuantity.hpp" | ||||
|  | ||||
| namespace okapi { | ||||
| QUANTITY_TYPE(0, 3, 0, 0, QVolume) | ||||
|  | ||||
| constexpr QVolume kilometer3 = kilometer2 * kilometer; | ||||
| constexpr QVolume meter3 = meter2 * meter; | ||||
| constexpr QVolume decimeter3 = decimeter2 * decimeter; | ||||
| constexpr QVolume centimeter3 = centimeter2 * centimeter; | ||||
| constexpr QVolume millimeter3 = millimeter2 * millimeter; | ||||
| constexpr QVolume inch3 = inch2 * inch; | ||||
| constexpr QVolume foot3 = foot2 * foot; | ||||
| constexpr QVolume mile3 = mile2 * mile; | ||||
| constexpr QVolume litre = decimeter3; | ||||
| } // namespace okapi | ||||
							
								
								
									
										419
									
								
								SerialTest/include/okapi/api/units/RQuantity.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										419
									
								
								SerialTest/include/okapi/api/units/RQuantity.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,419 @@ | ||||
| /* | ||||
|  * This code is a modified version of Benjamin Jurke's work in 2015. You can read his blog post | ||||
|  * here: | ||||
|  * https://benjaminjurke.com/content/articles/2015/compile-time-numerical-unit-dimension-checking/ | ||||
|  * | ||||
|  * This Source Code Form is subject to the terms of the Mozilla Public | ||||
|  * License, v. 2.0. If a copy of the MPL was not distributed with this | ||||
|  * file, You can obtain one at http://mozilla.org/MPL/2.0/. | ||||
|  */ | ||||
| #pragma once | ||||
|  | ||||
| #include <cmath> | ||||
| #include <ratio> | ||||
|  | ||||
| namespace okapi { | ||||
| template <typename MassDim, typename LengthDim, typename TimeDim, typename AngleDim> | ||||
| class RQuantity { | ||||
|   public: | ||||
|   explicit constexpr RQuantity() : value(0.0) { | ||||
|   } | ||||
|  | ||||
|   explicit constexpr RQuantity(double val) : value(val) { | ||||
|   } | ||||
|  | ||||
|   explicit constexpr RQuantity(long double val) : value(static_cast<double>(val)) { | ||||
|   } | ||||
|  | ||||
|   // The intrinsic operations for a quantity with a unit is addition and subtraction | ||||
|   constexpr RQuantity const &operator+=(const RQuantity &rhs) { | ||||
|     value += rhs.value; | ||||
|     return *this; | ||||
|   } | ||||
|  | ||||
|   constexpr RQuantity const &operator-=(const RQuantity &rhs) { | ||||
|     value -= rhs.value; | ||||
|     return *this; | ||||
|   } | ||||
|  | ||||
|   constexpr RQuantity operator-() { | ||||
|     return RQuantity(value * -1); | ||||
|   } | ||||
|  | ||||
|   constexpr RQuantity const &operator*=(const double rhs) { | ||||
|     value *= rhs; | ||||
|     return *this; | ||||
|   } | ||||
|  | ||||
|   constexpr RQuantity const &operator/=(const double rhs) { | ||||
|     value /= rhs; | ||||
|     return *this; | ||||
|   } | ||||
|  | ||||
|   // Returns the value of the quantity in multiples of the specified unit | ||||
|   constexpr double convert(const RQuantity &rhs) const { | ||||
|     return value / rhs.value; | ||||
|   } | ||||
|  | ||||
|   // returns the raw value of the quantity (should not be used) | ||||
|   constexpr double getValue() const { | ||||
|     return value; | ||||
|   } | ||||
|  | ||||
|   constexpr RQuantity<MassDim, LengthDim, TimeDim, AngleDim> abs() const { | ||||
|     return RQuantity<MassDim, LengthDim, TimeDim, AngleDim>(std::fabs(value)); | ||||
|   } | ||||
|  | ||||
|   constexpr RQuantity<std::ratio_divide<MassDim, std::ratio<2>>, | ||||
|                       std::ratio_divide<LengthDim, std::ratio<2>>, | ||||
|                       std::ratio_divide<TimeDim, std::ratio<2>>, | ||||
|                       std::ratio_divide<AngleDim, std::ratio<2>>> | ||||
|   sqrt() const { | ||||
|     return RQuantity<std::ratio_divide<MassDim, std::ratio<2>>, | ||||
|                      std::ratio_divide<LengthDim, std::ratio<2>>, | ||||
|                      std::ratio_divide<TimeDim, std::ratio<2>>, | ||||
|                      std::ratio_divide<AngleDim, std::ratio<2>>>(std::sqrt(value)); | ||||
|   } | ||||
|  | ||||
|   private: | ||||
|   double value; | ||||
| }; | ||||
|  | ||||
| // Predefined (physical unit) quantity types: | ||||
| // ------------------------------------------ | ||||
| #define QUANTITY_TYPE(_Mdim, _Ldim, _Tdim, _Adim, name)                                            \ | ||||
|   typedef RQuantity<std::ratio<_Mdim>, std::ratio<_Ldim>, std::ratio<_Tdim>, std::ratio<_Adim>>    \ | ||||
|     name; | ||||
|  | ||||
| // Unitless | ||||
| QUANTITY_TYPE(0, 0, 0, 0, Number) | ||||
| constexpr Number number(1.0); | ||||
|  | ||||
| // Standard arithmetic operators: | ||||
| // ------------------------------ | ||||
| template <typename M, typename L, typename T, typename A> | ||||
| constexpr RQuantity<M, L, T, A> operator+(const RQuantity<M, L, T, A> &lhs, | ||||
|                                           const RQuantity<M, L, T, A> &rhs) { | ||||
|   return RQuantity<M, L, T, A>(lhs.getValue() + rhs.getValue()); | ||||
| } | ||||
| template <typename M, typename L, typename T, typename A> | ||||
| constexpr RQuantity<M, L, T, A> operator-(const RQuantity<M, L, T, A> &lhs, | ||||
|                                           const RQuantity<M, L, T, A> &rhs) { | ||||
|   return RQuantity<M, L, T, A>(lhs.getValue() - rhs.getValue()); | ||||
| } | ||||
| template <typename M1, | ||||
|           typename L1, | ||||
|           typename T1, | ||||
|           typename A1, | ||||
|           typename M2, | ||||
|           typename L2, | ||||
|           typename T2, | ||||
|           typename A2> | ||||
| constexpr RQuantity<std::ratio_add<M1, M2>, | ||||
|                     std::ratio_add<L1, L2>, | ||||
|                     std::ratio_add<T1, T2>, | ||||
|                     std::ratio_add<A1, A2>> | ||||
| operator*(const RQuantity<M1, L1, T1, A1> &lhs, const RQuantity<M2, L2, T2, A2> &rhs) { | ||||
|   return RQuantity<std::ratio_add<M1, M2>, | ||||
|                    std::ratio_add<L1, L2>, | ||||
|                    std::ratio_add<T1, T2>, | ||||
|                    std::ratio_add<A1, A2>>(lhs.getValue() * rhs.getValue()); | ||||
| } | ||||
| template <typename M, typename L, typename T, typename A> | ||||
| constexpr RQuantity<M, L, T, A> operator*(const double &lhs, const RQuantity<M, L, T, A> &rhs) { | ||||
|   return RQuantity<M, L, T, A>(lhs * rhs.getValue()); | ||||
| } | ||||
| template <typename M, typename L, typename T, typename A> | ||||
| constexpr RQuantity<M, L, T, A> operator*(const RQuantity<M, L, T, A> &lhs, const double &rhs) { | ||||
|   return RQuantity<M, L, T, A>(lhs.getValue() * rhs); | ||||
| } | ||||
| template <typename M1, | ||||
|           typename L1, | ||||
|           typename T1, | ||||
|           typename A1, | ||||
|           typename M2, | ||||
|           typename L2, | ||||
|           typename T2, | ||||
|           typename A2> | ||||
| constexpr RQuantity<std::ratio_subtract<M1, M2>, | ||||
|                     std::ratio_subtract<L1, L2>, | ||||
|                     std::ratio_subtract<T1, T2>, | ||||
|                     std::ratio_subtract<A1, A2>> | ||||
| operator/(const RQuantity<M1, L1, T1, A1> &lhs, const RQuantity<M2, L2, T2, A2> &rhs) { | ||||
|   return RQuantity<std::ratio_subtract<M1, M2>, | ||||
|                    std::ratio_subtract<L1, L2>, | ||||
|                    std::ratio_subtract<T1, T2>, | ||||
|                    std::ratio_subtract<A1, A2>>(lhs.getValue() / rhs.getValue()); | ||||
| } | ||||
| template <typename M, typename L, typename T, typename A> | ||||
| constexpr RQuantity<std::ratio_subtract<std::ratio<0>, M>, | ||||
|                     std::ratio_subtract<std::ratio<0>, L>, | ||||
|                     std::ratio_subtract<std::ratio<0>, T>, | ||||
|                     std::ratio_subtract<std::ratio<0>, A>> | ||||
| operator/(const double &x, const RQuantity<M, L, T, A> &rhs) { | ||||
|   return RQuantity<std::ratio_subtract<std::ratio<0>, M>, | ||||
|                    std::ratio_subtract<std::ratio<0>, L>, | ||||
|                    std::ratio_subtract<std::ratio<0>, T>, | ||||
|                    std::ratio_subtract<std::ratio<0>, A>>(x / rhs.getValue()); | ||||
| } | ||||
| template <typename M, typename L, typename T, typename A> | ||||
| constexpr RQuantity<M, L, T, A> operator/(const RQuantity<M, L, T, A> &rhs, const double &x) { | ||||
|   return RQuantity<M, L, T, A>(rhs.getValue() / x); | ||||
| } | ||||
|  | ||||
| // Comparison operators for quantities: | ||||
| // ------------------------------------ | ||||
| template <typename M, typename L, typename T, typename A> | ||||
| constexpr bool operator==(const RQuantity<M, L, T, A> &lhs, const RQuantity<M, L, T, A> &rhs) { | ||||
|   return (lhs.getValue() == rhs.getValue()); | ||||
| } | ||||
| template <typename M, typename L, typename T, typename A> | ||||
| constexpr bool operator!=(const RQuantity<M, L, T, A> &lhs, const RQuantity<M, L, T, A> &rhs) { | ||||
|   return (lhs.getValue() != rhs.getValue()); | ||||
| } | ||||
| template <typename M, typename L, typename T, typename A> | ||||
| constexpr bool operator<=(const RQuantity<M, L, T, A> &lhs, const RQuantity<M, L, T, A> &rhs) { | ||||
|   return (lhs.getValue() <= rhs.getValue()); | ||||
| } | ||||
| template <typename M, typename L, typename T, typename A> | ||||
| constexpr bool operator>=(const RQuantity<M, L, T, A> &lhs, const RQuantity<M, L, T, A> &rhs) { | ||||
|   return (lhs.getValue() >= rhs.getValue()); | ||||
| } | ||||
| template <typename M, typename L, typename T, typename A> | ||||
| constexpr bool operator<(const RQuantity<M, L, T, A> &lhs, const RQuantity<M, L, T, A> &rhs) { | ||||
|   return (lhs.getValue() < rhs.getValue()); | ||||
| } | ||||
| template <typename M, typename L, typename T, typename A> | ||||
| constexpr bool operator>(const RQuantity<M, L, T, A> &lhs, const RQuantity<M, L, T, A> &rhs) { | ||||
|   return (lhs.getValue() > rhs.getValue()); | ||||
| } | ||||
|  | ||||
| // Common math functions: | ||||
| // ------------------------------ | ||||
|  | ||||
| template <typename M, typename L, typename T, typename A> | ||||
| constexpr RQuantity<M, L, T, A> abs(const RQuantity<M, L, T, A> &rhs) { | ||||
|   return RQuantity<M, L, T, A>(std::abs(rhs.getValue())); | ||||
| } | ||||
|  | ||||
| template <typename R, typename M, typename L, typename T, typename A> | ||||
| constexpr RQuantity<std::ratio_multiply<M, R>, | ||||
|                     std::ratio_multiply<L, R>, | ||||
|                     std::ratio_multiply<T, R>, | ||||
|                     std::ratio_multiply<A, R>> | ||||
| pow(const RQuantity<M, L, T, A> &lhs) { | ||||
|   return RQuantity<std::ratio_multiply<M, R>, | ||||
|                    std::ratio_multiply<L, R>, | ||||
|                    std::ratio_multiply<T, R>, | ||||
|                    std::ratio_multiply<A, R>>(std::pow(lhs.getValue(), double(R::num) / R::den)); | ||||
| } | ||||
|  | ||||
| template <int R, typename M, typename L, typename T, typename A> | ||||
| constexpr RQuantity<std::ratio_multiply<M, std::ratio<R>>, | ||||
|                     std::ratio_multiply<L, std::ratio<R>>, | ||||
|                     std::ratio_multiply<T, std::ratio<R>>, | ||||
|                     std::ratio_multiply<A, std::ratio<R>>> | ||||
| pow(const RQuantity<M, L, T, A> &lhs) { | ||||
|   return RQuantity<std::ratio_multiply<M, std::ratio<R>>, | ||||
|                    std::ratio_multiply<L, std::ratio<R>>, | ||||
|                    std::ratio_multiply<T, std::ratio<R>>, | ||||
|                    std::ratio_multiply<A, std::ratio<R>>>(std::pow(lhs.getValue(), R)); | ||||
| } | ||||
|  | ||||
| template <int R, typename M, typename L, typename T, typename A> | ||||
| constexpr RQuantity<std::ratio_divide<M, std::ratio<R>>, | ||||
|                     std::ratio_divide<L, std::ratio<R>>, | ||||
|                     std::ratio_divide<T, std::ratio<R>>, | ||||
|                     std::ratio_divide<A, std::ratio<R>>> | ||||
| root(const RQuantity<M, L, T, A> &lhs) { | ||||
|   return RQuantity<std::ratio_divide<M, std::ratio<R>>, | ||||
|                    std::ratio_divide<L, std::ratio<R>>, | ||||
|                    std::ratio_divide<T, std::ratio<R>>, | ||||
|                    std::ratio_divide<A, std::ratio<R>>>(std::pow(lhs.getValue(), 1.0 / R)); | ||||
| } | ||||
|  | ||||
| template <typename M, typename L, typename T, typename A> | ||||
| constexpr RQuantity<std::ratio_divide<M, std::ratio<2>>, | ||||
|                     std::ratio_divide<L, std::ratio<2>>, | ||||
|                     std::ratio_divide<T, std::ratio<2>>, | ||||
|                     std::ratio_divide<A, std::ratio<2>>> | ||||
| sqrt(const RQuantity<M, L, T, A> &rhs) { | ||||
|   return RQuantity<std::ratio_divide<M, std::ratio<2>>, | ||||
|                    std::ratio_divide<L, std::ratio<2>>, | ||||
|                    std::ratio_divide<T, std::ratio<2>>, | ||||
|                    std::ratio_divide<A, std::ratio<2>>>(std::sqrt(rhs.getValue())); | ||||
| } | ||||
|  | ||||
| template <typename M, typename L, typename T, typename A> | ||||
| constexpr RQuantity<std::ratio_divide<M, std::ratio<3>>, | ||||
|                     std::ratio_divide<L, std::ratio<3>>, | ||||
|                     std::ratio_divide<T, std::ratio<3>>, | ||||
|                     std::ratio_divide<A, std::ratio<3>>> | ||||
| cbrt(const RQuantity<M, L, T, A> &rhs) { | ||||
|   return RQuantity<std::ratio_divide<M, std::ratio<3>>, | ||||
|                    std::ratio_divide<L, std::ratio<3>>, | ||||
|                    std::ratio_divide<T, std::ratio<3>>, | ||||
|                    std::ratio_divide<A, std::ratio<3>>>(std::cbrt(rhs.getValue())); | ||||
| } | ||||
|  | ||||
| template <typename M, typename L, typename T, typename A> | ||||
| constexpr RQuantity<std::ratio_multiply<M, std::ratio<2>>, | ||||
|                     std::ratio_multiply<L, std::ratio<2>>, | ||||
|                     std::ratio_multiply<T, std::ratio<2>>, | ||||
|                     std::ratio_multiply<A, std::ratio<2>>> | ||||
| square(const RQuantity<M, L, T, A> &rhs) { | ||||
|   return RQuantity<std::ratio_multiply<M, std::ratio<2>>, | ||||
|                    std::ratio_multiply<L, std::ratio<2>>, | ||||
|                    std::ratio_multiply<T, std::ratio<2>>, | ||||
|                    std::ratio_multiply<A, std::ratio<2>>>(std::pow(rhs.getValue(), 2)); | ||||
| } | ||||
|  | ||||
| template <typename M, typename L, typename T, typename A> | ||||
| constexpr RQuantity<std::ratio_multiply<M, std::ratio<3>>, | ||||
|                     std::ratio_multiply<L, std::ratio<3>>, | ||||
|                     std::ratio_multiply<T, std::ratio<3>>, | ||||
|                     std::ratio_multiply<A, std::ratio<3>>> | ||||
| cube(const RQuantity<M, L, T, A> &rhs) { | ||||
|   return RQuantity<std::ratio_multiply<M, std::ratio<3>>, | ||||
|                    std::ratio_multiply<L, std::ratio<3>>, | ||||
|                    std::ratio_multiply<T, std::ratio<3>>, | ||||
|                    std::ratio_multiply<A, std::ratio<3>>>(std::pow(rhs.getValue(), 3)); | ||||
| } | ||||
|  | ||||
| template <typename M, typename L, typename T, typename A> | ||||
| constexpr RQuantity<M, L, T, A> hypot(const RQuantity<M, L, T, A> &lhs, | ||||
|                                       const RQuantity<M, L, T, A> &rhs) { | ||||
|   return RQuantity<M, L, T, A>(std::hypot(lhs.getValue(), rhs.getValue())); | ||||
| } | ||||
|  | ||||
| template <typename M, typename L, typename T, typename A> | ||||
| constexpr RQuantity<M, L, T, A> mod(const RQuantity<M, L, T, A> &lhs, | ||||
|                                     const RQuantity<M, L, T, A> &rhs) { | ||||
|   return RQuantity<M, L, T, A>(std::fmod(lhs.getValue(), rhs.getValue())); | ||||
| } | ||||
|  | ||||
| template <typename M1, | ||||
|           typename L1, | ||||
|           typename T1, | ||||
|           typename A1, | ||||
|           typename M2, | ||||
|           typename L2, | ||||
|           typename T2, | ||||
|           typename A2> | ||||
| constexpr RQuantity<M1, L1, T1, A1> copysign(const RQuantity<M1, L1, T1, A1> &lhs, | ||||
|                                              const RQuantity<M2, L2, T2, A2> &rhs) { | ||||
|   return RQuantity<M1, L1, T1, A1>(std::copysign(lhs.getValue(), rhs.getValue())); | ||||
| } | ||||
|  | ||||
| template <typename M, typename L, typename T, typename A> | ||||
| constexpr RQuantity<M, L, T, A> ceil(const RQuantity<M, L, T, A> &lhs, | ||||
|                                      const RQuantity<M, L, T, A> &rhs) { | ||||
|   return RQuantity<M, L, T, A>(std::ceil(lhs.getValue() / rhs.getValue()) * rhs.getValue()); | ||||
| } | ||||
|  | ||||
| template <typename M, typename L, typename T, typename A> | ||||
| constexpr RQuantity<M, L, T, A> floor(const RQuantity<M, L, T, A> &lhs, | ||||
|                                       const RQuantity<M, L, T, A> &rhs) { | ||||
|   return RQuantity<M, L, T, A>(std::floor(lhs.getValue() / rhs.getValue()) * rhs.getValue()); | ||||
| } | ||||
|  | ||||
| template <typename M, typename L, typename T, typename A> | ||||
| constexpr RQuantity<M, L, T, A> trunc(const RQuantity<M, L, T, A> &lhs, | ||||
|                                       const RQuantity<M, L, T, A> &rhs) { | ||||
|   return RQuantity<M, L, T, A>(std::trunc(lhs.getValue() / rhs.getValue()) * rhs.getValue()); | ||||
| } | ||||
|  | ||||
| template <typename M, typename L, typename T, typename A> | ||||
| constexpr RQuantity<M, L, T, A> round(const RQuantity<M, L, T, A> &lhs, | ||||
|                                       const RQuantity<M, L, T, A> &rhs) { | ||||
|   return RQuantity<M, L, T, A>(std::round(lhs.getValue() / rhs.getValue()) * rhs.getValue()); | ||||
| } | ||||
|  | ||||
| // Common trig functions: | ||||
| // ------------------------------ | ||||
|  | ||||
| constexpr Number | ||||
| sin(const RQuantity<std::ratio<0>, std::ratio<0>, std::ratio<0>, std::ratio<1>> &rhs) { | ||||
|   return Number(std::sin(rhs.getValue())); | ||||
| } | ||||
|  | ||||
| constexpr Number | ||||
| cos(const RQuantity<std::ratio<0>, std::ratio<0>, std::ratio<0>, std::ratio<1>> &rhs) { | ||||
|   return Number(std::cos(rhs.getValue())); | ||||
| } | ||||
|  | ||||
| constexpr Number | ||||
| tan(const RQuantity<std::ratio<0>, std::ratio<0>, std::ratio<0>, std::ratio<1>> &rhs) { | ||||
|   return Number(std::tan(rhs.getValue())); | ||||
| } | ||||
|  | ||||
| constexpr RQuantity<std::ratio<0>, std::ratio<0>, std::ratio<0>, std::ratio<1>> | ||||
| asin(const Number &rhs) { | ||||
|   return RQuantity<std::ratio<0>, std::ratio<0>, std::ratio<0>, std::ratio<1>>( | ||||
|     std::asin(rhs.getValue())); | ||||
| } | ||||
|  | ||||
| constexpr RQuantity<std::ratio<0>, std::ratio<0>, std::ratio<0>, std::ratio<1>> | ||||
| acos(const Number &rhs) { | ||||
|   return RQuantity<std::ratio<0>, std::ratio<0>, std::ratio<0>, std::ratio<1>>( | ||||
|     std::acos(rhs.getValue())); | ||||
| } | ||||
|  | ||||
| constexpr RQuantity<std::ratio<0>, std::ratio<0>, std::ratio<0>, std::ratio<1>> | ||||
| atan(const Number &rhs) { | ||||
|   return RQuantity<std::ratio<0>, std::ratio<0>, std::ratio<0>, std::ratio<1>>( | ||||
|     std::atan(rhs.getValue())); | ||||
| } | ||||
|  | ||||
| constexpr Number | ||||
| sinh(const RQuantity<std::ratio<0>, std::ratio<0>, std::ratio<0>, std::ratio<1>> &rhs) { | ||||
|   return Number(std::sinh(rhs.getValue())); | ||||
| } | ||||
|  | ||||
| constexpr Number | ||||
| cosh(const RQuantity<std::ratio<0>, std::ratio<0>, std::ratio<0>, std::ratio<1>> &rhs) { | ||||
|   return Number(std::cosh(rhs.getValue())); | ||||
| } | ||||
|  | ||||
| constexpr Number | ||||
| tanh(const RQuantity<std::ratio<0>, std::ratio<0>, std::ratio<0>, std::ratio<1>> &rhs) { | ||||
|   return Number(std::tanh(rhs.getValue())); | ||||
| } | ||||
|  | ||||
| constexpr RQuantity<std::ratio<0>, std::ratio<0>, std::ratio<0>, std::ratio<1>> | ||||
| asinh(const Number &rhs) { | ||||
|   return RQuantity<std::ratio<0>, std::ratio<0>, std::ratio<0>, std::ratio<1>>( | ||||
|     std::asinh(rhs.getValue())); | ||||
| } | ||||
|  | ||||
| constexpr RQuantity<std::ratio<0>, std::ratio<0>, std::ratio<0>, std::ratio<1>> | ||||
| acosh(const Number &rhs) { | ||||
|   return RQuantity<std::ratio<0>, std::ratio<0>, std::ratio<0>, std::ratio<1>>( | ||||
|     std::acosh(rhs.getValue())); | ||||
| } | ||||
|  | ||||
| constexpr RQuantity<std::ratio<0>, std::ratio<0>, std::ratio<0>, std::ratio<1>> | ||||
| atanh(const Number &rhs) { | ||||
|   return RQuantity<std::ratio<0>, std::ratio<0>, std::ratio<0>, std::ratio<1>>( | ||||
|     std::atanh(rhs.getValue())); | ||||
| } | ||||
|  | ||||
| template <typename M, typename L, typename T, typename A> | ||||
| constexpr RQuantity<std::ratio<0>, std::ratio<0>, std::ratio<0>, std::ratio<1>> | ||||
| atan2(const RQuantity<M, L, T, A> &lhs, const RQuantity<M, L, T, A> &rhs) { | ||||
|   return RQuantity<std::ratio<0>, std::ratio<0>, std::ratio<0>, std::ratio<1>>( | ||||
|     std::atan2(lhs.getValue(), rhs.getValue())); | ||||
| } | ||||
|  | ||||
| inline namespace literals { | ||||
| constexpr long double operator"" _pi(long double x) { | ||||
|   return static_cast<double>(x) * 3.1415926535897932384626433832795; | ||||
| } | ||||
| constexpr long double operator"" _pi(unsigned long long int x) { | ||||
|   return static_cast<double>(x) * 3.1415926535897932384626433832795; | ||||
| } | ||||
| } // namespace literals | ||||
| } // namespace okapi | ||||
|  | ||||
| // Conversion macro, which utilizes the string literals | ||||
| #define ConvertTo(_x, _y) (_x).convert(1.0_##_y) | ||||
							
								
								
									
										46
									
								
								SerialTest/include/okapi/api/units/RQuantityName.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										46
									
								
								SerialTest/include/okapi/api/units/RQuantityName.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,46 @@ | ||||
| #include "okapi/api/units/QAngle.hpp" | ||||
| #include "okapi/api/units/QLength.hpp" | ||||
| #include "okapi/api/units/QSpeed.hpp" | ||||
| #include <stdexcept> | ||||
| #include <typeindex> | ||||
| #include <unordered_map> | ||||
|  | ||||
| #pragma once | ||||
|  | ||||
| namespace okapi { | ||||
|  | ||||
| /** | ||||
| * Returns a short name for a unit. | ||||
| * For example: `str(1_ft)` will return "ft", so will `1 * foot` or `0.3048_m`. | ||||
| * Throws std::domain_error when `q` is a unit not defined in this function. | ||||
| * | ||||
| * @param q Your unit. Currently only QLength and QAngle are supported. | ||||
| * @return The short string suffix for that unit. | ||||
| */ | ||||
| template <class QType> std::string getShortUnitName(QType q) { | ||||
|   const std::unordered_map<std::type_index, std::unordered_map<double, const char *>> shortNameMap = | ||||
|     {{typeid(meter), | ||||
|       { | ||||
|         {meter.getValue(), "m"}, | ||||
|         {decimeter.getValue(), "dm"}, | ||||
|         {centimeter.getValue(), "cm"}, | ||||
|         {millimeter.getValue(), "mm"}, | ||||
|         {kilometer.getValue(), "km"}, | ||||
|         {inch.getValue(), "in"}, | ||||
|         {foot.getValue(), "ft"}, | ||||
|         {yard.getValue(), "yd"}, | ||||
|         {mile.getValue(), "mi"}, | ||||
|         {tile.getValue(), "tile"}, | ||||
|       }}, | ||||
|      {typeid(degree), {{degree.getValue(), "deg"}, {radian.getValue(), "rad"}}}}; | ||||
|  | ||||
|   try { | ||||
|     return shortNameMap.at(typeid(q)).at(q.getValue()); | ||||
|   } catch (const std::out_of_range &e) { | ||||
|     throw std::domain_error( | ||||
|       "You have requested the shortname of an unknown unit somewhere (likely odometry strings). " | ||||
|       "Shortname for provided unit is unspecified. You can override this function to add more " | ||||
|       "names or manually specify the name instead."); | ||||
|   } | ||||
| } | ||||
| } // namespace okapi | ||||
							
								
								
									
										41
									
								
								SerialTest/include/okapi/api/util/abstractRate.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								SerialTest/include/okapi/api/util/abstractRate.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,41 @@ | ||||
| /* | ||||
|  * This Source Code Form is subject to the terms of the Mozilla Public | ||||
|  * License, v. 2.0. If a copy of the MPL was not distributed with this | ||||
|  * file, You can obtain one at http://mozilla.org/MPL/2.0/. | ||||
|  */ | ||||
| #pragma once | ||||
|  | ||||
| #include "okapi/api/coreProsAPI.hpp" | ||||
| #include "okapi/api/units/QFrequency.hpp" | ||||
| #include "okapi/api/units/QTime.hpp" | ||||
|  | ||||
| namespace okapi { | ||||
| class AbstractRate { | ||||
|   public: | ||||
|   virtual ~AbstractRate(); | ||||
|  | ||||
|   /** | ||||
|    * Delay the current task such that it runs at the given frequency. The first delay will run for | ||||
|    * 1000/(ihz). Subsequent delays will adjust according to the previous runtime of the task. | ||||
|    * | ||||
|    * @param ihz the frequency | ||||
|    */ | ||||
|   virtual void delay(QFrequency ihz) = 0; | ||||
|  | ||||
|   /** | ||||
|    * Delay the current task until itime has passed. This method can be used by periodic tasks to | ||||
|    * ensure a consistent execution frequency. | ||||
|    * | ||||
|    * @param itime the time period | ||||
|    */ | ||||
|   virtual void delayUntil(QTime itime) = 0; | ||||
|  | ||||
|   /** | ||||
|    * Delay the current task until ims milliseconds have passed. This method can be used by | ||||
|    * periodic tasks to ensure a consistent execution frequency. | ||||
|    * | ||||
|    * @param ims the time period | ||||
|    */ | ||||
|   virtual void delayUntil(uint32_t ims) = 0; | ||||
| }; | ||||
| } // namespace okapi | ||||
							
								
								
									
										125
									
								
								SerialTest/include/okapi/api/util/abstractTimer.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										125
									
								
								SerialTest/include/okapi/api/util/abstractTimer.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,125 @@ | ||||
| /* | ||||
|  * This Source Code Form is subject to the terms of the Mozilla Public | ||||
|  * License, v. 2.0. If a copy of the MPL was not distributed with this | ||||
|  * file, You can obtain one at http://mozilla.org/MPL/2.0/. | ||||
|  */ | ||||
| #pragma once | ||||
|  | ||||
| #include "okapi/api/units/QFrequency.hpp" | ||||
| #include "okapi/api/units/QTime.hpp" | ||||
|  | ||||
| namespace okapi { | ||||
| class AbstractTimer { | ||||
|   public: | ||||
|   /** | ||||
|    * A Timer base class which implements its methods in terms of millis(). | ||||
|    * | ||||
|    * @param ifirstCalled the current time | ||||
|    */ | ||||
|   explicit AbstractTimer(QTime ifirstCalled); | ||||
|  | ||||
|   virtual ~AbstractTimer(); | ||||
|  | ||||
|   /** | ||||
|    * Returns the current time in units of QTime. | ||||
|    * | ||||
|    * @return the current time | ||||
|    */ | ||||
|   virtual QTime millis() const = 0; | ||||
|  | ||||
|   /** | ||||
|    * Returns the time passed in ms since the previous call of this function. | ||||
|    * | ||||
|    * @return The time passed in ms since the previous call of this function | ||||
|    */ | ||||
|   virtual QTime getDt(); | ||||
|  | ||||
|   /** | ||||
|    * Returns the time passed in ms since the previous call of getDt(). Does not change the time | ||||
|    * recorded by getDt(). | ||||
|    * | ||||
|    * @return The time passed in ms since the previous call of getDt() | ||||
|    */ | ||||
|   virtual QTime readDt() const; | ||||
|  | ||||
|   /** | ||||
|    * Returns the time the timer was first constructed. | ||||
|    * | ||||
|    * @return The time the timer was first constructed | ||||
|    */ | ||||
|   virtual QTime getStartingTime() const; | ||||
|  | ||||
|   /** | ||||
|    * Returns the time since the timer was first constructed. | ||||
|    * | ||||
|    * @return The time since the timer was first constructed | ||||
|    */ | ||||
|   virtual QTime getDtFromStart() const; | ||||
|  | ||||
|   /** | ||||
|    * Place a time marker. Placing another marker will overwrite the previous one. | ||||
|    */ | ||||
|   virtual void placeMark(); | ||||
|  | ||||
|   /** | ||||
|    * Clears the marker. | ||||
|    * | ||||
|    * @return The old marker | ||||
|    */ | ||||
|   virtual QTime clearMark(); | ||||
|  | ||||
|   /** | ||||
|    * Place a hard time marker. Placing another hard marker will not overwrite the previous one; | ||||
|    * instead, call clearHardMark() and then place another. | ||||
|    */ | ||||
|   virtual void placeHardMark(); | ||||
|  | ||||
|   /** | ||||
|    * Clears the hard marker. | ||||
|    * | ||||
|    * @return The old hard marker | ||||
|    */ | ||||
|   virtual QTime clearHardMark(); | ||||
|  | ||||
|   /** | ||||
|    * Returns the time since the time marker. Returns 0_ms if there is no marker. | ||||
|    * | ||||
|    * @return The time since the time marker | ||||
|    */ | ||||
|   virtual QTime getDtFromMark() const; | ||||
|  | ||||
|   /** | ||||
|    * Returns the time since the hard time marker. Returns 0_ms if there is no hard marker set. | ||||
|    * | ||||
|    * @return The time since the hard time marker | ||||
|    */ | ||||
|   virtual QTime getDtFromHardMark() const; | ||||
|  | ||||
|   /** | ||||
|    * Returns true when the input time period has passed, then resets. Meant to be used in loops | ||||
|    * to run an action every time period without blocking. | ||||
|    * | ||||
|    * @param time time period | ||||
|    * @return true when the input time period has passed, false after reading true until the | ||||
|    *   period has passed again | ||||
|    */ | ||||
|   virtual bool repeat(QTime time); | ||||
|  | ||||
|   /** | ||||
|    * Returns true when the input time period has passed, then resets. Meant to be used in loops | ||||
|    * to run an action every time period without blocking. | ||||
|    * | ||||
|    * @param frequency the repeat frequency | ||||
|    * @return true when the input time period has passed, false after reading true until the | ||||
|    *   period has passed again | ||||
|    */ | ||||
|   virtual bool repeat(QFrequency frequency); | ||||
|  | ||||
|   protected: | ||||
|   QTime firstCalled; | ||||
|   QTime lastCalled; | ||||
|   QTime mark; | ||||
|   QTime hardMark; | ||||
|   QTime repeatMark; | ||||
| }; | ||||
| } // namespace okapi | ||||
							
								
								
									
										192
									
								
								SerialTest/include/okapi/api/util/logging.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										192
									
								
								SerialTest/include/okapi/api/util/logging.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,192 @@ | ||||
| /* | ||||
|  * This Source Code Form is subject to the terms of the Mozilla Public | ||||
|  * License, v. 2.0. If a copy of the MPL was not distributed with this | ||||
|  * file, You can obtain one at http://mozilla.org/MPL/2.0/. | ||||
|  */ | ||||
| #pragma once | ||||
|  | ||||
| #include "okapi/api/coreProsAPI.hpp" | ||||
| #include "okapi/api/util/abstractTimer.hpp" | ||||
| #include "okapi/api/util/mathUtil.hpp" | ||||
| #include <memory> | ||||
| #include <mutex> | ||||
|  | ||||
| #if defined(THREADS_STD) | ||||
| #else | ||||
| #include "okapi/impl/util/timer.hpp" | ||||
| #endif | ||||
|  | ||||
| #define LOG_DEBUG(msg) logger->debug([=]() { return msg; }) | ||||
| #define LOG_INFO(msg) logger->info([=]() { return msg; }) | ||||
| #define LOG_WARN(msg) logger->warn([=]() { return msg; }) | ||||
| #define LOG_ERROR(msg) logger->error([=]() { return msg; }) | ||||
|  | ||||
| #define LOG_DEBUG_S(msg) LOG_DEBUG(std::string(msg)) | ||||
| #define LOG_INFO_S(msg) LOG_INFO(std::string(msg)) | ||||
| #define LOG_WARN_S(msg) LOG_WARN(std::string(msg)) | ||||
| #define LOG_ERROR_S(msg) LOG_ERROR(std::string(msg)) | ||||
|  | ||||
| namespace okapi { | ||||
| class Logger { | ||||
|   public: | ||||
|   enum class LogLevel { | ||||
|     debug = 4, ///< debug | ||||
|     info = 3,  ///< info | ||||
|     warn = 2,  ///< warn | ||||
|     error = 1, ///< error | ||||
|     off = 0    ///< off | ||||
|   }; | ||||
|  | ||||
|   /** | ||||
|    * A logger that does nothing. | ||||
|    */ | ||||
|   Logger() noexcept; | ||||
|  | ||||
|   /** | ||||
|    * A logger that opens the input file by name. If the file contains `/ser/`, the file will be | ||||
|    * opened in write mode. Otherwise, the file will be opened in append mode. The file will be | ||||
|    * closed when the logger is destructed. | ||||
|    * | ||||
|    * @param itimer A timer used to get the current time for log statements. | ||||
|    * @param ifileName The name of the log file to open. | ||||
|    * @param ilevel The log level. Log statements more verbose than this level will be disabled. | ||||
|    */ | ||||
|   Logger(std::unique_ptr<AbstractTimer> itimer, | ||||
|          std::string_view ifileName, | ||||
|          const LogLevel &ilevel) noexcept; | ||||
|  | ||||
|   /** | ||||
|    * A logger that uses an existing file handle. The file will be closed when the logger is | ||||
|    * destructed. | ||||
|    * | ||||
|    * @param itimer A timer used to get the current time for log statements. | ||||
|    * @param ifile The log file to open. Will be closed by the logger! | ||||
|    * @param ilevel The log level. Log statements more verbose than this level will be disabled. | ||||
|    */ | ||||
|   Logger(std::unique_ptr<AbstractTimer> itimer, FILE *ifile, const LogLevel &ilevel) noexcept; | ||||
|  | ||||
|   ~Logger(); | ||||
|  | ||||
|   constexpr bool isDebugLevelEnabled() const noexcept { | ||||
|     return toUnderlyingType(logLevel) >= toUnderlyingType(LogLevel::debug); | ||||
|   } | ||||
|  | ||||
|   template <typename T> void debug(T ilazyMessage) noexcept { | ||||
|     if (isDebugLevelEnabled() && logfile && timer) { | ||||
|       std::scoped_lock lock(logfileMutex); | ||||
|       fprintf(logfile, | ||||
|               "%ld (%s) DEBUG: %s\n", | ||||
|               static_cast<long>(timer->millis().convert(millisecond)), | ||||
|               CrossplatformThread::getName().c_str(), | ||||
|               ilazyMessage().c_str()); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   constexpr bool isInfoLevelEnabled() const noexcept { | ||||
|     return toUnderlyingType(logLevel) >= toUnderlyingType(LogLevel::info); | ||||
|   } | ||||
|  | ||||
|   template <typename T> void info(T ilazyMessage) noexcept { | ||||
|     if (isInfoLevelEnabled() && logfile && timer) { | ||||
|       std::scoped_lock lock(logfileMutex); | ||||
|       fprintf(logfile, | ||||
|               "%ld (%s) INFO: %s\n", | ||||
|               static_cast<long>(timer->millis().convert(millisecond)), | ||||
|               CrossplatformThread::getName().c_str(), | ||||
|               ilazyMessage().c_str()); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   constexpr bool isWarnLevelEnabled() const noexcept { | ||||
|     return toUnderlyingType(logLevel) >= toUnderlyingType(LogLevel::warn); | ||||
|   } | ||||
|  | ||||
|   template <typename T> void warn(T ilazyMessage) noexcept { | ||||
|     if (isWarnLevelEnabled() && logfile && timer) { | ||||
|       std::scoped_lock lock(logfileMutex); | ||||
|       fprintf(logfile, | ||||
|               "%ld (%s) WARN: %s\n", | ||||
|               static_cast<long>(timer->millis().convert(millisecond)), | ||||
|               CrossplatformThread::getName().c_str(), | ||||
|               ilazyMessage().c_str()); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   constexpr bool isErrorLevelEnabled() const noexcept { | ||||
|     return toUnderlyingType(logLevel) >= toUnderlyingType(LogLevel::error); | ||||
|   } | ||||
|  | ||||
|   template <typename T> void error(T ilazyMessage) noexcept { | ||||
|     if (isErrorLevelEnabled() && logfile && timer) { | ||||
|       std::scoped_lock lock(logfileMutex); | ||||
|       fprintf(logfile, | ||||
|               "%ld (%s) ERROR: %s\n", | ||||
|               static_cast<long>(timer->millis().convert(millisecond)), | ||||
|               CrossplatformThread::getName().c_str(), | ||||
|               ilazyMessage().c_str()); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * Closes the connection to the log file. | ||||
|    */ | ||||
|   constexpr void close() noexcept { | ||||
|     if (logfile) { | ||||
|       fclose(logfile); | ||||
|       logfile = nullptr; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * @return The default logger. | ||||
|    */ | ||||
|   static std::shared_ptr<Logger> getDefaultLogger(); | ||||
|  | ||||
|   /** | ||||
|    * Sets a new default logger. OkapiLib classes use the default logger unless given another logger | ||||
|    * in their constructor. | ||||
|    * | ||||
|    * @param ilogger The new logger instance. | ||||
|    */ | ||||
|   static void setDefaultLogger(std::shared_ptr<Logger> ilogger); | ||||
|  | ||||
|   private: | ||||
|   const std::unique_ptr<AbstractTimer> timer; | ||||
|   const LogLevel logLevel; | ||||
|   FILE *logfile; | ||||
|   CrossplatformMutex logfileMutex; | ||||
|  | ||||
|   static bool isSerialStream(std::string_view filename); | ||||
| }; | ||||
|  | ||||
| extern std::shared_ptr<Logger> defaultLogger; | ||||
|  | ||||
| struct DefaultLoggerInitializer { | ||||
|   DefaultLoggerInitializer() { | ||||
|     if (count++ == 0) { | ||||
|       init(); | ||||
|     } | ||||
|   } | ||||
|   ~DefaultLoggerInitializer() { | ||||
|     if (--count == 0) { | ||||
|       cleanup(); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   static int count; | ||||
|  | ||||
|   static void init() { | ||||
| #if defined(THREADS_STD) | ||||
|     defaultLogger = std::make_shared<Logger>(); | ||||
| #else | ||||
|     defaultLogger = | ||||
|       std::make_shared<Logger>(std::make_unique<Timer>(), "/ser/sout", Logger::LogLevel::warn); | ||||
| #endif | ||||
|   } | ||||
|  | ||||
|   static void cleanup() { | ||||
|   } | ||||
| }; | ||||
|  | ||||
| static DefaultLoggerInitializer defaultLoggerInitializer; // NOLINT(cert-err58-cpp) | ||||
| } // namespace okapi | ||||
							
								
								
									
										255
									
								
								SerialTest/include/okapi/api/util/mathUtil.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										255
									
								
								SerialTest/include/okapi/api/util/mathUtil.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,255 @@ | ||||
| /* | ||||
|  * This Source Code Form is subject to the terms of the Mozilla Public | ||||
|  * License, v. 2.0. If a copy of the MPL was not distributed with this | ||||
|  * file, You can obtain one at http://mozilla.org/MPL/2.0/. | ||||
|  */ | ||||
| #pragma once | ||||
|  | ||||
| #include "okapi/api/device/motor/abstractMotor.hpp" | ||||
| #include <algorithm> | ||||
| #include <cstdint> | ||||
| #include <math.h> | ||||
| #include <type_traits> | ||||
|  | ||||
| namespace okapi { | ||||
| /** | ||||
|  * Converts inches to millimeters. | ||||
|  */ | ||||
| static constexpr double inchToMM = 25.4; | ||||
|  | ||||
| /** | ||||
|  * Converts millimeters to inches. | ||||
|  */ | ||||
| static constexpr double mmToInch = 0.0393700787; | ||||
|  | ||||
| /** | ||||
|  * Converts degrees to radians. | ||||
|  */ | ||||
| static constexpr double degreeToRadian = 0.01745329252; | ||||
|  | ||||
| /** | ||||
|  * Converts radians to degrees. | ||||
|  */ | ||||
| static constexpr double radianToDegree = 57.2957795; | ||||
|  | ||||
| /** | ||||
|  * The ticks per rotation of the 393 IME with torque gearing. | ||||
|  */ | ||||
| static constexpr double imeTorqueTPR = 627.2; | ||||
|  | ||||
| /** | ||||
|  * The ticks per rotation of the 393 IME with speed gearing. | ||||
|  */ | ||||
| static constexpr std::int32_t imeSpeedTPR = 392; | ||||
|  | ||||
| /** | ||||
|  * The ticks per rotation of the 393 IME with turbo gearing. | ||||
|  */ | ||||
| static constexpr double imeTurboTPR = 261.333; | ||||
|  | ||||
| /** | ||||
|  * The ticks per rotation of the 269 IME. | ||||
|  */ | ||||
| static constexpr double ime269TPR = 240.448; | ||||
|  | ||||
| /** | ||||
|  * The ticks per rotation of the V5 motor with a red gearset. | ||||
|  */ | ||||
| static constexpr std::int32_t imev5RedTPR = 1800; | ||||
|  | ||||
| /** | ||||
|  * The ticks per rotation of the V5 motor with a green gearset. | ||||
|  */ | ||||
| static constexpr std::int32_t imev5GreenTPR = 900; | ||||
|  | ||||
| /** | ||||
|  * The ticks per rotation of the V5 motor with a blue gearset. | ||||
|  */ | ||||
| static constexpr std::int32_t imev5BlueTPR = 300; | ||||
|  | ||||
| /** | ||||
|  * The ticks per rotation of the red quadrature encoders. | ||||
|  */ | ||||
| static constexpr std::int32_t quadEncoderTPR = 360; | ||||
|  | ||||
| /** | ||||
|  * The value of pi. | ||||
|  */ | ||||
| static constexpr double pi = 3.1415926535897932; | ||||
|  | ||||
| /** | ||||
|  * The value of pi divided by 2. | ||||
|  */ | ||||
| static constexpr double pi2 = 1.5707963267948966; | ||||
|  | ||||
| /** | ||||
|  * The conventional value of gravity of Earth. | ||||
|  */ | ||||
| static constexpr double gravity = 9.80665; | ||||
|  | ||||
| /** | ||||
|  * Same as PROS_ERR. | ||||
|  */ | ||||
| static constexpr auto OKAPI_PROS_ERR = INT32_MAX; | ||||
|  | ||||
| /** | ||||
|  * Same as PROS_ERR_F. | ||||
|  */ | ||||
| static constexpr auto OKAPI_PROS_ERR_F = INFINITY; | ||||
|  | ||||
| /** | ||||
|  * The maximum voltage that can be sent to V5 motors. | ||||
|  */ | ||||
| static constexpr double v5MotorMaxVoltage = 12000; | ||||
|  | ||||
| /** | ||||
|  * The polling frequency of V5 motors in milliseconds. | ||||
|  */ | ||||
| static constexpr std::int8_t motorUpdateRate = 10; | ||||
|  | ||||
| /** | ||||
|  * The polling frequency of the ADI ports in milliseconds. | ||||
|  */ | ||||
| static constexpr std::int8_t adiUpdateRate = 10; | ||||
|  | ||||
| /** | ||||
|  * Integer power function. Computes `base^expo`. | ||||
|  * | ||||
|  * @param base The base. | ||||
|  * @param expo The exponent. | ||||
|  * @return `base^expo`. | ||||
|  */ | ||||
| constexpr double ipow(const double base, const int expo) { | ||||
|   return (expo == 0) ? 1 | ||||
|          : expo == 1 ? base | ||||
|          : expo > 1  ? ((expo & 1) ? base * ipow(base, expo - 1) | ||||
|                                    : ipow(base, expo / 2) * ipow(base, expo / 2)) | ||||
|                      : 1 / ipow(base, -expo); | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * Cuts out a range from the number. The new range of the input number will be | ||||
|  * `(-inf, min]U[max, +inf)`. If value sits equally between `min` and `max`, `max` will be returned. | ||||
|  * | ||||
|  * @param value The number to bound. | ||||
|  * @param min The lower bound of range. | ||||
|  * @param max The upper bound of range. | ||||
|  * @return The remapped value. | ||||
|  */ | ||||
| constexpr double cutRange(const double value, const double min, const double max) { | ||||
|   const double middle = max - ((max - min) / 2); | ||||
|  | ||||
|   if (value > min && value < middle) { | ||||
|     return min; | ||||
|   } else if (value <= max && value >= middle) { | ||||
|     return max; | ||||
|   } | ||||
|  | ||||
|   return value; | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * Deadbands a range of the number. Returns the input value, or `0` if it is in the range `[min, | ||||
|  * max]`. | ||||
|  * | ||||
|  * @param value The number to deadband. | ||||
|  * @param min The lower bound of deadband. | ||||
|  * @param max The upper bound of deadband. | ||||
|  * @return The input value or `0` if it is in the range `[min, max]`. | ||||
|  */ | ||||
| constexpr double deadband(const double value, const double min, const double max) { | ||||
|   return std::clamp(value, min, max) == value ? 0 : value; | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * Remap a value in the range `[oldMin, oldMax]` to the range `[newMin, newMax]`. | ||||
|  * | ||||
|  * @param value The value in the old range. | ||||
|  * @param oldMin The old range lower bound. | ||||
|  * @param oldMax The old range upper bound. | ||||
|  * @param newMin The new range lower bound. | ||||
|  * @param newMax The new range upper bound. | ||||
|  * @return The input value in the new range `[newMin, newMax]`. | ||||
|  */ | ||||
| constexpr double remapRange(const double value, | ||||
|                             const double oldMin, | ||||
|                             const double oldMax, | ||||
|                             const double newMin, | ||||
|                             const double newMax) { | ||||
|   return (value - oldMin) * ((newMax - newMin) / (oldMax - oldMin)) + newMin; | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * Converts an enum to its value type. | ||||
|  * | ||||
|  * @param e The enum value. | ||||
|  * @return The corresponding value. | ||||
|  */ | ||||
| template <typename E> constexpr auto toUnderlyingType(const E e) noexcept { | ||||
|   return static_cast<std::underlying_type_t<E>>(e); | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * Converts a bool to a sign. | ||||
|  * | ||||
|  * @param b The bool. | ||||
|  * @return True corresponds to `1` and false corresponds to `-1`. | ||||
|  */ | ||||
| constexpr auto boolToSign(const bool b) noexcept { | ||||
|   return b ? 1 : -1; | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * Computes `lhs mod rhs` using Euclidean division. C's `%` symbol computes the remainder, not | ||||
|  * modulus. | ||||
|  * | ||||
|  * @param lhs The left-hand side. | ||||
|  * @param rhs The right-hand side. | ||||
|  * @return `lhs` mod `rhs`. | ||||
|  */ | ||||
| constexpr long modulus(const long lhs, const long rhs) noexcept { | ||||
|   return ((lhs % rhs) + rhs) % rhs; | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * Converts a gearset to its TPR. | ||||
|  * | ||||
|  * @param igearset The gearset. | ||||
|  * @return The corresponding TPR. | ||||
|  */ | ||||
| constexpr std::int32_t gearsetToTPR(const AbstractMotor::gearset igearset) noexcept { | ||||
|   switch (igearset) { | ||||
|   case AbstractMotor::gearset::red: | ||||
|     return imev5RedTPR; | ||||
|   case AbstractMotor::gearset::green: | ||||
|     return imev5GreenTPR; | ||||
|   case AbstractMotor::gearset::blue: | ||||
|   case AbstractMotor::gearset::invalid: | ||||
|   default: | ||||
|     return imev5BlueTPR; | ||||
|   } | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * Maps ADI port numbers/chars to numbers: | ||||
|  * ``` | ||||
|  * when (port) { | ||||
|  *   in ['a', 'h'] -> [1, 8] | ||||
|  *   in ['A', 'H'] -> [1, 8] | ||||
|  *   else -> [1, 8] | ||||
|  * } | ||||
|  * ``` | ||||
|  * | ||||
|  * @param port The ADI port number or char. | ||||
|  * @return An equivalent ADI port number. | ||||
|  */ | ||||
| constexpr std::int8_t transformADIPort(const std::int8_t port) { | ||||
|   if (port >= 'a' && port <= 'h') { | ||||
|     return port - ('a' - 1); | ||||
|   } else if (port >= 'A' && port <= 'H') { | ||||
|     return port - ('A' - 1); | ||||
|   } else { | ||||
|     return port; | ||||
|   } | ||||
| } | ||||
| } // namespace okapi | ||||
							
								
								
									
										34
									
								
								SerialTest/include/okapi/api/util/supplier.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								SerialTest/include/okapi/api/util/supplier.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,34 @@ | ||||
| /* | ||||
|  * This Source Code Form is subject to the terms of the Mozilla Public | ||||
|  * License, v. 2.0. If a copy of the MPL was not distributed with this | ||||
|  * file, You can obtain one at http://mozilla.org/MPL/2.0/. | ||||
|  */ | ||||
| #pragma once | ||||
|  | ||||
| #include <functional> | ||||
|  | ||||
| namespace okapi { | ||||
| /** | ||||
|  * A supplier of instances of T. | ||||
|  * | ||||
|  * @tparam T the type to supply | ||||
|  */ | ||||
| template <typename T> class Supplier { | ||||
|   public: | ||||
|   explicit Supplier(std::function<T(void)> ifunc) : func(ifunc) { | ||||
|   } | ||||
|  | ||||
|   virtual ~Supplier() = default; | ||||
|  | ||||
|   /** | ||||
|    * Get an instance of type T. This is usually a new instance, but it does not have to be. | ||||
|    * @return an instance of T | ||||
|    */ | ||||
|   T get() const { | ||||
|     return func(); | ||||
|   } | ||||
|  | ||||
|   protected: | ||||
|   std::function<T(void)> func; | ||||
| }; | ||||
| } // namespace okapi | ||||
							
								
								
									
										41
									
								
								SerialTest/include/okapi/api/util/timeUtil.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								SerialTest/include/okapi/api/util/timeUtil.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,41 @@ | ||||
| /* | ||||
|  * This Source Code Form is subject to the terms of the Mozilla Public | ||||
|  * License, v. 2.0. If a copy of the MPL was not distributed with this | ||||
|  * file, You can obtain one at http://mozilla.org/MPL/2.0/. | ||||
|  */ | ||||
| #pragma once | ||||
|  | ||||
| #include "okapi/api/control/util/settledUtil.hpp" | ||||
| #include "okapi/api/util/abstractRate.hpp" | ||||
| #include "okapi/api/util/abstractTimer.hpp" | ||||
| #include "okapi/api/util/supplier.hpp" | ||||
|  | ||||
| namespace okapi { | ||||
| /** | ||||
|  * Utility class for holding an AbstractTimer, AbstractRate, and SettledUtil together in one | ||||
|  * class since they are commonly used together. | ||||
|  */ | ||||
| class TimeUtil { | ||||
|   public: | ||||
|   TimeUtil(const Supplier<std::unique_ptr<AbstractTimer>> &itimerSupplier, | ||||
|            const Supplier<std::unique_ptr<AbstractRate>> &irateSupplier, | ||||
|            const Supplier<std::unique_ptr<SettledUtil>> &isettledUtilSupplier); | ||||
|  | ||||
|   std::unique_ptr<AbstractTimer> getTimer() const; | ||||
|  | ||||
|   std::unique_ptr<AbstractRate> getRate() const; | ||||
|  | ||||
|   std::unique_ptr<SettledUtil> getSettledUtil() const; | ||||
|  | ||||
|   Supplier<std::unique_ptr<AbstractTimer>> getTimerSupplier() const; | ||||
|  | ||||
|   Supplier<std::unique_ptr<AbstractRate>> getRateSupplier() const; | ||||
|  | ||||
|   Supplier<std::unique_ptr<SettledUtil>> getSettledUtilSupplier() const; | ||||
|  | ||||
|   protected: | ||||
|   Supplier<std::unique_ptr<AbstractTimer>> timerSupplier; | ||||
|   Supplier<std::unique_ptr<AbstractRate>> rateSupplier; | ||||
|   Supplier<std::unique_ptr<SettledUtil>> settledUtilSupplier; | ||||
| }; | ||||
| } // namespace okapi | ||||
| @@ -0,0 +1,506 @@ | ||||
| /* | ||||
|  * This Source Code Form is subject to the terms of the Mozilla Public | ||||
|  * License, v. 2.0. If a copy of the MPL was not distributed with this | ||||
|  * file, You can obtain one at http://mozilla.org/MPL/2.0/. | ||||
|  */ | ||||
| #pragma once | ||||
|  | ||||
| #include "okapi/api/chassis/controller/chassisControllerIntegrated.hpp" | ||||
| #include "okapi/api/chassis/controller/chassisControllerPid.hpp" | ||||
| #include "okapi/api/chassis/controller/defaultOdomChassisController.hpp" | ||||
| #include "okapi/api/chassis/model/hDriveModel.hpp" | ||||
| #include "okapi/api/chassis/model/skidSteerModel.hpp" | ||||
| #include "okapi/api/chassis/model/xDriveModel.hpp" | ||||
| #include "okapi/api/util/logging.hpp" | ||||
| #include "okapi/api/util/mathUtil.hpp" | ||||
| #include "okapi/impl/device/motor/motor.hpp" | ||||
| #include "okapi/impl/device/motor/motorGroup.hpp" | ||||
| #include "okapi/impl/device/rotarysensor/adiEncoder.hpp" | ||||
| #include "okapi/impl/device/rotarysensor/integratedEncoder.hpp" | ||||
| #include "okapi/impl/device/rotarysensor/rotationSensor.hpp" | ||||
| #include "okapi/impl/util/timeUtilFactory.hpp" | ||||
|  | ||||
| namespace okapi { | ||||
| class ChassisControllerBuilder { | ||||
|   public: | ||||
|   /** | ||||
|    * A builder that creates ChassisControllers. Use this to create your ChassisController. | ||||
|    * | ||||
|    * @param ilogger The logger this instance will log to. | ||||
|    */ | ||||
|   explicit ChassisControllerBuilder( | ||||
|     const std::shared_ptr<Logger> &ilogger = Logger::getDefaultLogger()); | ||||
|  | ||||
|   /** | ||||
|    * Sets the motors using a skid-steer layout. | ||||
|    * | ||||
|    * @param ileft The left motor. | ||||
|    * @param iright The right motor. | ||||
|    * @return An ongoing builder. | ||||
|    */ | ||||
|   ChassisControllerBuilder &withMotors(const Motor &ileft, const Motor &iright); | ||||
|  | ||||
|   /** | ||||
|    * Sets the motors using a skid-steer layout. | ||||
|    * | ||||
|    * @param ileft The left motor. | ||||
|    * @param iright The right motor. | ||||
|    * @return An ongoing builder. | ||||
|    */ | ||||
|   ChassisControllerBuilder &withMotors(const MotorGroup &ileft, const MotorGroup &iright); | ||||
|  | ||||
|   /** | ||||
|    * Sets the motors using a skid-steer layout. | ||||
|    * | ||||
|    * @param ileft The left motor. | ||||
|    * @param iright The right motor. | ||||
|    * @return An ongoing builder. | ||||
|    */ | ||||
|   ChassisControllerBuilder &withMotors(const std::shared_ptr<AbstractMotor> &ileft, | ||||
|                                        const std::shared_ptr<AbstractMotor> &iright); | ||||
|  | ||||
|   /** | ||||
|    * Sets the motors using an x-drive layout. | ||||
|    * | ||||
|    * @param itopLeft The top left motor. | ||||
|    * @param itopRight The top right motor. | ||||
|    * @param ibottomRight The bottom right motor. | ||||
|    * @param ibottomLeft The bottom left motor. | ||||
|    * @return An ongoing builder. | ||||
|    */ | ||||
|   ChassisControllerBuilder &withMotors(const Motor &itopLeft, | ||||
|                                        const Motor &itopRight, | ||||
|                                        const Motor &ibottomRight, | ||||
|                                        const Motor &ibottomLeft); | ||||
|  | ||||
|   /** | ||||
|    * Sets the motors using an x-drive layout. | ||||
|    * | ||||
|    * @param itopLeft The top left motor. | ||||
|    * @param itopRight The top right motor. | ||||
|    * @param ibottomRight The bottom right motor. | ||||
|    * @param ibottomLeft The bottom left motor. | ||||
|    * @return An ongoing builder. | ||||
|    */ | ||||
|   ChassisControllerBuilder &withMotors(const MotorGroup &itopLeft, | ||||
|                                        const MotorGroup &itopRight, | ||||
|                                        const MotorGroup &ibottomRight, | ||||
|                                        const MotorGroup &ibottomLeft); | ||||
|  | ||||
|   /** | ||||
|    * Sets the motors using an x-drive layout. | ||||
|    * | ||||
|    * @param itopLeft The top left motor. | ||||
|    * @param itopRight The top right motor. | ||||
|    * @param ibottomRight The bottom right motor. | ||||
|    * @param ibottomLeft The bottom left motor. | ||||
|    * @return An ongoing builder. | ||||
|    */ | ||||
|   ChassisControllerBuilder &withMotors(const std::shared_ptr<AbstractMotor> &itopLeft, | ||||
|                                        const std::shared_ptr<AbstractMotor> &itopRight, | ||||
|                                        const std::shared_ptr<AbstractMotor> &ibottomRight, | ||||
|                                        const std::shared_ptr<AbstractMotor> &ibottomLeft); | ||||
|  | ||||
|   /** | ||||
|    * Sets the motors using an h-drive layout. | ||||
|    * | ||||
|    * @param ileft The left motor. | ||||
|    * @param iright The right motor. | ||||
|    * @param imiddle The middle motor. | ||||
|    * @return An ongoing builder. | ||||
|    */ | ||||
|   ChassisControllerBuilder & | ||||
|   withMotors(const Motor &ileft, const Motor &iright, const Motor &imiddle); | ||||
|  | ||||
|   /** | ||||
|    * Sets the motors using an h-drive layout. | ||||
|    * | ||||
|    * @param ileft The left motor. | ||||
|    * @param iright The right motor. | ||||
|    * @param imiddle The middle motor. | ||||
|    * @return An ongoing builder. | ||||
|    */ | ||||
|   ChassisControllerBuilder & | ||||
|   withMotors(const MotorGroup &ileft, const MotorGroup &iright, const MotorGroup &imiddle); | ||||
|  | ||||
|   /** | ||||
|    * Sets the motors using an h-drive layout. | ||||
|    * | ||||
|    * @param ileft The left motor. | ||||
|    * @param iright The right motor. | ||||
|    * @param imiddle The middle motor. | ||||
|    * @return An ongoing builder. | ||||
|    */ | ||||
|   ChassisControllerBuilder & | ||||
|   withMotors(const MotorGroup &ileft, const MotorGroup &iright, const Motor &imiddle); | ||||
|  | ||||
|   /** | ||||
|    * Sets the motors using an h-drive layout. | ||||
|    * | ||||
|    * @param ileft The left motor. | ||||
|    * @param iright The right motor. | ||||
|    * @param imiddle The middle motor. | ||||
|    * @return An ongoing builder. | ||||
|    */ | ||||
|   ChassisControllerBuilder &withMotors(const std::shared_ptr<AbstractMotor> &ileft, | ||||
|                                        const std::shared_ptr<AbstractMotor> &iright, | ||||
|                                        const std::shared_ptr<AbstractMotor> &imiddle); | ||||
|  | ||||
|   /** | ||||
|    * Sets the sensors. The default sensors are the motor's integrated encoders. | ||||
|    * | ||||
|    * @param ileft The left side sensor. | ||||
|    * @param iright The right side sensor. | ||||
|    * @return An ongoing builder. | ||||
|    */ | ||||
|   ChassisControllerBuilder &withSensors(const ADIEncoder &ileft, const ADIEncoder &iright); | ||||
|  | ||||
|   /** | ||||
|    * Sets the sensors. The default sensors are the motor's integrated encoders. | ||||
|    * | ||||
|    * @param ileft The left side sensor. | ||||
|    * @param iright The right side sensor. | ||||
|    * @param imiddle The middle sensor. | ||||
|    * @return An ongoing builder. | ||||
|    */ | ||||
|   ChassisControllerBuilder & | ||||
|   withSensors(const ADIEncoder &ileft, const ADIEncoder &iright, const ADIEncoder &imiddle); | ||||
|  | ||||
|   /** | ||||
|    * Sets the sensors. The default sensors are the motor's integrated encoders. | ||||
|    * | ||||
|    * @param ileft The left side sensor. | ||||
|    * @param iright The right side sensor. | ||||
|    * @return An ongoing builder. | ||||
|    */ | ||||
|   ChassisControllerBuilder &withSensors(const RotationSensor &ileft, const RotationSensor &iright); | ||||
|  | ||||
|   /** | ||||
|    * Sets the sensors. The default sensors are the motor's integrated encoders. | ||||
|    * | ||||
|    * @param ileft The left side sensor. | ||||
|    * @param iright The right side sensor. | ||||
|    * @param imiddle The middle sensor. | ||||
|    * @return An ongoing builder. | ||||
|    */ | ||||
|   ChassisControllerBuilder &withSensors(const RotationSensor &ileft, | ||||
|                                         const RotationSensor &iright, | ||||
|                                         const RotationSensor &imiddle); | ||||
|  | ||||
|   /** | ||||
|    * Sets the sensors. The default sensors are the motor's integrated encoders. | ||||
|    * | ||||
|    * @param ileft The left side sensor. | ||||
|    * @param iright The right side sensor. | ||||
|    * @return An ongoing builder. | ||||
|    */ | ||||
|   ChassisControllerBuilder &withSensors(const IntegratedEncoder &ileft, | ||||
|                                         const IntegratedEncoder &iright); | ||||
|  | ||||
|   /** | ||||
|    * Sets the sensors. The default sensors are the motor's integrated encoders. | ||||
|    * | ||||
|    * @param ileft The left side sensor. | ||||
|    * @param iright The right side sensor. | ||||
|    * @param imiddle The middle sensor. | ||||
|    * @return An ongoing builder. | ||||
|    */ | ||||
|   ChassisControllerBuilder &withSensors(const IntegratedEncoder &ileft, | ||||
|                                         const IntegratedEncoder &iright, | ||||
|                                         const ADIEncoder &imiddle); | ||||
|  | ||||
|   /** | ||||
|    * Sets the sensors. The default sensors are the motor's integrated encoders. | ||||
|    * | ||||
|    * @param ileft The left side sensor. | ||||
|    * @param iright The right side sensor. | ||||
|    * @return An ongoing builder. | ||||
|    */ | ||||
|   ChassisControllerBuilder &withSensors(const std::shared_ptr<ContinuousRotarySensor> &ileft, | ||||
|                                         const std::shared_ptr<ContinuousRotarySensor> &iright); | ||||
|  | ||||
|   /** | ||||
|    * Sets the sensors. The default sensors are the motor's integrated encoders. | ||||
|    * | ||||
|    * @param ileft The left side sensor. | ||||
|    * @param iright The right side sensor. | ||||
|    * @param imiddle The middle sensor. | ||||
|    * @return An ongoing builder. | ||||
|    */ | ||||
|   ChassisControllerBuilder &withSensors(const std::shared_ptr<ContinuousRotarySensor> &ileft, | ||||
|                                         const std::shared_ptr<ContinuousRotarySensor> &iright, | ||||
|                                         const std::shared_ptr<ContinuousRotarySensor> &imiddle); | ||||
|  | ||||
|   /** | ||||
|    * Sets the PID controller gains, causing the builder to generate a ChassisControllerPID. Uses the | ||||
|    * turn controller's gains for the angle controller's gains. | ||||
|    * | ||||
|    * @param idistanceGains The distance controller's gains. | ||||
|    * @param iturnGains The turn controller's gains. | ||||
|    * @return An ongoing builder. | ||||
|    */ | ||||
|   ChassisControllerBuilder &withGains(const IterativePosPIDController::Gains &idistanceGains, | ||||
|                                       const IterativePosPIDController::Gains &iturnGains); | ||||
|  | ||||
|   /** | ||||
|    * Sets the PID controller gains, causing the builder to generate a ChassisControllerPID. | ||||
|    * | ||||
|    * @param idistanceGains The distance controller's gains. | ||||
|    * @param iturnGains The turn controller's gains. | ||||
|    * @param iangleGains The angle controller's gains. | ||||
|    * @return An ongoing builder. | ||||
|    */ | ||||
|   ChassisControllerBuilder &withGains(const IterativePosPIDController::Gains &idistanceGains, | ||||
|                                       const IterativePosPIDController::Gains &iturnGains, | ||||
|                                       const IterativePosPIDController::Gains &iangleGains); | ||||
|  | ||||
|   /** | ||||
|    * Sets the odometry information, causing the builder to generate an Odometry variant. | ||||
|    * | ||||
|    * @param imode The new default StateMode used to interpret target points and query the Odometry | ||||
|    * state. | ||||
|    * @param imoveThreshold The minimum length movement. | ||||
|    * @param iturnThreshold The minimum angle turn. | ||||
|    * @return An ongoing builder. | ||||
|    */ | ||||
|   ChassisControllerBuilder &withOdometry(const StateMode &imode = StateMode::FRAME_TRANSFORMATION, | ||||
|                                          const QLength &imoveThreshold = 0_mm, | ||||
|                                          const QAngle &iturnThreshold = 0_deg); | ||||
|  | ||||
|   /** | ||||
|    * Sets the odometry information, causing the builder to generate an Odometry variant. | ||||
|    * | ||||
|    * @param iodomScales The ChassisScales used just for odometry (if they are different than those | ||||
|    * for the drive). | ||||
|    * @param imode The new default StateMode used to interpret target points and query the Odometry | ||||
|    * state. | ||||
|    * @param imoveThreshold The minimum length movement. | ||||
|    * @param iturnThreshold The minimum angle turn. | ||||
|    * @return An ongoing builder. | ||||
|    */ | ||||
|   ChassisControllerBuilder &withOdometry(const ChassisScales &iodomScales, | ||||
|                                          const StateMode &imode = StateMode::FRAME_TRANSFORMATION, | ||||
|                                          const QLength &imoveThreshold = 0_mm, | ||||
|                                          const QAngle &iturnThreshold = 0_deg); | ||||
|  | ||||
|   /** | ||||
|    * Sets the odometry information, causing the builder to generate an Odometry variant. | ||||
|    * | ||||
|    * @param iodometry The odometry object. | ||||
|    * @param imode The new default StateMode used to interpret target points and query the Odometry | ||||
|    * state. | ||||
|    * @param imoveThreshold The minimum length movement. | ||||
|    * @param iturnThreshold The minimum angle turn. | ||||
|    * @return An ongoing builder. | ||||
|    */ | ||||
|   ChassisControllerBuilder &withOdometry(std::shared_ptr<Odometry> iodometry, | ||||
|                                          const StateMode &imode = StateMode::FRAME_TRANSFORMATION, | ||||
|                                          const QLength &imoveThreshold = 0_mm, | ||||
|                                          const QAngle &iturnThreshold = 0_deg); | ||||
|  | ||||
|   /** | ||||
|    * Sets the derivative filters. Uses a PassthroughFilter by default. | ||||
|    * | ||||
|    * @param idistanceFilter The distance controller's filter. | ||||
|    * @param iturnFilter The turn controller's filter. | ||||
|    * @param iangleFilter The angle controller's filter. | ||||
|    * @return An ongoing builder. | ||||
|    */ | ||||
|   ChassisControllerBuilder &withDerivativeFilters( | ||||
|     std::unique_ptr<Filter> idistanceFilter, | ||||
|     std::unique_ptr<Filter> iturnFilter = std::make_unique<PassthroughFilter>(), | ||||
|     std::unique_ptr<Filter> iangleFilter = std::make_unique<PassthroughFilter>()); | ||||
|  | ||||
|   /** | ||||
|    * Sets the chassis dimensions. | ||||
|    * | ||||
|    * @param igearset The gearset in the drive motors. | ||||
|    * @param iscales The ChassisScales for the base. | ||||
|    * @return An ongoing builder. | ||||
|    */ | ||||
|   ChassisControllerBuilder &withDimensions(const AbstractMotor::GearsetRatioPair &igearset, | ||||
|                                            const ChassisScales &iscales); | ||||
|  | ||||
|   /** | ||||
|    * Sets the max velocity. Overrides the max velocity of the gearset. | ||||
|    * | ||||
|    * @param imaxVelocity The max velocity. | ||||
|    * @return An ongoing builder. | ||||
|    */ | ||||
|   ChassisControllerBuilder &withMaxVelocity(double imaxVelocity); | ||||
|  | ||||
|   /** | ||||
|    * Sets the max voltage. The default is `12000`. | ||||
|    * | ||||
|    * @param imaxVoltage The max voltage. | ||||
|    * @return An ongoing builder. | ||||
|    */ | ||||
|   ChassisControllerBuilder &withMaxVoltage(double imaxVoltage); | ||||
|  | ||||
|   /** | ||||
|    * Sets the TimeUtilFactory used when building a ChassisController. This instance will be given | ||||
|    * to the ChassisController (not to controllers it uses). The default is the static | ||||
|    * TimeUtilFactory. | ||||
|    * | ||||
|    * @param itimeUtilFactory The TimeUtilFactory. | ||||
|    * @return An ongoing builder. | ||||
|    */ | ||||
|   ChassisControllerBuilder & | ||||
|   withChassisControllerTimeUtilFactory(const TimeUtilFactory &itimeUtilFactory); | ||||
|  | ||||
|   /** | ||||
|    * Sets the TimeUtilFactory used when building a ClosedLoopController. This instance will be given | ||||
|    * to any ClosedLoopController instances. The default is the static TimeUtilFactory. | ||||
|    * | ||||
|    * @param itimeUtilFactory The TimeUtilFactory. | ||||
|    * @return An ongoing builder. | ||||
|    */ | ||||
|   ChassisControllerBuilder & | ||||
|   withClosedLoopControllerTimeUtilFactory(const TimeUtilFactory &itimeUtilFactory); | ||||
|  | ||||
|   /** | ||||
|    * Creates a new ConfigurableTimeUtilFactory with the given parameters. Given to any | ||||
|    * ClosedLoopController instances. | ||||
|    * | ||||
|    * @param iatTargetError The minimum error to be considered settled. | ||||
|    * @param iatTargetDerivative The minimum error derivative to be considered settled. | ||||
|    * @param iatTargetTime The minimum time within atTargetError to be considered settled. | ||||
|    * @return An ongoing builder. | ||||
|    */ | ||||
|   ChassisControllerBuilder &withClosedLoopControllerTimeUtil(double iatTargetError = 50, | ||||
|                                                              double iatTargetDerivative = 5, | ||||
|                                                              const QTime &iatTargetTime = 250_ms); | ||||
|  | ||||
|   /** | ||||
|    * Sets the TimeUtilFactory used when building an Odometry. The default is the static | ||||
|    * TimeUtilFactory. | ||||
|    * | ||||
|    * @param itimeUtilFactory The TimeUtilFactory. | ||||
|    * @return An ongoing builder. | ||||
|    */ | ||||
|   ChassisControllerBuilder &withOdometryTimeUtilFactory(const TimeUtilFactory &itimeUtilFactory); | ||||
|  | ||||
|   /** | ||||
|    * Sets the logger used for the ChassisController and ClosedLoopControllers. | ||||
|    * | ||||
|    * @param ilogger The logger. | ||||
|    * @return An ongoing builder. | ||||
|    */ | ||||
|   ChassisControllerBuilder &withLogger(const std::shared_ptr<Logger> &ilogger); | ||||
|  | ||||
|   /** | ||||
|    * Parents the internal tasks started by this builder to the current task, meaning they will be | ||||
|    * deleted once the current task is deleted. The `initialize` and `competition_initialize` tasks | ||||
|    * are never parented to. This is the default behavior. | ||||
|    * | ||||
|    * Read more about this in the [builders and tasks tutorial] | ||||
|    * (docs/tutorials/concepts/builders-and-tasks.md). | ||||
|    * | ||||
|    * @return An ongoing builder. | ||||
|    */ | ||||
|   ChassisControllerBuilder &parentedToCurrentTask(); | ||||
|  | ||||
|   /** | ||||
|    * Prevents parenting the internal tasks started by this builder to the current task, meaning they | ||||
|    * will not be deleted once the current task is deleted. This can cause runaway tasks, but is | ||||
|    * sometimes the desired behavior (e.x., if you want to use this builder once in `autonomous` and | ||||
|    * then again in `opcontrol`). | ||||
|    * | ||||
|    * Read more about this in the [builders and tasks tutorial] | ||||
|    * (docs/tutorials/concepts/builders-and-tasks.md). | ||||
|    * | ||||
|    * @return An ongoing builder. | ||||
|    */ | ||||
|   ChassisControllerBuilder ¬ParentedToCurrentTask(); | ||||
|  | ||||
|   /** | ||||
|    * Builds the ChassisController. Throws a std::runtime_exception if no motors were set or if no | ||||
|    * dimensions were set. | ||||
|    * | ||||
|    * @return A fully built ChassisController. | ||||
|    */ | ||||
|   std::shared_ptr<ChassisController> build(); | ||||
|  | ||||
|   /** | ||||
|    * Builds the OdomChassisController. Throws a std::runtime_exception if no motors were set, if no | ||||
|    * dimensions were set, or if no odometry information was passed. | ||||
|    * | ||||
|    * @return A fully built OdomChassisController. | ||||
|    */ | ||||
|   std::shared_ptr<OdomChassisController> buildOdometry(); | ||||
|  | ||||
|   private: | ||||
|   std::shared_ptr<Logger> logger; | ||||
|  | ||||
|   struct SkidSteerMotors { | ||||
|     std::shared_ptr<AbstractMotor> left; | ||||
|     std::shared_ptr<AbstractMotor> right; | ||||
|   }; | ||||
|  | ||||
|   struct XDriveMotors { | ||||
|     std::shared_ptr<AbstractMotor> topLeft; | ||||
|     std::shared_ptr<AbstractMotor> topRight; | ||||
|     std::shared_ptr<AbstractMotor> bottomRight; | ||||
|     std::shared_ptr<AbstractMotor> bottomLeft; | ||||
|   }; | ||||
|  | ||||
|   struct HDriveMotors { | ||||
|     std::shared_ptr<AbstractMotor> left; | ||||
|     std::shared_ptr<AbstractMotor> right; | ||||
|     std::shared_ptr<AbstractMotor> middle; | ||||
|   }; | ||||
|  | ||||
|   enum class DriveMode { SkidSteer, XDrive, HDrive }; | ||||
|  | ||||
|   bool hasMotors{false}; // Used to verify motors were passed | ||||
|   DriveMode driveMode{DriveMode::SkidSteer}; | ||||
|   SkidSteerMotors skidSteerMotors; | ||||
|   XDriveMotors xDriveMotors; | ||||
|   HDriveMotors hDriveMotors; | ||||
|  | ||||
|   bool sensorsSetByUser{false}; // Used so motors don't overwrite sensors set manually | ||||
|   std::shared_ptr<ContinuousRotarySensor> leftSensor{nullptr}; | ||||
|   std::shared_ptr<ContinuousRotarySensor> rightSensor{nullptr}; | ||||
|   std::shared_ptr<ContinuousRotarySensor> middleSensor{nullptr}; | ||||
|  | ||||
|   bool hasGains{false}; // Whether gains were passed, no gains means CCI | ||||
|   IterativePosPIDController::Gains distanceGains; | ||||
|   std::unique_ptr<Filter> distanceFilter = std::make_unique<PassthroughFilter>(); | ||||
|   IterativePosPIDController::Gains angleGains; | ||||
|   std::unique_ptr<Filter> angleFilter = std::make_unique<PassthroughFilter>(); | ||||
|   IterativePosPIDController::Gains turnGains; | ||||
|   std::unique_ptr<Filter> turnFilter = std::make_unique<PassthroughFilter>(); | ||||
|   TimeUtilFactory chassisControllerTimeUtilFactory = TimeUtilFactory(); | ||||
|   TimeUtilFactory closedLoopControllerTimeUtilFactory = TimeUtilFactory(); | ||||
|   TimeUtilFactory odometryTimeUtilFactory = TimeUtilFactory(); | ||||
|  | ||||
|   AbstractMotor::GearsetRatioPair gearset{AbstractMotor::gearset::invalid, 1.0}; | ||||
|   ChassisScales driveScales{{1, 1}, imev5GreenTPR}; | ||||
|   bool differentOdomScales{false}; | ||||
|   ChassisScales odomScales{{1, 1}, imev5GreenTPR}; | ||||
|   std::shared_ptr<Logger> controllerLogger = Logger::getDefaultLogger(); | ||||
|  | ||||
|   bool hasOdom{false}; // Whether odometry was passed | ||||
|   std::shared_ptr<Odometry> odometry; | ||||
|   StateMode stateMode; | ||||
|   QLength moveThreshold; | ||||
|   QAngle turnThreshold; | ||||
|  | ||||
|   bool maxVelSetByUser{false}; // Used so motors don't overwrite maxVelocity | ||||
|   double maxVelocity{600}; | ||||
|  | ||||
|   double maxVoltage{12000}; | ||||
|  | ||||
|   bool isParentedToCurrentTask{true}; | ||||
|  | ||||
|   std::shared_ptr<ChassisControllerPID> buildCCPID(); | ||||
|   std::shared_ptr<ChassisControllerIntegrated> buildCCI(); | ||||
|   std::shared_ptr<DefaultOdomChassisController> | ||||
|   buildDOCC(std::shared_ptr<ChassisController> chassisController); | ||||
|  | ||||
|   std::shared_ptr<ChassisModel> makeChassisModel(); | ||||
|   std::shared_ptr<SkidSteerModel> makeSkidSteerModel(); | ||||
|   std::shared_ptr<XDriveModel> makeXDriveModel(); | ||||
|   std::shared_ptr<HDriveModel> makeHDriveModel(); | ||||
| }; | ||||
| } // namespace okapi | ||||
| @@ -0,0 +1,177 @@ | ||||
| /* | ||||
|  * This Source Code Form is subject to the terms of the Mozilla Public | ||||
|  * License, v. 2.0. If a copy of the MPL was not distributed with this | ||||
|  * file, You can obtain one at http://mozilla.org/MPL/2.0/. | ||||
|  */ | ||||
| #pragma once | ||||
|  | ||||
| #include "okapi/api/chassis/controller/chassisController.hpp" | ||||
| #include "okapi/api/control/async/asyncLinearMotionProfileController.hpp" | ||||
| #include "okapi/api/control/async/asyncMotionProfileController.hpp" | ||||
| #include "okapi/api/util/logging.hpp" | ||||
| #include "okapi/impl/device/motor/motor.hpp" | ||||
| #include "okapi/impl/device/motor/motorGroup.hpp" | ||||
| #include "okapi/impl/util/timeUtilFactory.hpp" | ||||
|  | ||||
| namespace okapi { | ||||
| class AsyncMotionProfileControllerBuilder { | ||||
|   public: | ||||
|   /** | ||||
|    * A builder that creates async motion profile controllers. Use this to build an | ||||
|    * AsyncMotionProfileController or an AsyncLinearMotionProfileController. | ||||
|    * | ||||
|    * @param ilogger The logger this instance will log to. | ||||
|    */ | ||||
|   explicit AsyncMotionProfileControllerBuilder( | ||||
|     const std::shared_ptr<Logger> &ilogger = Logger::getDefaultLogger()); | ||||
|  | ||||
|   /** | ||||
|    * Sets the output. This must be used with buildLinearMotionProfileController(). | ||||
|    * | ||||
|    * @param ioutput The output. | ||||
|    * @param idiameter The diameter of the mechanical part the motor spins. | ||||
|    * @param ipair The gearset. | ||||
|    * @return An ongoing builder. | ||||
|    */ | ||||
|   AsyncMotionProfileControllerBuilder &withOutput(const Motor &ioutput, | ||||
|                                                   const QLength &idiameter, | ||||
|                                                   const AbstractMotor::GearsetRatioPair &ipair); | ||||
|  | ||||
|   /** | ||||
|    * Sets the output. This must be used with buildLinearMotionProfileController(). | ||||
|    * | ||||
|    * @param ioutput The output. | ||||
|    * @param idiameter The diameter of the mechanical part the motor spins. | ||||
|    * @param ipair The gearset. | ||||
|    * @return An ongoing builder. | ||||
|    */ | ||||
|   AsyncMotionProfileControllerBuilder &withOutput(const MotorGroup &ioutput, | ||||
|                                                   const QLength &idiameter, | ||||
|                                                   const AbstractMotor::GearsetRatioPair &ipair); | ||||
|  | ||||
|   /** | ||||
|    * Sets the output. This must be used with buildLinearMotionProfileController(). | ||||
|    * | ||||
|    * @param ioutput The output. | ||||
|    * @param idiameter The diameter of the mechanical part the motor spins. | ||||
|    * @param ipair The gearset. | ||||
|    * @return An ongoing builder. | ||||
|    */ | ||||
|   AsyncMotionProfileControllerBuilder & | ||||
|   withOutput(const std::shared_ptr<ControllerOutput<double>> &ioutput, | ||||
|              const QLength &idiameter, | ||||
|              const AbstractMotor::GearsetRatioPair &ipair); | ||||
|  | ||||
|   /** | ||||
|    * Sets the output. This must be used with buildMotionProfileController(). | ||||
|    * | ||||
|    * @param icontroller The chassis controller to use. | ||||
|    * @return An ongoing builder. | ||||
|    */ | ||||
|   AsyncMotionProfileControllerBuilder &withOutput(ChassisController &icontroller); | ||||
|  | ||||
|   /** | ||||
|    * Sets the output. This must be used with buildMotionProfileController(). | ||||
|    * | ||||
|    * @param icontroller The chassis controller to use. | ||||
|    * @return An ongoing builder. | ||||
|    */ | ||||
|   AsyncMotionProfileControllerBuilder & | ||||
|   withOutput(const std::shared_ptr<ChassisController> &icontroller); | ||||
|  | ||||
|   /** | ||||
|    * Sets the output. This must be used with buildMotionProfileController(). | ||||
|    * | ||||
|    * @param imodel The chassis model to use. | ||||
|    * @param iscales The chassis dimensions. | ||||
|    * @param ipair The gearset. | ||||
|    * @return An ongoing builder. | ||||
|    */ | ||||
|   AsyncMotionProfileControllerBuilder &withOutput(const std::shared_ptr<ChassisModel> &imodel, | ||||
|                                                   const ChassisScales &iscales, | ||||
|                                                   const AbstractMotor::GearsetRatioPair &ipair); | ||||
|  | ||||
|   /** | ||||
|    * Sets the limits. | ||||
|    * | ||||
|    * @param ilimits The limits. | ||||
|    * @return An ongoing builder. | ||||
|    */ | ||||
|   AsyncMotionProfileControllerBuilder &withLimits(const PathfinderLimits &ilimits); | ||||
|  | ||||
|   /** | ||||
|    * Sets the TimeUtilFactory used when building the controller. The default is the static | ||||
|    * TimeUtilFactory. | ||||
|    * | ||||
|    * @param itimeUtilFactory The TimeUtilFactory. | ||||
|    * @return An ongoing builder. | ||||
|    */ | ||||
|   AsyncMotionProfileControllerBuilder &withTimeUtilFactory(const TimeUtilFactory &itimeUtilFactory); | ||||
|  | ||||
|   /** | ||||
|    * Sets the logger. | ||||
|    * | ||||
|    * @param ilogger The logger. | ||||
|    * @return An ongoing builder. | ||||
|    */ | ||||
|   AsyncMotionProfileControllerBuilder &withLogger(const std::shared_ptr<Logger> &ilogger); | ||||
|  | ||||
|   /** | ||||
|    * Parents the internal tasks started by this builder to the current task, meaning they will be | ||||
|    * deleted once the current task is deleted. The `initialize` and `competition_initialize` tasks | ||||
|    * are never parented to. This is the default behavior. | ||||
|    * | ||||
|    * Read more about this in the [builders and tasks tutorial] | ||||
|    * (docs/tutorials/concepts/builders-and-tasks.md). | ||||
|    * | ||||
|    * @return An ongoing builder. | ||||
|    */ | ||||
|   AsyncMotionProfileControllerBuilder &parentedToCurrentTask(); | ||||
|  | ||||
|   /** | ||||
|    * Prevents parenting the internal tasks started by this builder to the current task, meaning they | ||||
|    * will not be deleted once the current task is deleted. This can cause runaway tasks, but is | ||||
|    * sometimes the desired behavior (e.x., if you want to use this builder once in `autonomous` and | ||||
|    * then again in `opcontrol`). | ||||
|    * | ||||
|    * Read more about this in the [builders and tasks tutorial] | ||||
|    * (docs/tutorials/concepts/builders-and-tasks.md). | ||||
|    * | ||||
|    * @return An ongoing builder. | ||||
|    */ | ||||
|   AsyncMotionProfileControllerBuilder ¬ParentedToCurrentTask(); | ||||
|  | ||||
|   /** | ||||
|    * Builds the AsyncLinearMotionProfileController. | ||||
|    * | ||||
|    * @return A fully built AsyncLinearMotionProfileController. | ||||
|    */ | ||||
|   std::shared_ptr<AsyncLinearMotionProfileController> buildLinearMotionProfileController(); | ||||
|  | ||||
|   /** | ||||
|    * Builds the AsyncMotionProfileController. | ||||
|    * | ||||
|    * @return A fully built AsyncMotionProfileController. | ||||
|    */ | ||||
|   std::shared_ptr<AsyncMotionProfileController> buildMotionProfileController(); | ||||
|  | ||||
|   private: | ||||
|   std::shared_ptr<Logger> logger; | ||||
|  | ||||
|   bool hasLimits{false}; | ||||
|   PathfinderLimits limits; | ||||
|  | ||||
|   bool hasOutput{false}; | ||||
|   std::shared_ptr<ControllerOutput<double>> output; | ||||
|   QLength diameter; | ||||
|  | ||||
|   bool hasModel{false}; | ||||
|   std::shared_ptr<ChassisModel> model; | ||||
|   ChassisScales scales{{1, 1}, imev5GreenTPR}; | ||||
|   AbstractMotor::GearsetRatioPair pair{AbstractMotor::gearset::invalid}; | ||||
|   TimeUtilFactory timeUtilFactory = TimeUtilFactory(); | ||||
|   std::shared_ptr<Logger> controllerLogger = Logger::getDefaultLogger(); | ||||
|  | ||||
|   bool isParentedToCurrentTask{true}; | ||||
| }; | ||||
| } // namespace okapi | ||||
| @@ -0,0 +1,190 @@ | ||||
| /* | ||||
|  * This Source Code Form is subject to the terms of the Mozilla Public | ||||
|  * License, v. 2.0. If a copy of the MPL was not distributed with this | ||||
|  * file, You can obtain one at http://mozilla.org/MPL/2.0/. | ||||
|  */ | ||||
| #pragma once | ||||
|  | ||||
| #include "okapi/api/control/async/asyncPosIntegratedController.hpp" | ||||
| #include "okapi/api/control/async/asyncPosPidController.hpp" | ||||
| #include "okapi/api/control/async/asyncPositionController.hpp" | ||||
| #include "okapi/api/util/logging.hpp" | ||||
| #include "okapi/impl/device/motor/motor.hpp" | ||||
| #include "okapi/impl/device/motor/motorGroup.hpp" | ||||
| #include "okapi/impl/device/rotarysensor/adiEncoder.hpp" | ||||
| #include "okapi/impl/device/rotarysensor/integratedEncoder.hpp" | ||||
| #include "okapi/impl/util/timeUtilFactory.hpp" | ||||
|  | ||||
| namespace okapi { | ||||
| class AsyncPosControllerBuilder { | ||||
|   public: | ||||
|   /** | ||||
|    * A builder that creates async position controllers. Use this to create an | ||||
|    * AsyncPosIntegratedController or an AsyncPosPIDController. | ||||
|    * | ||||
|    * @param ilogger The logger this instance will log to. | ||||
|    */ | ||||
|   explicit AsyncPosControllerBuilder( | ||||
|     const std::shared_ptr<Logger> &ilogger = Logger::getDefaultLogger()); | ||||
|  | ||||
|   /** | ||||
|    * Sets the motor. | ||||
|    * | ||||
|    * @param imotor The motor. | ||||
|    * @return An ongoing builder. | ||||
|    */ | ||||
|   AsyncPosControllerBuilder &withMotor(const Motor &imotor); | ||||
|  | ||||
|   /** | ||||
|    * Sets the motor. | ||||
|    * | ||||
|    * @param imotor The motor. | ||||
|    * @return An ongoing builder. | ||||
|    */ | ||||
|   AsyncPosControllerBuilder &withMotor(const MotorGroup &imotor); | ||||
|  | ||||
|   /** | ||||
|    * Sets the motor. | ||||
|    * | ||||
|    * @param imotor The motor. | ||||
|    * @return An ongoing builder. | ||||
|    */ | ||||
|   AsyncPosControllerBuilder &withMotor(const std::shared_ptr<AbstractMotor> &imotor); | ||||
|  | ||||
|   /** | ||||
|    * Sets the sensor. The default sensor is the motor's integrated encoder. | ||||
|    * | ||||
|    * @param isensor The sensor. | ||||
|    * @return An ongoing builder. | ||||
|    */ | ||||
|   AsyncPosControllerBuilder &withSensor(const ADIEncoder &isensor); | ||||
|  | ||||
|   /** | ||||
|    * Sets the sensor. The default sensor is the motor's integrated encoder. | ||||
|    * | ||||
|    * @param isensor The sensor. | ||||
|    * @return An ongoing builder. | ||||
|    */ | ||||
|   AsyncPosControllerBuilder &withSensor(const IntegratedEncoder &isensor); | ||||
|  | ||||
|   /** | ||||
|    * Sets the sensor. The default sensor is the motor's integrated encoder. | ||||
|    * | ||||
|    * @param isensor The sensor. | ||||
|    * @return An ongoing builder. | ||||
|    */ | ||||
|   AsyncPosControllerBuilder &withSensor(const std::shared_ptr<RotarySensor> &isensor); | ||||
|  | ||||
|   /** | ||||
|    * Sets the controller gains, causing the builder to generate an AsyncPosPIDController. This does | ||||
|    * not set the integrated control's gains. | ||||
|    * | ||||
|    * @param igains The gains. | ||||
|    * @return An ongoing builder. | ||||
|    */ | ||||
|   AsyncPosControllerBuilder &withGains(const IterativePosPIDController::Gains &igains); | ||||
|  | ||||
|   /** | ||||
|    * Sets the derivative filter which filters the derivative term before it is scaled by kD. The | ||||
|    * filter is ignored when using integrated control. The default derivative filter is a | ||||
|    * PassthroughFilter. | ||||
|    * | ||||
|    * @param iderivativeFilter The derivative filter. | ||||
|    * @return An ongoing builder. | ||||
|    */ | ||||
|   AsyncPosControllerBuilder &withDerivativeFilter(std::unique_ptr<Filter> iderivativeFilter); | ||||
|  | ||||
|   /** | ||||
|    * Sets the gearset. The default gearset is derived from the motor's. | ||||
|    * | ||||
|    * @param igearset The gearset. | ||||
|    * @return An ongoing builder. | ||||
|    */ | ||||
|   AsyncPosControllerBuilder &withGearset(const AbstractMotor::GearsetRatioPair &igearset); | ||||
|  | ||||
|   /** | ||||
|    * Sets the maximum velocity. The default maximum velocity is derived from the motor's gearset. | ||||
|    * This parameter is ignored when using an AsyncPosPIDController. | ||||
|    * | ||||
|    * @param imaxVelocity The maximum velocity. | ||||
|    * @return An ongoing builder. | ||||
|    */ | ||||
|   AsyncPosControllerBuilder &withMaxVelocity(double imaxVelocity); | ||||
|  | ||||
|   /** | ||||
|    * Sets the TimeUtilFactory used when building the controller. The default is the static | ||||
|    * TimeUtilFactory. | ||||
|    * | ||||
|    * @param itimeUtilFactory The TimeUtilFactory. | ||||
|    * @return An ongoing builder. | ||||
|    */ | ||||
|   AsyncPosControllerBuilder &withTimeUtilFactory(const TimeUtilFactory &itimeUtilFactory); | ||||
|  | ||||
|   /** | ||||
|    * Sets the logger. | ||||
|    * | ||||
|    * @param ilogger The logger. | ||||
|    * @return An ongoing builder. | ||||
|    */ | ||||
|   AsyncPosControllerBuilder &withLogger(const std::shared_ptr<Logger> &ilogger); | ||||
|  | ||||
|   /** | ||||
|    * Parents the internal tasks started by this builder to the current task, meaning they will be | ||||
|    * deleted once the current task is deleted. The `initialize` and `competition_initialize` tasks | ||||
|    * are never parented to. This is the default behavior. | ||||
|    * | ||||
|    * Read more about this in the [builders and tasks tutorial] | ||||
|    * (docs/tutorials/concepts/builders-and-tasks.md). | ||||
|    * | ||||
|    * @return An ongoing builder. | ||||
|    */ | ||||
|   AsyncPosControllerBuilder &parentedToCurrentTask(); | ||||
|  | ||||
|   /** | ||||
|    * Prevents parenting the internal tasks started by this builder to the current task, meaning they | ||||
|    * will not be deleted once the current task is deleted. This can cause runaway tasks, but is | ||||
|    * sometimes the desired behavior (e.x., if you want to use this builder once in `autonomous` and | ||||
|    * then again in `opcontrol`). | ||||
|    * | ||||
|    * Read more about this in the [builders and tasks tutorial] | ||||
|    * (docs/tutorials/concepts/builders-and-tasks.md). | ||||
|    * | ||||
|    * @return An ongoing builder. | ||||
|    */ | ||||
|   AsyncPosControllerBuilder ¬ParentedToCurrentTask(); | ||||
|  | ||||
|   /** | ||||
|    * Builds the AsyncPositionController. Throws a std::runtime_exception is no motors were set. | ||||
|    * | ||||
|    * @return A fully built AsyncPositionController. | ||||
|    */ | ||||
|   std::shared_ptr<AsyncPositionController<double, double>> build(); | ||||
|  | ||||
|   private: | ||||
|   std::shared_ptr<Logger> logger; | ||||
|  | ||||
|   bool hasMotors{false}; // Used to verify motors were passed | ||||
|   std::shared_ptr<AbstractMotor> motor; | ||||
|  | ||||
|   bool sensorsSetByUser{false}; // Used so motors don't overwrite sensors set manually | ||||
|   std::shared_ptr<RotarySensor> sensor; | ||||
|  | ||||
|   bool hasGains{false}; // Whether gains were passed, no gains means integrated control | ||||
|   IterativePosPIDController::Gains gains; | ||||
|   std::unique_ptr<Filter> derivativeFilter = std::make_unique<PassthroughFilter>(); | ||||
|  | ||||
|   bool gearsetSetByUser{false}; // Used so motor's don't overwrite a gearset set manually | ||||
|   AbstractMotor::GearsetRatioPair pair{AbstractMotor::gearset::invalid}; | ||||
|  | ||||
|   bool maxVelSetByUser{false}; // Used so motors don't overwrite maxVelocity | ||||
|   double maxVelocity{600}; | ||||
|  | ||||
|   TimeUtilFactory timeUtilFactory = TimeUtilFactory(); | ||||
|   std::shared_ptr<Logger> controllerLogger = Logger::getDefaultLogger(); | ||||
|  | ||||
|   bool isParentedToCurrentTask{true}; | ||||
|  | ||||
|   std::shared_ptr<AsyncPosIntegratedController> buildAPIC(); | ||||
|   std::shared_ptr<AsyncPosPIDController> buildAPPC(); | ||||
| }; | ||||
| } // namespace okapi | ||||
| @@ -0,0 +1,203 @@ | ||||
| /* | ||||
|  * This Source Code Form is subject to the terms of the Mozilla Public | ||||
|  * License, v. 2.0. If a copy of the MPL was not distributed with this | ||||
|  * file, You can obtain one at http://mozilla.org/MPL/2.0/. | ||||
|  */ | ||||
| #pragma once | ||||
|  | ||||
| #include "okapi/api/control/async/asyncVelIntegratedController.hpp" | ||||
| #include "okapi/api/control/async/asyncVelPidController.hpp" | ||||
| #include "okapi/api/control/async/asyncVelocityController.hpp" | ||||
| #include "okapi/api/util/logging.hpp" | ||||
| #include "okapi/impl/device/motor/motor.hpp" | ||||
| #include "okapi/impl/device/motor/motorGroup.hpp" | ||||
| #include "okapi/impl/device/rotarysensor/adiEncoder.hpp" | ||||
| #include "okapi/impl/device/rotarysensor/integratedEncoder.hpp" | ||||
| #include "okapi/impl/util/timeUtilFactory.hpp" | ||||
|  | ||||
| namespace okapi { | ||||
| class AsyncVelControllerBuilder { | ||||
|   public: | ||||
|   /** | ||||
|    * A builder that creates async velocity controllers. Use this to create an | ||||
|    * AsyncVelIntegratedController or an AsyncVelPIDController. | ||||
|    * | ||||
|    * @param ilogger The logger this instance will log to. | ||||
|    */ | ||||
|   explicit AsyncVelControllerBuilder( | ||||
|     const std::shared_ptr<Logger> &ilogger = Logger::getDefaultLogger()); | ||||
|  | ||||
|   /** | ||||
|    * Sets the motor. | ||||
|    * | ||||
|    * @param imotor The motor. | ||||
|    * @return An ongoing builder. | ||||
|    */ | ||||
|   AsyncVelControllerBuilder &withMotor(const Motor &imotor); | ||||
|  | ||||
|   /** | ||||
|    * Sets the motor. | ||||
|    * | ||||
|    * @param imotor The motor. | ||||
|    * @return An ongoing builder. | ||||
|    */ | ||||
|   AsyncVelControllerBuilder &withMotor(const MotorGroup &imotor); | ||||
|  | ||||
|   /** | ||||
|    * Sets the motor. | ||||
|    * | ||||
|    * @param imotor The motor. | ||||
|    * @return An ongoing builder. | ||||
|    */ | ||||
|   AsyncVelControllerBuilder &withMotor(const std::shared_ptr<AbstractMotor> &imotor); | ||||
|  | ||||
|   /** | ||||
|    * Sets the sensor. The default sensor is the motor's integrated encoder. | ||||
|    * | ||||
|    * @param isensor The sensor. | ||||
|    * @return An ongoing builder. | ||||
|    */ | ||||
|   AsyncVelControllerBuilder &withSensor(const ADIEncoder &isensor); | ||||
|  | ||||
|   /** | ||||
|    * Sets the sensor. The default sensor is the motor's integrated encoder. | ||||
|    * | ||||
|    * @param isensor The sensor. | ||||
|    * @return An ongoing builder. | ||||
|    */ | ||||
|   AsyncVelControllerBuilder &withSensor(const IntegratedEncoder &isensor); | ||||
|  | ||||
|   /** | ||||
|    * Sets the sensor. The default sensor is the motor's integrated encoder. | ||||
|    * | ||||
|    * @param isensor The sensor. | ||||
|    * @return An ongoing builder. | ||||
|    */ | ||||
|   AsyncVelControllerBuilder &withSensor(const std::shared_ptr<RotarySensor> &isensor); | ||||
|  | ||||
|   /** | ||||
|    * Sets the controller gains, causing the builder to generate an AsyncVelPIDController. This does | ||||
|    * not set the integrated control's gains. | ||||
|    * | ||||
|    * @param igains The gains. | ||||
|    * @return An ongoing builder. | ||||
|    */ | ||||
|   AsyncVelControllerBuilder &withGains(const IterativeVelPIDController::Gains &igains); | ||||
|  | ||||
|   /** | ||||
|    * Sets the VelMath which calculates and filters velocity. This is ignored when using integrated | ||||
|    * controller. If using a PID controller (by setting the gains), this is required. | ||||
|    * | ||||
|    * @param ivelMath The VelMath. | ||||
|    * @return An ongoing builder. | ||||
|    */ | ||||
|   AsyncVelControllerBuilder &withVelMath(std::unique_ptr<VelMath> ivelMath); | ||||
|  | ||||
|   /** | ||||
|    * Sets the derivative filter which filters the derivative term before it is scaled by kD. The | ||||
|    * filter is ignored when using integrated control. The default derivative filter is a | ||||
|    * PassthroughFilter. | ||||
|    * | ||||
|    * @param iderivativeFilter The derivative filter. | ||||
|    * @return An ongoing builder. | ||||
|    */ | ||||
|   AsyncVelControllerBuilder &withDerivativeFilter(std::unique_ptr<Filter> iderivativeFilter); | ||||
|  | ||||
|   /** | ||||
|    * Sets the gearset. The default gearset is derived from the motor's. | ||||
|    * | ||||
|    * @param igearset The gearset. | ||||
|    * @return An ongoing builder. | ||||
|    */ | ||||
|   AsyncVelControllerBuilder &withGearset(const AbstractMotor::GearsetRatioPair &igearset); | ||||
|  | ||||
|   /** | ||||
|    * Sets the maximum velocity. The default maximum velocity is derived from the motor's gearset. | ||||
|    * This parameter is ignored when using an AsyncVelPIDController. | ||||
|    * | ||||
|    * @param imaxVelocity The maximum velocity. | ||||
|    * @return An ongoing builder. | ||||
|    */ | ||||
|   AsyncVelControllerBuilder &withMaxVelocity(double imaxVelocity); | ||||
|  | ||||
|   /** | ||||
|    * Sets the TimeUtilFactory used when building the controller. The default is the static | ||||
|    * TimeUtilFactory. | ||||
|    * | ||||
|    * @param itimeUtilFactory The TimeUtilFactory. | ||||
|    * @return An ongoing builder. | ||||
|    */ | ||||
|   AsyncVelControllerBuilder &withTimeUtilFactory(const TimeUtilFactory &itimeUtilFactory); | ||||
|  | ||||
|   /** | ||||
|    * Sets the logger. | ||||
|    * | ||||
|    * @param ilogger The logger. | ||||
|    * @return An ongoing builder. | ||||
|    */ | ||||
|   AsyncVelControllerBuilder &withLogger(const std::shared_ptr<Logger> &ilogger); | ||||
|  | ||||
|   /** | ||||
|    * Parents the internal tasks started by this builder to the current task, meaning they will be | ||||
|    * deleted once the current task is deleted. The `initialize` and `competition_initialize` tasks | ||||
|    * are never parented to. This is the default behavior. | ||||
|    * | ||||
|    * Read more about this in the [builders and tasks tutorial] | ||||
|    * (docs/tutorials/concepts/builders-and-tasks.md). | ||||
|    * | ||||
|    * @return An ongoing builder. | ||||
|    */ | ||||
|   AsyncVelControllerBuilder &parentedToCurrentTask(); | ||||
|  | ||||
|   /** | ||||
|    * Prevents parenting the internal tasks started by this builder to the current task, meaning they | ||||
|    * will not be deleted once the current task is deleted. This can cause runaway tasks, but is | ||||
|    * sometimes the desired behavior (e.x., if you want to use this builder once in `autonomous` and | ||||
|    * then again in `opcontrol`). | ||||
|    * | ||||
|    * Read more about this in the [builders and tasks tutorial] | ||||
|    * (docs/tutorials/concepts/builders-and-tasks.md). | ||||
|    * | ||||
|    * @return An ongoing builder. | ||||
|    */ | ||||
|   AsyncVelControllerBuilder ¬ParentedToCurrentTask(); | ||||
|  | ||||
|   /** | ||||
|    * Builds the AsyncVelocityController. Throws a std::runtime_exception is no motors were set. | ||||
|    * | ||||
|    * @return A fully built AsyncVelocityController. | ||||
|    */ | ||||
|   std::shared_ptr<AsyncVelocityController<double, double>> build(); | ||||
|  | ||||
|   private: | ||||
|   std::shared_ptr<Logger> logger; | ||||
|  | ||||
|   bool hasMotors{false}; // Used to verify motors were passed | ||||
|   std::shared_ptr<AbstractMotor> motor; | ||||
|  | ||||
|   bool sensorsSetByUser{false}; // Used so motors don't overwrite sensors set manually | ||||
|   std::shared_ptr<RotarySensor> sensor; | ||||
|  | ||||
|   bool hasGains{false}; // Whether gains were passed, no gains means integrated control | ||||
|   IterativeVelPIDController::Gains gains; | ||||
|  | ||||
|   bool hasVelMath{false}; // Used to verify velMath was passed | ||||
|   std::unique_ptr<VelMath> velMath; | ||||
|  | ||||
|   std::unique_ptr<Filter> derivativeFilter = std::make_unique<PassthroughFilter>(); | ||||
|  | ||||
|   bool gearsetSetByUser{false}; // Used so motor's don't overwrite a gearset set manually | ||||
|   AbstractMotor::GearsetRatioPair pair{AbstractMotor::gearset::invalid}; | ||||
|  | ||||
|   bool maxVelSetByUser{false}; // Used so motors don't overwrite maxVelocity | ||||
|   double maxVelocity{600}; | ||||
|  | ||||
|   TimeUtilFactory timeUtilFactory = TimeUtilFactory(); | ||||
|   std::shared_ptr<Logger> controllerLogger = Logger::getDefaultLogger(); | ||||
|  | ||||
|   bool isParentedToCurrentTask{true}; | ||||
|  | ||||
|   std::shared_ptr<AsyncVelIntegratedController> buildAVIC(); | ||||
|   std::shared_ptr<AsyncVelPIDController> buildAVPC(); | ||||
| }; | ||||
| } // namespace okapi | ||||
| @@ -0,0 +1,120 @@ | ||||
| /* | ||||
|  * This Source Code Form is subject to the terms of the Mozilla Public | ||||
|  * License, v. 2.0. If a copy of the MPL was not distributed with this | ||||
|  * file, You can obtain one at http://mozilla.org/MPL/2.0/. | ||||
|  */ | ||||
| #pragma once | ||||
|  | ||||
| #include "okapi/api/control/iterative/iterativeMotorVelocityController.hpp" | ||||
| #include "okapi/api/control/iterative/iterativePosPidController.hpp" | ||||
| #include "okapi/api/control/iterative/iterativeVelPidController.hpp" | ||||
| #include "okapi/api/util/mathUtil.hpp" | ||||
| #include "okapi/impl/device/motor/motor.hpp" | ||||
| #include "okapi/impl/device/motor/motorGroup.hpp" | ||||
| #include "okapi/impl/filter/velMathFactory.hpp" | ||||
|  | ||||
| namespace okapi { | ||||
| class IterativeControllerFactory { | ||||
|   public: | ||||
|   /** | ||||
|    * Position PID controller. | ||||
|    * | ||||
|    * @param ikP proportional gain | ||||
|    * @param ikI integral gain | ||||
|    * @param ikD derivative gain | ||||
|    * @param ikBias controller bias (constant offset added to the output) | ||||
|    * @param iderivativeFilter A filter for filtering the derivative term. | ||||
|    * @param ilogger The logger this instance will log to. | ||||
|    */ | ||||
|   static IterativePosPIDController | ||||
|   posPID(double ikP, | ||||
|          double ikI, | ||||
|          double ikD, | ||||
|          double ikBias = 0, | ||||
|          std::unique_ptr<Filter> iderivativeFilter = std::make_unique<PassthroughFilter>(), | ||||
|          const std::shared_ptr<Logger> &ilogger = Logger::getDefaultLogger()); | ||||
|  | ||||
|   /** | ||||
|    * Velocity PD controller. | ||||
|    * | ||||
|    * @param ikP proportional gain | ||||
|    * @param ikD derivative gain | ||||
|    * @param ikF feed-forward gain | ||||
|    * @param ikSF a feed-forward gain to counteract static friction | ||||
|    * @param iderivativeFilter A filter for filtering the derivative term. | ||||
|    * @param ilogger The logger this instance will log to. | ||||
|    */ | ||||
|   static IterativeVelPIDController | ||||
|   velPID(double ikP, | ||||
|          double ikD, | ||||
|          double ikF = 0, | ||||
|          double ikSF = 0, | ||||
|          std::unique_ptr<VelMath> ivelMath = VelMathFactory::createPtr(imev5GreenTPR), | ||||
|          std::unique_ptr<Filter> iderivativeFilter = std::make_unique<PassthroughFilter>(), | ||||
|          const std::shared_ptr<Logger> &ilogger = Logger::getDefaultLogger()); | ||||
|  | ||||
|   /** | ||||
|    * Velocity PD controller that automatically writes to the motor. | ||||
|    * | ||||
|    * @param imotor output motor | ||||
|    * @param ikP proportional gain | ||||
|    * @param ikD derivative gain | ||||
|    * @param ikF feed-forward gain | ||||
|    * @param ikSF a feed-forward gain to counteract static friction | ||||
|    * @param ivelMath The VelMath. | ||||
|    * @param iderivativeFilter A filter for filtering the derivative term. | ||||
|    * @param ilogger The logger this instance will log to. | ||||
|    */ | ||||
|   static IterativeMotorVelocityController | ||||
|   motorVelocity(Motor imotor, | ||||
|                 double ikP, | ||||
|                 double ikD, | ||||
|                 double ikF = 0, | ||||
|                 double ikSF = 0, | ||||
|                 std::unique_ptr<VelMath> ivelMath = VelMathFactory::createPtr(imev5GreenTPR), | ||||
|                 std::unique_ptr<Filter> iderivativeFilter = std::make_unique<PassthroughFilter>(), | ||||
|                 const std::shared_ptr<Logger> &ilogger = Logger::getDefaultLogger()); | ||||
|  | ||||
|   /** | ||||
|    * Velocity PD controller that automatically writes to the motor. | ||||
|    * | ||||
|    * @param imotor output motor | ||||
|    * @param ikP proportional gain | ||||
|    * @param ikD derivative gain | ||||
|    * @param ikF feed-forward gain | ||||
|    * @param ikSF a feed-forward gain to counteract static friction | ||||
|    * @param ivelMath The VelMath. | ||||
|    * @param iderivativeFilter A filter for filtering the derivative term. | ||||
|    * @param ilogger The logger this instance will log to. | ||||
|    */ | ||||
|   static IterativeMotorVelocityController | ||||
|   motorVelocity(MotorGroup imotor, | ||||
|                 double ikP, | ||||
|                 double ikD, | ||||
|                 double ikF = 0, | ||||
|                 double ikSF = 0, | ||||
|                 std::unique_ptr<VelMath> ivelMath = VelMathFactory::createPtr(imev5GreenTPR), | ||||
|                 std::unique_ptr<Filter> iderivativeFilter = std::make_unique<PassthroughFilter>(), | ||||
|                 const std::shared_ptr<Logger> &ilogger = Logger::getDefaultLogger()); | ||||
|  | ||||
|   /** | ||||
|    * Velocity PD controller that automatically writes to the motor. | ||||
|    * | ||||
|    * @param imotor output motor | ||||
|    * @param icontroller controller to use | ||||
|    */ | ||||
|   static IterativeMotorVelocityController | ||||
|   motorVelocity(Motor imotor, | ||||
|                 std::shared_ptr<IterativeVelocityController<double, double>> icontroller); | ||||
|  | ||||
|   /** | ||||
|    * Velocity PD controller that automatically writes to the motor. | ||||
|    * | ||||
|    * @param imotor output motor | ||||
|    * @param icontroller controller to use | ||||
|    */ | ||||
|   static IterativeMotorVelocityController | ||||
|   motorVelocity(MotorGroup imotor, | ||||
|                 std::shared_ptr<IterativeVelocityController<double, double>> icontroller); | ||||
| }; | ||||
| } // namespace okapi | ||||
| @@ -0,0 +1,25 @@ | ||||
| /* | ||||
|  * This Source Code Form is subject to the terms of the Mozilla Public | ||||
|  * License, v. 2.0. If a copy of the MPL was not distributed with this | ||||
|  * file, You can obtain one at http://mozilla.org/MPL/2.0/. | ||||
|  */ | ||||
| #pragma once | ||||
|  | ||||
| #include "okapi/api/control/util/controllerRunner.hpp" | ||||
| #include "okapi/impl/util/timeUtilFactory.hpp" | ||||
|  | ||||
| namespace okapi { | ||||
| template <typename Input, typename Output> class ControllerRunnerFactory { | ||||
|   public: | ||||
|   /** | ||||
|    * A utility class that runs a closed-loop controller. | ||||
|    * | ||||
|    * @param ilogger The logger this instance will log to. | ||||
|    * @return | ||||
|    */ | ||||
|   static ControllerRunner<Input, Output> | ||||
|   create(const std::shared_ptr<Logger> &ilogger = Logger::getDefaultLogger()) { | ||||
|     return ControllerRunner<Input, Output>(TimeUtilFactory::createDefault(), ilogger); | ||||
|   } | ||||
| }; | ||||
| } // namespace okapi | ||||
| @@ -0,0 +1,47 @@ | ||||
| /* | ||||
|  * This Source Code Form is subject to the terms of the Mozilla Public | ||||
|  * License, v. 2.0. If a copy of the MPL was not distributed with this | ||||
|  * file, You can obtain one at http://mozilla.org/MPL/2.0/. | ||||
|  */ | ||||
| #pragma once | ||||
|  | ||||
| #include "okapi/api/control/util/pidTuner.hpp" | ||||
| #include <memory> | ||||
|  | ||||
| namespace okapi { | ||||
| class PIDTunerFactory { | ||||
|   public: | ||||
|   static PIDTuner create(const std::shared_ptr<ControllerInput<double>> &iinput, | ||||
|                          const std::shared_ptr<ControllerOutput<double>> &ioutput, | ||||
|                          QTime itimeout, | ||||
|                          std::int32_t igoal, | ||||
|                          double ikPMin, | ||||
|                          double ikPMax, | ||||
|                          double ikIMin, | ||||
|                          double ikIMax, | ||||
|                          double ikDMin, | ||||
|                          double ikDMax, | ||||
|                          std::int32_t inumIterations = 5, | ||||
|                          std::int32_t inumParticles = 16, | ||||
|                          double ikSettle = 1, | ||||
|                          double ikITAE = 2, | ||||
|                          const std::shared_ptr<Logger> &ilogger = Logger::getDefaultLogger()); | ||||
|  | ||||
|   static std::unique_ptr<PIDTuner> | ||||
|   createPtr(const std::shared_ptr<ControllerInput<double>> &iinput, | ||||
|             const std::shared_ptr<ControllerOutput<double>> &ioutput, | ||||
|             QTime itimeout, | ||||
|             std::int32_t igoal, | ||||
|             double ikPMin, | ||||
|             double ikPMax, | ||||
|             double ikIMin, | ||||
|             double ikIMax, | ||||
|             double ikDMin, | ||||
|             double ikDMax, | ||||
|             std::int32_t inumIterations = 5, | ||||
|             std::int32_t inumParticles = 16, | ||||
|             double ikSettle = 1, | ||||
|             double ikITAE = 2, | ||||
|             const std::shared_ptr<Logger> &ilogger = Logger::getDefaultLogger()); | ||||
| }; | ||||
| } // namespace okapi | ||||
							
								
								
									
										71
									
								
								SerialTest/include/okapi/impl/device/adiUltrasonic.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										71
									
								
								SerialTest/include/okapi/impl/device/adiUltrasonic.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,71 @@ | ||||
| /* | ||||
|  * This Source Code Form is subject to the terms of the Mozilla Public | ||||
|  * License, v. 2.0. If a copy of the MPL was not distributed with this | ||||
|  * file, You can obtain one at http://mozilla.org/MPL/2.0/. | ||||
|  */ | ||||
| #pragma once | ||||
|  | ||||
| #include "api.h" | ||||
| #include "okapi/api/control/controllerInput.hpp" | ||||
| #include "okapi/api/filter/passthroughFilter.hpp" | ||||
| #include <memory> | ||||
|  | ||||
| namespace okapi { | ||||
| class ADIUltrasonic : public ControllerInput<double> { | ||||
|   public: | ||||
|   /** | ||||
|    * An ultrasonic sensor in the ADI (3-wire) ports. | ||||
|    * | ||||
|    * ```cpp | ||||
|    * auto ultra = ADIUltrasonic('A', 'B'); | ||||
|    * auto filteredUltra = ADIUltrasonic('A', 'B', std::make_unique<MedianFilter<5>>()); | ||||
|    * ``` | ||||
|    * | ||||
|    * @param iportPing The port connected to the orange OUTPUT cable. This must be in port ``1``, | ||||
|    * ``3``, ``5``, or ``7`` (``A``, ``C``, ``E``, or ``G``). | ||||
|    * @param iportEcho The port connected to the yellow INPUT cable. This must be in the next highest | ||||
|    * port following iportPing. | ||||
|    * @param ifilter The filter to use for filtering the distance measurements. | ||||
|    */ | ||||
|   ADIUltrasonic(std::uint8_t iportPing, | ||||
|                 std::uint8_t iportEcho, | ||||
|                 std::unique_ptr<Filter> ifilter = std::make_unique<PassthroughFilter>()); | ||||
|  | ||||
|   /** | ||||
|    * An ultrasonic sensor in the ADI (3-wire) ports. | ||||
|    * | ||||
|    * ```cpp | ||||
|    * auto ultra = ADIUltrasonic({1, 'A', 'B'}); | ||||
|    * auto filteredUltra = ADIUltrasonic({1, 'A', 'B'}, std::make_unique<MedianFilter<5>>()); | ||||
|    * ``` | ||||
|    * | ||||
|    * @param iports The ports the ultrasonic is plugged in to in the order ``{smart port, ping port, | ||||
|    * echo port}``. The smart port is the smart port number (``[1, 21]``). The ping port is the port | ||||
|    * connected to the orange OUTPUT cable. This must be in port ``1``, ``3``, ``5``, or ``7`` | ||||
|    * (``A``, ``C``, ``E``, or ``G``). The echo port is the port connected to the yellow INPUT cable. | ||||
|    * This must be in the next highest port following the ping port. | ||||
|    * @param ifilter The filter to use for filtering the distance measurements. | ||||
|    */ | ||||
|   ADIUltrasonic(std::tuple<std::uint8_t, std::uint8_t, std::uint8_t> iports, | ||||
|                 std::unique_ptr<Filter> ifilter = std::make_unique<PassthroughFilter>()); | ||||
|  | ||||
|   virtual ~ADIUltrasonic(); | ||||
|  | ||||
|   /** | ||||
|    * Returns the current filtered sensor value. | ||||
|    * | ||||
|    * @return current value | ||||
|    */ | ||||
|   virtual double get(); | ||||
|  | ||||
|   /** | ||||
|    * Get the sensor value for use in a control loop. This method might be automatically called in | ||||
|    * another thread by the controller. Calls get(). | ||||
|    */ | ||||
|   virtual double controllerGet() override; | ||||
|  | ||||
|   protected: | ||||
|   pros::c::ext_adi_ultrasonic_t ultra; | ||||
|   std::unique_ptr<Filter> filter; | ||||
| }; | ||||
| } // namespace okapi | ||||
							
								
								
									
										50
									
								
								SerialTest/include/okapi/impl/device/button/adiButton.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										50
									
								
								SerialTest/include/okapi/impl/device/button/adiButton.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,50 @@ | ||||
| /* | ||||
|  * This Source Code Form is subject to the terms of the Mozilla Public | ||||
|  * License, v. 2.0. If a copy of the MPL was not distributed with this | ||||
|  * file, You can obtain one at http://mozilla.org/MPL/2.0/. | ||||
|  */ | ||||
| #pragma once | ||||
|  | ||||
| #include "api.h" | ||||
| #include "okapi/api/device/button/buttonBase.hpp" | ||||
|  | ||||
| namespace okapi { | ||||
| class ADIButton : public ButtonBase { | ||||
|   public: | ||||
|   /** | ||||
|    * A button in an ADI port. | ||||
|    * | ||||
|    * ```cpp | ||||
|    * auto btn = ADIButton('A', false); | ||||
|    * auto invertedBtn = ADIButton('A', true); | ||||
|    * ``` | ||||
|    * | ||||
|    * @param iport The ADI port number (``[1, 8]``, ``[a, h]``, ``[A, H]``). | ||||
|    * @param iinverted Whether the button is inverted (``true`` meaning default pressed and ``false`` | ||||
|    * meaning default not pressed). | ||||
|    */ | ||||
|   ADIButton(std::uint8_t iport, bool iinverted = false); | ||||
|  | ||||
|   /** | ||||
|    * A button in an ADI port. | ||||
|    * | ||||
|    * ```cpp | ||||
|    * auto btn = ADIButton({1, 'A'}, false); | ||||
|    * auto invertedBtn = ADIButton({1, 'A'}, true); | ||||
|    * ``` | ||||
|    * | ||||
|    * @param iports The ports the button is plugged in to in the order ``{smart port, button port}``. | ||||
|    * The smart port is the smart port number (``[1, 21]``). The button port is the ADI port number | ||||
|    * (``[1, 8]``, ``[a, h]``, ``[A, H]``). | ||||
|    * @param iinverted Whether the button is inverted (``true`` meaning default pressed and ``false`` | ||||
|    * meaning default not pressed). | ||||
|    */ | ||||
|   ADIButton(std::pair<std::uint8_t, std::uint8_t> iports, bool iinverted = false); | ||||
|  | ||||
|   protected: | ||||
|   std::uint8_t smartPort; | ||||
|   std::uint8_t port; | ||||
|  | ||||
|   virtual bool currentlyPressed() override; | ||||
| }; | ||||
| } // namespace okapi | ||||
| @@ -0,0 +1,38 @@ | ||||
| /* | ||||
|  * This Source Code Form is subject to the terms of the Mozilla Public | ||||
|  * License, v. 2.0. If a copy of the MPL was not distributed with this | ||||
|  * file, You can obtain one at http://mozilla.org/MPL/2.0/. | ||||
|  */ | ||||
| #pragma once | ||||
|  | ||||
| #include "api.h" | ||||
| #include "okapi/api/device/button/buttonBase.hpp" | ||||
| #include "okapi/impl/device/controllerUtil.hpp" | ||||
|  | ||||
| namespace okapi { | ||||
| class ControllerButton : public ButtonBase { | ||||
|   public: | ||||
|   /** | ||||
|    * A button on a Controller. | ||||
|    * | ||||
|    * @param ibtn The button id. | ||||
|    * @param iinverted Whether the button is inverted (default pressed instead of default released). | ||||
|    */ | ||||
|   ControllerButton(ControllerDigital ibtn, bool iinverted = false); | ||||
|  | ||||
|   /** | ||||
|    * A button on a Controller. | ||||
|    * | ||||
|    * @param icontroller The Controller the button is on. | ||||
|    * @param ibtn The button id. | ||||
|    * @param iinverted Whether the button is inverted (default pressed instead of default released). | ||||
|    */ | ||||
|   ControllerButton(ControllerId icontroller, ControllerDigital ibtn, bool iinverted = false); | ||||
|  | ||||
|   protected: | ||||
|   pros::controller_id_e_t id; | ||||
|   pros::controller_digital_e_t btn; | ||||
|  | ||||
|   virtual bool currentlyPressed() override; | ||||
| }; | ||||
| } // namespace okapi | ||||
							
								
								
									
										118
									
								
								SerialTest/include/okapi/impl/device/controller.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										118
									
								
								SerialTest/include/okapi/impl/device/controller.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,118 @@ | ||||
| /* | ||||
|  * This Source Code Form is subject to the terms of the Mozilla Public | ||||
|  * License, v. 2.0. If a copy of the MPL was not distributed with this | ||||
|  * file, You can obtain one at http://mozilla.org/MPL/2.0/. | ||||
|  */ | ||||
| #pragma once | ||||
|  | ||||
| #include "api.h" | ||||
| #include "okapi/impl/device/button/controllerButton.hpp" | ||||
| #include "okapi/impl/device/controllerUtil.hpp" | ||||
| #include <array> | ||||
|  | ||||
| namespace okapi { | ||||
| class Controller { | ||||
|   public: | ||||
|   Controller(ControllerId iid = ControllerId::master); | ||||
|  | ||||
|   virtual ~Controller(); | ||||
|  | ||||
|   /** | ||||
|    * Returns whether the controller is connected. | ||||
|    * | ||||
|    * @return true if the controller is connected | ||||
|    */ | ||||
|   virtual bool isConnected(); | ||||
|  | ||||
|   /** | ||||
|    * Returns the current analog reading for the channel in the range [-1, 1]. Returns 0 if the | ||||
|    * controller is not connected. | ||||
|    * | ||||
|    * @param ichannel the channel to read | ||||
|    * @return the value of that channel in the range [-1, 1] | ||||
|    */ | ||||
|   virtual float getAnalog(ControllerAnalog ichannel); | ||||
|  | ||||
|   /** | ||||
|    * Returns whether the digital button is currently pressed. Returns false if the controller is | ||||
|    * not connected. | ||||
|    * | ||||
|    * @param ibutton the button to check | ||||
|    * @return true if the button is pressed, false if the controller is not connected | ||||
|    */ | ||||
|   virtual bool getDigital(ControllerDigital ibutton); | ||||
|  | ||||
|   /** | ||||
|    * Returns a ControllerButton for the given button on this controller. | ||||
|    * | ||||
|    * @param ibtn the button | ||||
|    * @return a ControllerButton on this controller | ||||
|    */ | ||||
|   virtual ControllerButton &operator[](ControllerDigital ibtn); | ||||
|  | ||||
|   /** | ||||
|    * Sets text to the controller LCD screen. | ||||
|    * | ||||
|    * @param iline the line number in the range [0-2] at which the text will be displayed | ||||
|    * @param icol the column number in the range [0-14] at which the text will be displayed | ||||
|    * @param itext the string to display | ||||
|    * @return 1 if the operation was successful, PROS_ERR otherwise | ||||
|    */ | ||||
|   virtual std::int32_t setText(std::uint8_t iline, std::uint8_t icol, std::string itext); | ||||
|  | ||||
|   /** | ||||
|    * Clears all of the lines of the controller screen. On vexOS version 1.0.0 this function will | ||||
|    * block for 110ms. | ||||
|    * | ||||
|    * @return 1 if the operation was successful, PROS_ERR otherwise | ||||
|    */ | ||||
|   virtual std::int32_t clear(); | ||||
|  | ||||
|   /** | ||||
|    * Clears an individual line of the controller screen. | ||||
|    * | ||||
|    * @param iline the line number to clear in the range [0, 2]. | ||||
|    * @return 1 if the operation was successful, PROS_ERR otherwise | ||||
|    */ | ||||
|   virtual std::int32_t clearLine(std::uint8_t iline); | ||||
|  | ||||
|   /** | ||||
|    * Rumble the controller. | ||||
|    * | ||||
|    * Controller rumble activation is currently in beta, so continuous, fast | ||||
|    * updates will not work well. | ||||
|    * | ||||
|    * @param irumblePattern A string consisting of the characters '.', '-', and ' ', where dots are | ||||
|    * short rumbles, dashes are long rumbles, and spaces are pauses. Maximum supported length is 8 | ||||
|    * characters. | ||||
|    * | ||||
|    * @return 1 if the operation was successful or PROS_ERR if the operation failed, setting errno. | ||||
|    */ | ||||
|   virtual std::int32_t rumble(std::string irumblePattern); | ||||
|  | ||||
|   /** | ||||
|    * Gets the battery capacity of the given controller. | ||||
|    * | ||||
|    * This function uses the following values of errno when an error state is reached: | ||||
|    * EACCES - Another resource is currently trying to access the controller port. | ||||
|    * | ||||
|    * @return the controller's battery capacity | ||||
|    */ | ||||
|   virtual std::int32_t getBatteryCapacity(); | ||||
|  | ||||
|   /** | ||||
|    * Gets the battery level of the given controller. | ||||
|    * | ||||
|    * This function uses the following values of errno when an error state is reached: | ||||
|    * EACCES - Another resource is currently trying to access the controller port. | ||||
|    * | ||||
|    * @return the controller's battery level | ||||
|    */ | ||||
|   virtual std::int32_t getBatteryLevel(); | ||||
|  | ||||
|   protected: | ||||
|   ControllerId okapiId; | ||||
|   pros::controller_id_e_t prosId; | ||||
|   std::array<ControllerButton *, 12> buttonArray{}; | ||||
| }; | ||||
| } // namespace okapi | ||||
							
								
								
									
										64
									
								
								SerialTest/include/okapi/impl/device/controllerUtil.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										64
									
								
								SerialTest/include/okapi/impl/device/controllerUtil.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,64 @@ | ||||
| /* | ||||
|  * This Source Code Form is subject to the terms of the Mozilla Public | ||||
|  * License, v. 2.0. If a copy of the MPL was not distributed with this | ||||
|  * file, You can obtain one at http://mozilla.org/MPL/2.0/. | ||||
|  */ | ||||
| #pragma once | ||||
|  | ||||
| #include "api.h" | ||||
|  | ||||
| namespace okapi { | ||||
| /** | ||||
|  * Which controller role this has. | ||||
|  */ | ||||
| enum class ControllerId { | ||||
|   master = 0, ///< master | ||||
|   partner = 1 ///< partner | ||||
| }; | ||||
|  | ||||
| /** | ||||
|  * The analog sticks. | ||||
|  */ | ||||
| enum class ControllerAnalog { | ||||
|   leftX = 0,  ///< leftX | ||||
|   leftY = 1,  ///< leftY | ||||
|   rightX = 2, ///< rightX | ||||
|   rightY = 3  ///< rightY | ||||
| }; | ||||
|  | ||||
| /** | ||||
|  * Various buttons. | ||||
|  */ | ||||
| enum class ControllerDigital { | ||||
|   L1 = 6,     ///< L1 | ||||
|   L2 = 7,     ///< L2 | ||||
|   R1 = 8,     ///< R1 | ||||
|   R2 = 9,     ///< R2 | ||||
|   up = 10,    ///< up | ||||
|   down = 11,  ///< down | ||||
|   left = 12,  ///< left | ||||
|   right = 13, ///< right | ||||
|   X = 14,     ///< X | ||||
|   B = 15,     ///< B | ||||
|   Y = 16,     ///< Y | ||||
|   A = 17      ///< A | ||||
| }; | ||||
|  | ||||
| class ControllerUtil { | ||||
|   public: | ||||
|   /** | ||||
|    * Maps an `id` to the PROS enum equivalent. | ||||
|    */ | ||||
|   static pros::controller_id_e_t idToProsEnum(ControllerId in); | ||||
|  | ||||
|   /** | ||||
|    * Maps an `analog` to the PROS enum equivalent. | ||||
|    */ | ||||
|   static pros::controller_analog_e_t analogToProsEnum(ControllerAnalog in); | ||||
|  | ||||
|   /** | ||||
|    * Maps a `digital` to the PROS enum equivalent. | ||||
|    */ | ||||
|   static pros::controller_digital_e_t digitalToProsEnum(ControllerDigital in); | ||||
| }; | ||||
| } // namespace okapi | ||||
							
								
								
									
										76
									
								
								SerialTest/include/okapi/impl/device/distanceSensor.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										76
									
								
								SerialTest/include/okapi/impl/device/distanceSensor.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,76 @@ | ||||
| /* | ||||
|  * This Source Code Form is subject to the terms of the Mozilla Public | ||||
|  * License, v. 2.0. If a copy of the MPL was not distributed with this | ||||
|  * file, You can obtain one at http://mozilla.org/MPL/2.0/. | ||||
|  */ | ||||
| #pragma once | ||||
|  | ||||
| #include "api.h" | ||||
| #include "okapi/api/control/controllerInput.hpp" | ||||
| #include "okapi/api/filter/passthroughFilter.hpp" | ||||
| #include <memory> | ||||
|  | ||||
| namespace okapi { | ||||
| class DistanceSensor : public ControllerInput<double> { | ||||
|   public: | ||||
|   /** | ||||
|    * A distance sensor on a V5 port. | ||||
|    * | ||||
|    * ```cpp | ||||
|    * auto ds = DistanceSensor(1); | ||||
|    * auto filteredDistSensor = DistanceSensor(1, std::make_unique<MedianFilter<5>>()); | ||||
|    * ``` | ||||
|    * | ||||
|    * @param iport The V5 port the device uses. | ||||
|    * @param ifilter The filter to use for filtering the distance measurements. | ||||
|    */ | ||||
|   DistanceSensor(std::uint8_t iport, | ||||
|                  std::unique_ptr<Filter> ifilter = std::make_unique<PassthroughFilter>()); | ||||
|  | ||||
|   virtual ~DistanceSensor() = default; | ||||
|  | ||||
|   /** | ||||
|    * Get the current filtered sensor value in mm. | ||||
|    * | ||||
|    * @return The current filtered sensor value in mm. | ||||
|    */ | ||||
|   double get(); | ||||
|  | ||||
|   /** | ||||
|    * Get the sensor value for use in a control loop. This method might be automatically called in | ||||
|    * another thread by the controller. | ||||
|    * | ||||
|    * @return The same as [get](@ref okapi::DistanceSensor::get). | ||||
|    */ | ||||
|   double controllerGet() override; | ||||
|  | ||||
|   /** | ||||
|    * Get the confidence in the distance reading. This value has a range of ``[0, 63]``. ``63`` means | ||||
|    * high confidence, lower values imply less confidence. Confidence is only available when distance | ||||
|    * is greater than ``200`` mm. | ||||
|    * | ||||
|    * @return The confidence value in the range ``[0, 63]``. | ||||
|    */ | ||||
|   std::int32_t getConfidence() const; | ||||
|  | ||||
|   /** | ||||
|    * Get the current guess at relative object size. This value has a range of ``[0, 400]``. A 18" x | ||||
|    * 30" grey card will return a value of approximately ``75`` in typical room lighting. | ||||
|    * | ||||
|    * @return The size value in the range ``[0, 400]`` or ``PROS_ERR`` if the operation failed, | ||||
|    * setting errno. | ||||
|    */ | ||||
|   std::int32_t getObjectSize() const; | ||||
|  | ||||
|   /** | ||||
|    * Get the object velocity in m/s. | ||||
|    * | ||||
|    * @return The object velocity in m/s. | ||||
|    */ | ||||
|   double getObjectVelocity() const; | ||||
|  | ||||
|   protected: | ||||
|   std::uint8_t port; | ||||
|   std::unique_ptr<Filter> filter; | ||||
| }; | ||||
| } // namespace okapi | ||||
							
								
								
									
										69
									
								
								SerialTest/include/okapi/impl/device/motor/adiMotor.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										69
									
								
								SerialTest/include/okapi/impl/device/motor/adiMotor.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,69 @@ | ||||
| /* | ||||
|  * This Source Code Form is subject to the terms of the Mozilla Public | ||||
|  * License, v. 2.0. If a copy of the MPL was not distributed with this | ||||
|  * file, You can obtain one at http://mozilla.org/MPL/2.0/. | ||||
|  */ | ||||
| #pragma once | ||||
|  | ||||
| #include "api.h" | ||||
| #include "okapi/api/control/controllerOutput.hpp" | ||||
| #include "okapi/api/util/logging.hpp" | ||||
|  | ||||
| namespace okapi { | ||||
| class ADIMotor : public ControllerOutput<double> { | ||||
|   public: | ||||
|   /** | ||||
|    * A motor in an ADI port. | ||||
|    * | ||||
|    * ```cpp | ||||
|    * auto mtr = ADIMotor('A'); | ||||
|    * auto reversedMtr = ADIMotor('A', true); | ||||
|    * ``` | ||||
|    * | ||||
|    * @param iport The ADI port number (``[1, 8]``, ``[a, h]``, ``[A, H]``). | ||||
|    * @param ireverse Whether the motor is reversed. | ||||
|    * @param logger The logger that initialization warnings will be logged to. | ||||
|    */ | ||||
|   ADIMotor(std::uint8_t iport, | ||||
|            bool ireverse = false, | ||||
|            const std::shared_ptr<Logger> &logger = Logger::getDefaultLogger()); | ||||
|  | ||||
|   /** | ||||
|    * A motor in an ADI port. | ||||
|    * | ||||
|    * ```cpp | ||||
|    * auto mtr = ADIMotor({1, 'A'}, false); | ||||
|    * auto reversedMtr = ADIMotor({1, 'A'}, true); | ||||
|    * ``` | ||||
|    * | ||||
|    * @param iports The ports the motor is plugged in to in the order ``{smart port, motor port}``. | ||||
|    * The smart port is the smart port number (``[1, 21]``). The motor port is the ADI port number | ||||
|    * (``[1, 8]``, ``[a, h]``, ``[A, H]``). | ||||
|    * @param ireverse Whether the motor is reversed. | ||||
|    * @param logger The logger that initialization warnings will be logged to. | ||||
|    */ | ||||
|   ADIMotor(std::pair<std::uint8_t, std::uint8_t> iports, | ||||
|            bool ireverse = false, | ||||
|            const std::shared_ptr<Logger> &logger = Logger::getDefaultLogger()); | ||||
|  | ||||
|   /** | ||||
|    * Set the voltage to the motor. | ||||
|    * | ||||
|    * @param ivoltage voltage in the range [-127, 127]. | ||||
|    */ | ||||
|   virtual void moveVoltage(std::int8_t ivoltage) const; | ||||
|  | ||||
|   /** | ||||
|    * Writes the value of the controller output. This method might be automatically called in another | ||||
|    * thread by the controller. The range of input values is expected to be [-1, 1]. | ||||
|    * | ||||
|    * @param ivalue the controller's output in the range [-1, 1] | ||||
|    */ | ||||
|   void controllerSet(double ivalue) override; | ||||
|  | ||||
|   protected: | ||||
|   std::uint8_t smartPort; | ||||
|   std::uint8_t port; | ||||
|   std::int8_t reversed; | ||||
| }; | ||||
| } // namespace okapi | ||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user