Magnetic Encoder Base

The MagneticEncoderBase is the shared CRTP base class for the magnetic angle encoders (AS5600 Magnetic Encoder and MT6701 Magnetic Encoder). It holds all of the machinery common to those encoders:

  • the periodic update loop (raw-count accumulation + velocity estimation),

  • the position / velocity accessors (count, radians, degrees, accumulator, RPM),

  • and the periodic driver that calls update() at the configured rate.

The concrete encoder supplies exactly one thing - a read() that refreshes the raw count from the sensor - which the base invokes through static (CRTP) dispatch, so there is no virtual-call overhead even when the update loop runs at very high frequency (e.g. 1-2 kHz).

The periodic driver is selected at compile time (per encoder, via KConfig / menuconfig):

  • a espp::HighResolutionTimer (default), which has microsecond resolution and is the right choice for sub-millisecond update periods, or

  • an espp::Timer, which schedules against an absolute wake-up time (drift-free and in phase - important for stable velocity / accumulator state) but is limited to the FreeRTOS tick resolution.

API Reference

Header File

Classes

template<typename Derived, bool UseHighResTimer, int CountsPerRevolution, int MinDiff = 2, std::integral RegisterAddressType = std::uint8_t, bool UseAddress = true>
class MagneticEncoderBase : public espp::BasePeripheral<std::uint8_t, true>

CRTP base class for magnetic angle encoders (e.g. As5600, Mt6701).

This class holds all of the machinery shared by the magnetic encoders: the periodic update loop (raw-count accumulation + velocity estimation), the position / velocity accessors, and the periodic driver that calls update() at the configured rate. The concrete encoder supplies exactly one thing - a `read(std::error_code&)` that refreshes `count_` from the sensor (and any device-specific state) - which the base invokes through static (CRTP) dispatch, so there is no virtual-call overhead even when the update loop runs at very high frequency (e.g. 1-2 kHz).

The periodic driver is selected at compile time via UseHighResTimer:

  • `true` (default in the encoders’ Kconfig): an esp_timer-backed espp::HighResolutionTimer, which has microsecond resolution and is the right choice for sub-millisecond update periods.

  • `false`: an espp::Timer, which schedules against an absolute wake-up time (the k-th callback targets `start + k * period`) so it is periodic and in phase - critical for stable velocity / accumulator state - but is limited to the FreeRTOS tick resolution.

Note

There is an implicit assumption regarding the maximum velocity that can be measured (above which there will be aliasing). The fastest velocity that can be measured is `0.5 / update_period * 60` RPM, i.e. half a rotation in one update period. This also bounds the reliability of the accumulator, since it accumulates position differences every update.

Warning

You should not call update() yourself if you have configured the encoder to run its own timer (run_task = true) or if you have called start().

Template Parameters:
  • Derived – The concrete encoder class (CRTP). Must provide `void read(std::error_code&)` which updates `count_`.

  • UseHighResTimer – If true, drive updates with HighResolutionTimer; if false, drive with espp::Timer.

  • CountsPerRevolution – Number of raw counts per mechanical revolution (e.g. 4096 for the 12-bit As5600, 16384 for the 14-bit Mt6701).

  • MinDiff – Minimum count difference required to update the velocity estimate; smaller differences are treated as zero velocity to reject noise / jitter.

  • RegisterAddressType – Register address type for BasePeripheral.

  • UseAddress – Whether the peripheral is addressed (I2C) or not (SSI).

Subclassed by espp::Mt6701< Interface >

Public Types

using TimerType = std::conditional_t<UseHighResTimer, espp::HighResolutionTimer, espp::Timer>

The periodic driver type selected by UseHighResTimer.

typedef std::function<float(float raw)> velocity_filter_fn

Filter the input raw velocity and return it.

Param raw:

Most recent raw velocity measured.

Return:

Filtered velocity.

typedef std::function<bool(uint8_t)> probe_fn

Function to probe the peripheral

Param address:

The address to probe

Return:

True if the peripheral is found at the given address

Public Functions

inline bool needs_zero_search() const

Return whether the sensor needs to search for absolute 0 on startup.

Note

Magnetic angle encoders (using I2C / SPI) always know their absolute angle on startup, so this always returns false.

Returns:

False.

inline int get_count() const

Get the most recently updated raw count value from the encoder.

Note

This value always represents the angle of the encoder modulo one rotation, meaning it only represents the range 0 to 360 degrees.

Returns:

Raw count value in the range [0, COUNTS_PER_REVOLUTION).

inline int64_t get_accumulator() const

Return the accumulated count generated since initialization.

Note

This value is a raw counter value that can be +/-; divide by COUNTS_PER_REVOLUTION to convert it to revolutions. It is stored as a 64-bit value so it does not overflow during long, continuous rotation.

Returns:

Raw accumulator value.

inline void reset_accumulator()

Reset the accumulator to zero.

inline float get_mechanical_radians() const

Return the mechanical / shaft angle of the encoder, in radians, within the range [0, 2pi].

Returns:

Angle in radians of the encoder within the range [0, 2pi].

inline float get_mechanical_degrees() const

Return the mechanical / shaft angle of the encoder, in degrees, within the range [0, 360].

Returns:

Angle in degrees of the encoder within the range [0, 360].

inline float get_radians() const

Return the accumulated position of the encoder, in radians.

Note

This can be any value, it is not restricted to [-2pi, 2pi].

Returns:

Position in radians of the encoder.

inline float get_degrees() const

Return the accumulated position of the encoder, in degrees.

Note

This can be any value, it is not restricted to [-360, 360].

Returns:

Position in degrees of the encoder.

inline float get_rpm() const

Return the filtered velocity of the encoder, in RPM.

Returns:

Filtered velocity (revolutions / minute, RPM).

inline void initialize(std::error_code &ec)

Initialize the accumulator to the current position and start the update timer.

Parameters:

ec – Error code to set if there is an error.

inline void initialize(bool run_task, std::error_code &ec)

Initialize the accumulator to the current position and start the update timer, if desired.

Note

If you do not start the timer, you must call update() manually.

Parameters:
  • run_task – Whether to start the update timer.

  • ec – Error code to set if there is an error.

inline void update(std::error_code &ec)

Update the state of the encoder by reading the latest data from the encoder and updating the associated state.

Note

You should not call this function if you have started the encoder’s update timer (e.g. run_task = true, or you called start()).

Parameters:

ec – Error code to set if there is an error.

inline bool start()

Start the update timer.

Note

This will start the timer that calls update() at the update_period.

Note

This is only useful if you previously stopped the timer or if you initialized with run_task = false.

Returns:

True if the timer was started successfully, false otherwise.

inline void stop()

Stop the update timer.

Note

This will stop the timer that calls update() at the update_period.

Note

After stopping, you can manually call update() or restart with start().

inline bool probe(std::error_code &ec) const

Probe the peripheral

Note

This function is thread safe

Note

If the probe function is not set, this function will return false and set the error code to operation_not_supported

Note

This function is only available if UseAddress is true

Parameters:

ec – The error code to set if there is an error

Returns:

True if the peripheral is found

inline void set_address(uint8_t address)

Set the address of the peripheral

Note

This function is thread safe

Note

This function is only available if UseAddress is true

Parameters:

address – The address of the peripheral

inline void set_probe(const probe_fn &probe)

Set the probe function

Note

This function is thread safe

Note

This should rarely be used, as the probe function is usually set in the constructor. If you need to change the probe function, consider using the set_config function instead.

Note

This function is only available if UseAddress is true

Parameters:

probe – The probe function

inline void set_write(const write_fn &write)

Set the write function

Note

This function is thread safe

Note

This should rarely be used, as the write function is usually set in the constructor. If you need to change the write function, consider using the set_config function instead.

Parameters:

write – The write function

inline void set_read(const read_fn &read)

Set the read function

Note

This function is thread safe

Note

This should rarely be used, as the read function is usually set in the constructor. If you need to change the read function, consider using the set_config function instead.

Parameters:

read – The read function

inline void set_read_register(const read_register_fn &read_register)

Set the read register function

Note

This function is thread safe

Note

This should rarely be used, as the read register function is usually set in the constructor. If you need to change the read register function, consider using the set_config function instead.

Parameters:

read_register – The read register function

inline void set_write_then_read(const write_then_read_fn &write_then_read)

Set the write then read function

Note

This function is thread safe

Note

This should rarely be used, as the write then read function is usually set in the constructor. If you need to change the write then

Parameters:

write_then_read – The write then read function

inline void set_separate_write_then_read_delay(const std::chrono::milliseconds &delay)

Set the delay between the write and read operations in write_then_read

Note

This function is thread safe

Note

This should rarely be used, as the delay is usually set in the constructor. If you need to change the delay, consider using the set_config function instead.

Note

This delay is only used if the write_then_read function is not set to a custom function and the write and read functions are separate functions.

Parameters:

delay – The delay between the write and read operations in write_then_read

inline void set_config(const Config &config)

Set the configuration for the peripheral

Note

This function is thread safe

Note

The configuration should normally be set in the constructor, but this function can be used to change the configuration after the peripheral has been created - for instance if the peripheral could be found on different communications buses.

Parameters:

config – The configuration for the peripheral

inline void set_config(Config &&config)

Set the configuration for the peripheral

Note

This function is thread safe

Note

The configuration should normally be set in the constructor, but this function can be used to change the configuration after the peripheral has been created - for instance if the peripheral could be found on different communications buses.

Parameters:

config – The configuration for the peripheral

inline const Config &config() const

Get the configuration for the peripheral

Returns:

The configuration for the peripheral

inline uint8_t address() const

Get the address of the peripheral

Returns:

The address of the peripheral

inline const std::string &get_name() const

Get the name of the component

Note

This is the tag of the logger

Returns:

A const reference to the name of the component

inline void set_log_tag(const std::string_view &tag)

Set the tag for the logger

Parameters:

tag – The tag to use for the logger

inline espp::Logger::Verbosity get_log_level() const

Get the log level for the logger

Returns:

The verbosity level of the logger

inline void set_log_level(espp::Logger::Verbosity level)

Set the log level for the logger

Parameters:

level – The verbosity level to use for the logger

inline void set_log_verbosity(espp::Logger::Verbosity level)

Set the log verbosity for the logger

See also

set_log_level

Note

This is a convenience method that calls set_log_level

Parameters:

level – The verbosity level to use for the logger

inline espp::Logger::Verbosity get_log_verbosity() const

Get the log verbosity for the logger

See also

get_log_level

Note

This is a convenience method that calls get_log_level

Returns:

The verbosity level of the logger

inline void set_log_rate_limit(std::chrono::duration<float> rate_limit)

Set the rate limit for the logger

Note

Only calls to the logger that have _rate_limit suffix will be rate limited

Parameters:

rate_limit – The rate limit to use for the logger

Public Static Attributes

static constexpr int COUNTS_PER_REVOLUTION = CountsPerRevolution

Int number of counts per revolution for the magnetic encoder.

static constexpr float COUNTS_PER_REVOLUTION_F = (float)CountsPerRevolution

Float number of counts per revolution.

static constexpr float COUNTS_TO_RADIANS = 2.0f * (float)(M_PI) / COUNTS_PER_REVOLUTION_F

Conversion factor to convert from count value to radians.

static constexpr float COUNTS_TO_DEGREES = 360.0f / COUNTS_PER_REVOLUTION_F

Conversion factor to convert from count value to degrees.

static constexpr float SECONDS_PER_MINUTE = 60.0f

Conversion factor to convert from seconds to minutes.

static constexpr int MIN_DIFF = MinDiff

Minimum difference for velocity calculation.