AS5600 Magnetic Encoder
The AS5600 magnetic encoder component provides the user a convenient way to measure
Raw count
Raw radians
Raw degrees
Accumulated count (since the component was created)
Accumulated radians (since the component was created)
Accumulated degrees (since the component was created)
Speed (rotations per minute / RPM)
It does so by spawning a task which periodically reads the magnetic encoder, updates the accumulator, and computes the velocity. The component can be configured to optionally filter the velocity.
The periodicity / update rate of the encoder can be configured at time of creation.
The encoder is designed to fulfill the needs of the BldcMotor API, to provide closed-loop motor control.
API Reference
Header File
Classes
-
class As5600 : public espp::BasePeripheral<>
Class for position and velocity measurement using a AS5600 magnetic encoder. This class starts its own measurement task at the specified frequency which reads the current angle, updates the accumulator, and filters / updates the velocity measurement. The datasheet for the AS5600 can be found here: https://ams.com/documents/20143/36005/AS5600_DS000365_5-00.pdf/649ee61c-8f9a-20df-9e10-43173a3eb323.
As5600 Example
// make the I2C that we'll use to communicate espp::I2c i2c({ .port = I2C_NUM_1, .sda_io_num = (gpio_num_t)CONFIG_EXAMPLE_I2C_SDA_GPIO, .scl_io_num = (gpio_num_t)CONFIG_EXAMPLE_I2C_SCL_GPIO, }); // make the velocity filter static constexpr float filter_cutoff_hz = 4.0f; static constexpr float encoder_update_period = 0.01f; // seconds espp::ButterworthFilter<2, espp::BiquadFilterDf2> filter( {.normalized_cutoff_frequency = 2.0f * filter_cutoff_hz * encoder_update_period}); // NOTE: we could just as easily disable filtering by simply returning the // raw value from this function auto filter_fn = [&filter](float raw) -> float { return filter.update(raw); }; // now make the as5600 which decodes the data espp::As5600 as5600( {.write_then_read = std::bind(&espp::I2c::write_read, &i2c, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4, std::placeholders::_5), .velocity_filter = filter_fn, .update_period = std::chrono::duration<float>(encoder_update_period), .log_level = espp::Logger::Verbosity::WARN}); // and finally, make the task to periodically poll the as5600 and print the // state. NOTE: the As5600 runs its own task to maintain state, so we're // just polling the current state. auto task_fn = [&quit_test, &as5600](std::mutex &m, std::condition_variable &cv) { static auto start = std::chrono::high_resolution_clock::now(); auto now = std::chrono::high_resolution_clock::now(); auto seconds = std::chrono::duration<float>(now - start).count(); auto count = as5600.get_count(); auto radians = as5600.get_radians(); auto degrees = as5600.get_degrees(); auto rpm = as5600.get_rpm(); fmt::print("{:.3f}, {}, {:.3f}, {:.3f}, {:.3f}\n", seconds, count, radians, degrees, rpm); quit_test = degrees <= -720.0f; // NOTE: sleeping in this way allows the sleep to exit early when the // task is being stopped / destroyed { std::unique_lock<std::mutex> lk(m); cv.wait_for(lk, 50ms); } // don't want to stop the task return false; }; auto task = espp::Task({.callback = task_fn, .task_config = { .name = "As5600 Task", .stack_size_bytes = 5 * 1024, }, .log_level = espp::Logger::Verbosity::WARN}); fmt::print("%time(s), count, radians, degrees, rpm\n"); task.start();
Note
There is an implicit assumption in this class regarding the maximum velocity it can measure (above which there will be aliasing). The fastest velocity it can measure will be (0.5f * update_period * 60.0f) which is half a rotation in one update period.
Note
The assumption above also affects the reliability of the accumulator, since it is based on accumulating position differences every update period.
Public Types
-
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 void initialize(std::error_code &ec)
Initialize the sensor.
- Parameters
ec – Error code to set if there is an error.
-
inline bool needs_zero_search() const
Return whether the sensor has found absolute 0 yet.
Note
The AS5600 (using I2C/SPI) does not need to search for absolute 0 and will always know it on startup. Therefore this function always returns false.
- Returns
True because the magnetic sensor (using I2C/SPI) does not need to sarch for 0.
-
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. It is not recommended to use this function, but is provided for edge use cases.
- Returns
Raw count value in the range [0, 16384] (0 to 360 degrees).
-
inline int get_accumulator() const
Return the accumulated count that the encoder has generated since it was initialized.
Note
This value is a raw counter value that can be +/-, meaning COUNTS_PER_REVOLUTION can be used to convert it to revolutions.
- Returns
Raw accumulator value.
-
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 bool probe (std::error_code &ec) requires(UseAddress)
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) requires(UseAddress)
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) requires(UseAddress)
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 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
See also
See also
- Returns
The verbosity level of the logger
-
inline void set_log_level(espp::Logger::Verbosity level)
Set the log level for the logger
See also
See also
- 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
See also
See also
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
See also
See also
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
See also
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 uint8_t DEFAULT_ADDRESS = (0b0110110)
I2C address of the AS5600.
-
static constexpr int COUNTS_PER_REVOLUTION = 16384
Int number of counts per revolution for the magnetic encoder.
-
static constexpr float COUNTS_PER_REVOLUTION_F = 16384.0f
Float number of counts per revolution for the magnetic encoder.
-
static constexpr float COUNTS_TO_RADIANS = 2.0f * 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.
-
struct Config
Configuration information for the As5600.
Public Members
-
uint8_t device_address = DEFAULT_ADDRESS
I2C address for this device.
-
BasePeripheral::write_then_read_fn write_then_read
Function to write then read from the device.
-
velocity_filter_fn velocity_filter = {nullptr}
Function to filter the veolcity.
Note
Will be called once every update_period seconds.
-
std::chrono::duration<float> update_period{.01f}
Update period (1/sample rate) in seconds. This determines the periodicity of the task which will read the position, update the accumulator, and update/filter velocity.
-
bool auto_init = {true}
Whether to automatically initialize the accumulator to the current position.
-
uint8_t device_address = DEFAULT_ADDRESS
-
typedef std::function<float(float raw)> velocity_filter_fn