Skip to content

Instantly share code, notes, and snippets.

@jones2126
Last active May 16, 2020 21:26
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jones2126/867e1e40ddd28c5fff01e09ba8e3da60 to your computer and use it in GitHub Desktop.
Save jones2126/867e1e40ddd28c5fff01e09ba8e3da60 to your computer and use it in GitHub Desktop.
Read an AMS AS5048B using an Arduino based microcontroller and print the RPM
/**
AS5048B_using_360_degrees_v2.cpp
The sensor will read and calculate the meters travelled at 10 Hz
m/s and RPM will be calculated each time a print is performed every 2 seconds (0.5 HZ) using meters travelled as input.
Therefore m/s and RPM will averaged for that 2 second period
*/
#include <Wire.h>
//unit consts
#define AS5048B_ANGLMSB_REG 0xFE //bits 0..7
#define AS5048B_RESOLUTION 16384.0 //14 bits
#define AS5048_ADDRESS 0x40
double position_now = 0;
float angle_now = 0;
float previous_angle = 0;
unsigned long prev_time_poll_AS5048B = 0;
float time_traveled = 0;
unsigned long prev_time_pub_speed = 0;
unsigned long prev_time_stamp_info = 0;
const int poll_AS5048B_Interval = 100; // 1000/10=100=10 Hz
const int infoInterval = 2000;
float ticks_traveled = 0;
float RPM = 0;
float revolutions = 0;
float mins_travelled = 0;
float meters_per_second = 0;
int moving_sw = 0;
float total_ticks = 0;
float meters_travelled = 0;
const float wheel_circumfrence = 1.59593;
uint16_t AMS_AS5048B_readReg16() { //reference: https://github.com/sosandroid/AMS_AS5048B
//16 bit value got from 2 8bits registers (7..0 MSB + 5..0 LSB) => 14 bits value
byte requestResult;
byte readArray[2];
uint16_t readValue = 0;
Wire.beginTransmission(AS5048_ADDRESS);
Wire.write(AS5048B_ANGLMSB_REG);
requestResult = Wire.endTransmission(false);
if (requestResult){
Serial.print("I2C error: ");
Serial.println(requestResult);
}
Wire.requestFrom(AS5048_ADDRESS, 2);
for (byte i=0; i < 2; i++) {
readArray[i] = Wire.read();
}
readValue = (((uint16_t) readArray[0]) << 6);
readValue += (readArray[1] & 0x3F);
return readValue;
}
void poll_AS5048B() {
previous_angle = angle_now; // time has passed and you are ready to take another position reading; store previous reading before you do.
position_now = AMS_AS5048B_readReg16(); // this will be a number between 0 and 16384
angle_now = (position_now / AS5048B_RESOLUTION) * 360.0; // convert the sensor reading to a float number between 0-360
ticks_traveled = abs(angle_now - previous_angle);
if (ticks_traveled > 180) {
ticks_traveled = 360 - ticks_traveled;
}
if (ticks_traveled < 1){ // if there is < 1 degree movement out of the 360 degree potential
moving_sw = 0;
RPM = 0;
}
else{
moving_sw = 1;
total_ticks = total_ticks + ticks_traveled; // total_ticks is used to publish the most recent m/s and RPM
}
if (moving_sw == 1 && angle_now > previous_angle) { // left side implementation - moving backward the angle value goes up (e.g. 360 -> 0, 10, 20)
meters_travelled = meters_travelled - ((ticks_traveled / 360) * wheel_circumfrence);
}
if (moving_sw == 1 && angle_now < previous_angle) { // left side implementation - moving forward the angle value goes down (e.g. 360 -> 359, 340, 270)
meters_travelled = meters_travelled + ((ticks_traveled / 360) * wheel_circumfrence);
}
}
void pub_info() {
time_traveled = millis() - prev_time_pub_speed;
prev_time_pub_speed = millis();
revolutions = total_ticks / 360; // determine what percentage of a full revolution has been completed in this time slice
time_traveled = time_traveled / 1000; // convert time travelled which is in millis to seconds
mins_travelled = time_traveled / 60; // calculate the number of minutes travelled based on the number of seconds travelled
RPM = (revolutions / mins_travelled); // Rpm = (revolutions / ((seconds/60))
meters_per_second = (RPM * wheel_circumfrence) / 60; // m/s = distance (meters) traveled during the time period * amount of time in seconds
Serial.print("previous_angle: ");
Serial.print(previous_angle);
Serial.print(", angle_now: ");
Serial.print(angle_now);
Serial.print(", total_ticks: ");
Serial.print(total_ticks);
Serial.print(", mins_travelled: ");
Serial.print(mins_travelled);
Serial.print(", revolutions: ");
Serial.print(revolutions);
Serial.print(", moving_sw: ");
Serial.print(moving_sw);
Serial.print(", RPM: ");
Serial.print(RPM);
Serial.print(", meters_per_second: ");
Serial.print(meters_per_second);
Serial.print(", meters_travelled: ");
Serial.println(meters_travelled);
total_ticks = 0;
}
void setup() {
Serial.begin(9600);
while (!Serial) ; //wait until Serial ready
Wire.begin();
// take a reading of the current position and save it both as current and previous so no distance is added to meters travelled.
position_now = AMS_AS5048B_readReg16();
angle_now = (position_now / AS5048B_RESOLUTION) * 360.0; // convert the sensor reading to a float number between 0-360
previous_angle = angle_now;
}
void loop() {
if (millis() - prev_time_poll_AS5048B >= poll_AS5048B_Interval) {
poll_AS5048B();
prev_time_poll_AS5048B = millis();
}
if (millis() - prev_time_stamp_info >= infoInterval) { // provide an informational message to ensure all is OK
pub_info();
prev_time_stamp_info = millis();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment