Last active
May 16, 2020 21:26
-
-
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
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
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