#pragma once #include #include #include #include #include #include namespace differential { namespace bacc = boost::accumulators; /** * \brief The Odometry class handles odometry readings * (2D pose and velocity with related timestamp) */ class Odometry { public: /// Integration function, used to integrate the odometry: typedef boost::function IntegrationFunction; /** * \brief Constructor * Timestamp will get the current time value * Value will be set to zero * \param velocity_rolling_window_size Rolling window size used to compute the velocity mean */ Odometry(size_t velocity_rolling_window_size = 10); /** * \brief Initialize the odometry * \param time Current time */ void init(const double &time); /** * \brief Updates the odometry class with latest wheel angular velocities * \param left_vel Left wheel angular velocity [rad/s] * \param right_vel Right wheel angular velocity [rad/s] * \param time Current time * \return true if the odometry is actually updated */ bool updateWheel(double left_vel, double right_vel, const double &time); /** * \brief Updates odometry from cumulative encoder tick counts * * Converts tick deltas to wheel arc lengths, then integrates pose with the * same exact/RK2 path as updateWheel. The first call after init() only * seeds the previous tick counts and returns false. * * Caller should unwrap hardware counter overflow into a monotonic int64 * cumulative count before calling. * * \param left_ticks Cumulative left wheel ticks (after gearbox, wheel side) * \param right_ticks Cumulative right wheel ticks (after gearbox, wheel side) * \param time Current time [s] * \return true if the odometry is actually updated */ bool updateTicks(std::int64_t left_ticks, std::int64_t right_ticks, const double &time); /** * \brief Updates the odometry class with latest velocity command * \param linear Linear velocity [m/s] * \param angular Angular velocity [rad/s] * \param time Current time */ void updateOdom(double linear, double angular, const double &time); /** * \brief heading getter * \return heading [rad] */ double getHeading() const { return heading_; } /** * \brief x position getter * \return x position [m] */ double getX() const { return x_; } /** * \brief y position getter * \return y position [m] */ double getY() const { return y_; } /** * \brief linear velocity getter * \return linear velocity [m/s] */ double getLinear() const { return linear_; } /** * \brief angular velocity getter * \return angular velocity [rad/s] */ double getAngular() const { return angular_; } /** * \brief Sets the wheel parameters: radius and separation * \param wheel_separation Separation between left and right wheels [m] * \param left_wheel_radius Left wheel radius [m] * \param right_wheel_radius Right wheel radius [m] */ void setWheelParams(double wheel_separation, double left_wheel_radius, double right_wheel_radius); /** * \brief Sets encoder resolution for both wheels (same CPR) * \param ticks_per_revolution Ticks per wheel revolution (wheel side) */ void setEncoderParams(double ticks_per_revolution); /** * \brief Sets encoder resolution per wheel * \param left_ticks_per_revolution Left wheel ticks per revolution * \param right_ticks_per_revolution Right wheel ticks per revolution */ void setEncoderParams(double left_ticks_per_revolution, double right_ticks_per_revolution); /** * \brief Velocity rolling window size setter * \param velocity_rolling_window_size Velocity rolling window size */ void setVelocityRollingWindowSize(size_t velocity_rolling_window_size); private: /// Rolling mean accumulator and window: typedef bacc::accumulator_set > RollingMeanAcc; typedef bacc::tag::rolling_window RollingWindow; /** * \brief Integrates the velocities (linear and angular) using 2nd order Runge-Kutta * \param linear Linear displacement [m] * \param angular Angular displacement [rad] */ void integrateRungeKutta2(double linear, double angular); /** * \brief Integrates the velocities (linear and angular) using exact method * \param linear Linear displacement [m] * \param angular Angular displacement [rad] */ void integrateExact(double linear, double angular); /** * \brief Reset linear and angular accumulators */ void resetAccumulators(); /// Current timestamp: double timestamp_; /// Current pose: double x_; // [m] double y_; // [m] double heading_; // [rad] /// Current velocity: double linear_; // [m/s] double angular_; // [rad/s] /// Wheel kinematic parameters [m]: double wheel_separation_; double left_wheel_radius_; double right_wheel_radius_; /// Encoder resolution [ticks / wheel revolution]: double left_ticks_per_revolution_; double right_ticks_per_revolution_; /// Previous cumulative tick counts for delta computation: bool ticks_initialized_; std::int64_t left_ticks_prev_; std::int64_t right_ticks_prev_; /// Rolling mean accumulators for the linear and angular velocities: size_t velocity_rolling_window_size_; RollingMeanAcc linear_acc_; RollingMeanAcc angular_acc_; /// Integration function, used to integrate the odometry: IntegrationFunction integrate_fun_; }; }