AS5600 agregar RPM al codigo

Hola, foro en Español, hace tiempo que quiero usar el AS5600, para convertir un motor a pasos en servomotor, (a bajo costo), y la información que recoge el sensor AS5600 via I2C sea el sistema de control del nema, tuve problemas para ajustar el imán, diametralmente imantado, en el primer motor me quedo casi 0.75 m.m. desfasado y si da incongruencias el monitor Serial, el otro motor solo 0.12m.m. de desfase, en relación al eje del motor, y si da datos correctos. Proporciona información del angulo, angulo maximo, +/- y numero de rotaciones +/- yo quiero que indique las revoluciones por minuto también.

//https://curiousscientist.tech/blog/as5600-magnetic-position-encoder   //codigo

#include <Wire.h> //This is for i2C
//#include <SSD1306Ascii.h> //i2C OLED
//#include <SSD1306AsciiWire.h> //i2C OLED

// i2C OLED
#define I2C_ADDRESS 0x36





//---------------------------------------------------------------------------
//Magnetic sensor things
int magnetStatus = 0; //value of the status register (MD, ML, MH)

int lowbyte; //raw angle 7:0
word highbyte; //raw angle 7:0 and 11:8
int rawAngle; //final raw angle 
float degAngle; //raw angle in degrees (360/4096 * [value between 0-4095])

int quadrantNumber, previousquadrantNumber; //quadrant IDs
float numberofTurns = 0; //number of turns
float correctedAngle = 0; //tared angle - based on the startup value
float startAngle = 0; //starting angle
float totalAngle = 0; //total absolute angular displacement
float previoustotalAngle = 0; //for the display printing

void setup()
{
  Serial.begin(115200); //start serial - tip: don't use serial if you don't need it (speed considerations)
  Wire.begin(); //start i2C  
 // Wire.setClock(800000L); //fast clock

  checkMagnetPresence(); //check the magnet (blocks until magnet is found)

  ReadRawAngle(); //make a reading so the degAngle gets updated
  startAngle = degAngle; //update startAngle with degAngle - for taring
}

void loop()
{    
    ReadRawAngle(); //ask the value from the sensor
    correctAngle(); //tare the value
    checkQuadrant(); //check quadrant, check rotations, check absolute angular position
//    refreshDisplay();
    //delay(100); //wait a little - adjust it for "better resolution"

}

void ReadRawAngle()
{ 
  //7:0 - bits
  Wire.beginTransmission(0x36); //connect to the sensor
  Wire.write(0x0D); //figure 21 - register map: Raw angle (7:0)
  Wire.endTransmission(); //end transmission
  Wire.requestFrom(0x36, 1); //request from the sensor
  
  while(Wire.available() == 0); //wait until it becomes available 
  lowbyte = Wire.read(); //Reading the data after the request
 
  //11:8 - 4 bits
  Wire.beginTransmission(0x36);
  Wire.write(0x0C); //figure 21 - register map: Raw angle (11:8)
  Wire.endTransmission();
  Wire.requestFrom(0x36, 1);
  
  while(Wire.available() == 0);  
  highbyte = Wire.read();
  
  //4 bits have to be shifted to its proper place as we want to build a 12-bit number
  highbyte = highbyte << 8; //shifting to left
  //What is happening here is the following: The variable is being shifted by 8 bits to the left:
  //Initial value: 00000000|00001111 (word = 16 bits or 2 bytes)
  //Left shifting by eight bits: 00001111|00000000 so, the high byte is filled in
  
  //Finally, we combine (bitwise OR) the two numbers:
  //High: 00001111|00000000
  //Low:  00000000|00001111
  //      -----------------
  //H|L:  00001111|00001111
  rawAngle = highbyte | lowbyte; //int is 16 bits (as well as the word)

  //We need to calculate the angle:
  // 12 bit -> 4096 different levels: 360° is divided into 4096 equal parts:
  //360/4096 = 0.087890625
  //Multiply the output of the encoder with 0.087890625
  degAngle = rawAngle * 0.087890625; 
  
  Serial.print("Deg angle: ");
  Serial.println(degAngle, 2); //absolute position of the encoder within the 0-360 circle
  
}

void correctAngle()
{
  //recalculate angle
  correctedAngle = degAngle - startAngle; //this tares the position

  if(correctedAngle < 0) //if the calculated angle is negative, we need to "normalize" it
  {
  correctedAngle = correctedAngle + 360; //correction for negative numbers (i.e. -15 becomes +345)
  }
  else
  {
    //do nothing
  }
  Serial.print("Corrected angle: ");
  Serial.println(correctedAngle, 2); //print the corrected/tared angle  
}

void checkQuadrant()
{
  /*
  //Quadrants:
  4  |  1
  ---|---
  3  |  2
  */

  //Quadrant 1
  if(correctedAngle >= 0 && correctedAngle <=90)
  {
    quadrantNumber = 1;
  }

  //Quadrant 2
  if(correctedAngle > 90 && correctedAngle <=180)
  {
    quadrantNumber = 2;
  }

  //Quadrant 3
  if(correctedAngle > 180 && correctedAngle <=270)
  {
    quadrantNumber = 3;
  }

  //Quadrant 4
  if(correctedAngle > 270 && correctedAngle <360)
  {
    quadrantNumber = 4;
  }
  Serial.print("Quadrant: ");
  Serial.println(quadrantNumber); //print our position "quadrant-wise"

  if(quadrantNumber != previousquadrantNumber) //if we changed quadrant
  {
    if(quadrantNumber == 1 && previousquadrantNumber == 4)
    {
      numberofTurns++; // 4 --> 1 transition: CW rotation
    }

    if(quadrantNumber == 4 && previousquadrantNumber == 1)
    {
      numberofTurns--; // 1 --> 4 transition: CCW rotation
    }
    //this could be done between every quadrants so one can count every 1/4th of transition

    previousquadrantNumber = quadrantNumber;  //update to the current quadrant
  
  }  
  Serial.print("Turns: ");
  Serial.println(numberofTurns,0); //number of turns in absolute terms (can be negative which indicates CCW turns)  

  //after we have the corrected angle and the turns, we can calculate the total absolute position
  totalAngle = (numberofTurns*360) + correctedAngle; //number of turns (+/-) plus the actual angle within the 0-360 range
  Serial.print("Total angle: ");
  Serial.println(totalAngle, 2); //absolute position of the motor expressed in degree angles, 2 digits
  delay(200);
}

void checkMagnetPresence()
{  
  while((magnetStatus & 32) != 32) //while the magnet is not adjusted to the proper distance - 32: MD = 1
  {
    magnetStatus = 0; //reset reading

    Wire.beginTransmission(0x36); //connect to the sensor
    Wire.write(0x0B); //figure 21 - register map: Status: MD ML MH
    Wire.endTransmission(); //end transmission
    Wire.requestFrom(0x36, 1); //request from the sensor

    while(Wire.available() == 0); //wait until it becomes available 
    magnetStatus = Wire.read(); //Reading the data after the request

    Serial.print("Magnet status: ");
    Serial.println(magnetStatus, BIN); //print it in binary so you can compare it to the table (fig 21)   
       
  }     
}

Saludos.

Nota este es el modelo de modulo que estaré usando para este proyecto.

Hola foro Español. esto es un iman diametral mente magnetizado.

Debe adherirse al eje del motor por la parte trasera.

Saludos.

Que pasó con esto?

Hola @Surbyte, ya tengo un código que lee las RPM ahora necesito modificar lo, para que funcione con arduino, y lcd grafic, esta echo par funcionar con stm32 y pantalla oled, en este y en anterior no usa la libreria Arduino AS5600, espero poder modificar lo, para usar la libreria AS5600 y sintetizar lo mas posible el código, post #1 en mil rotaciones no pierde ni un grado pero si cambio la dirección del giro pierde de 0.05 grados hasta 3.00 grados, creo que si usase esos datos en una impresora 3D resultaria inservible la pieza, no se si sea por el desface del imán, a pesar de que el desfase es la mitad de la tolerancia permitida o si el problema esta en el código, o por adherir el imán directa mente a la flecha del motor, tal vez deba llevar algún aislante magnético, entre la flecha y el imán alguna sugerencia.

#include <SoftwareSerial.h>
#include<Wire.h>
#include <U8g2lib.h>
#include <U8x8lib.h>
#include <U8glib.h>
#include <SPI.h>
#include "TimerOne.h"
#include <Wire.h>
#include <AccelStepper.h>
AccelStepper stepper(1, 10, 11);// pulses/steps 10; Direction 11
volatile float stepperMotorSpeed = 0;
const int RotaryCLK = 3;
const int RotaryDT = 4;
const int RotarySW = 5;
bool rotaryRotated = false;
int RotaryButtonValue = 0;
float RotaryTime;
volatile int rotaryValue = 0;
int previousRotaryValue = -1;
int CLKNow;
int CLKPrevious;
int DTNow;
int DTPrevious;
int magnetStatus = 0;
int lowbyte;
word highbyte;
int rawAngle;
float degAngle;
int quadrantNumber, previousquadrantNumber;
float numberofTurns = 0;
float correctedAngle = 0;
float startAngle = 0;
float totalAngle = 0;
float previoustotalAngle = -1;
float recentTotalAngle = 0;
float rpmValue = 0;
float stepRateFromRPM = 0;
float calculatedRPM = 0;
float stepperPosition = 0;
float stepperPreviousPosition = 0;
float rpmInterval = 200;
float rpmTimer = 0;
float timerdiff = 0;

U8G2_ST7920_128X64_1_HW_SPI u8g2(U8G2_R0, /* CS=*/ 10, /* reset=*/ 8);

void setup()
{
  Serial.begin(9600);
  checkMagnetPresence();
  ReadRawAngle();
  startAngle = degAngle;
  pinMode(RotaryCLK, INPUT_PULLUP);
  pinMode(RotaryDT, INPUT_PULLUP);
  pinMode(RotarySW, INPUT_PULLUP);
  attachInterrupt(digitalPinToInterrupt(RotaryCLK), RotaryEncoder, CHANGE);
  CLKPrevious = digitalRead(RotaryCLK);
  DTPrevious = digitalRead(RotaryDT);
  stepper.setSpeed(0);
  stepper.setMaxSpeed(10000);
  stepper.setAcceleration(5000);  
  u8g2.begin();
  u8g2.enableUTF8Print();
  u8g2.setFont(u8g2_font_t0_11_tr);
  u8g2.setColorIndex(1);
}
void callback()
{
  stepper.runSpeed();
}
void loop()
{
   u8g2.firstPage();
   do {
  ReadRawAngle();
  correctAngle();
  checkQuadrant();
  calculateRPM();
  CheckRotaryButton();
  stepper.setSpeed(stepperMotorSpeed);
  } 
  while ( u8g2.nextPage() );
}
void ReadRawAngle()
{
  u8g2.firstPage();
  do {
    Wire.beginTransmission(0x36);
    Wire.write(0x0D);
    Wire.endTransmission();
    Wire.requestFrom(0x36, 1);
    while (Wire.available() == 0);
    lowbyte = Wire.read();
    Wire.beginTransmission(0x36);
    Wire.write(0x0C);
    Wire.endTransmission();
    Wire.requestFrom(0x36, 1);
    while (Wire.available() == 0);
    highbyte = Wire.read();
    highbyte = highbyte << 8;
    rawAngle = highbyte | lowbyte;
    degAngle = rawAngle * 0.087890625;
    Serial.print("Deg angle: ");
    Serial.println(degAngle, 3);

    u8g2.clearBuffer();
    u8g2.drawStr( 40, 13, "DEg angle:");
    u8g2.setCursor(20, 24 );
    u8g2.print( degAngle, 3);
  } while ( u8g2.nextPage() );
}
void correctAngle()
{
  u8g2.firstPage();
  do {
    correctedAngle = degAngle - startAngle;
    if (correctedAngle < 0)
    {
      correctedAngle = correctedAngle + 360;
    }
    else
    {
    }
    Serial.print("Corrected angle: ");
    Serial.println(correctedAngle, 2);
    u8g2.clearBuffer();
    u8g2.drawStr( 40, 13, "Cerret angle");
    u8g2.setCursor(20, 24 );
    u8g2.print(correctedAngle, 3);
  } while ( u8g2.nextPage() );

}
void checkQuadrant()
{
  if (correctedAngle >= 0 && correctedAngle <= 90)
  {
    quadrantNumber = 1;
  }
  if (correctedAngle > 90 && correctedAngle <= 180)
  {
    quadrantNumber = 2;
  }
  if (correctedAngle > 180 && correctedAngle <= 270)
  {
    quadrantNumber = 3;
  }
  if (correctedAngle > 270 && correctedAngle < 360)
  {
    quadrantNumber = 4;
  }
  Serial.print("Quadrant: ");
  Serial.println(quadrantNumber);
  u8g2.clearBuffer();
  u8g2.drawStr( 40, 13, "Quadrant");
  u8g2.setCursor(20, 24 );
  u8g2.print(quadrantNumber);
  if (quadrantNumber != previousquadrantNumber)
  {
    if (quadrantNumber == 1 && previousquadrantNumber == 4)
    {
      numberofTurns++; // 4 --> 1 transition: CW rotation
    }
    if (quadrantNumber == 4 && previousquadrantNumber == 1)
    {
      numberofTurns--; // 1 --> 4 transition: CCW rotation
    }
    previousquadrantNumber = quadrantNumber;
  }
  Serial.print("Turns: ");
  Serial.println(numberofTurns, 0);
  u8g2.clearBuffer();
  u8g2.drawStr( 40, 13, "Turns");
  u8g2.setCursor(20, 24 );
  u8g2.print(numberofTurns);
  totalAngle = (numberofTurns * 360) + correctedAngle;
  Serial.print("Total angle: ");
  Serial.println(totalAngle, 3);
  u8g2.drawStr( 40, 13, "Total angle");
  u8g2.setCursor(20, 24 );
  u8g2.print(totalAngle, 3);
}
void checkMagnetPresence()
{
  while ((magnetStatus & 32) != 32)
  {
    magnetStatus = 0;
    Wire.beginTransmission(0x36);
    Wire.write(0x0B);
    Wire.endTransmission();
    Wire.requestFrom(0x36, 1);
    while (Wire.available() == 0);
    magnetStatus = Wire.read();
    Serial.print("Magnet status: ");
    Serial.println(magnetStatus, BIN);
    u8g2.clearBuffer();
    u8g2.drawStr( 40, 13, "Magnet status:");
    u8g2.setCursor(20, 24 );
    u8g2.print(magnetStatus, BIN);
  }
  Serial.println("Magnet found!");
  delay(1000);
}
void calculateRPM()
{
  timerdiff = millis() - rpmTimer;
  if (timerdiff > rpmInterval)
  {
    rpmValue = (60000.0 / rpmInterval) * (totalAngle - recentTotalAngle) / 360.0;
    rpmValue = (60000.0 / timerdiff) * (totalAngle - recentTotalAngle) / 360.0;
    stepRateFromRPM = rpmValue * 800.0 / 60.0;
    recentTotalAngle = totalAngle;
    rpmTimer = millis();
  }
}
void refreshDisplay()
{
  {
    stepperPosition = stepper.currentPosition();
    if (totalAngle != previoustotalAngle || rotaryRotated == true || stepperPreviousPosition != stepperPosition)
    {
      rotaryRotated = false;
      stepperPreviousPosition = stepperPosition;
      previoustotalAngle = totalAngle;
    }
  }
  {
  }
}
void RotaryEncoder()
{
  CLKNow = digitalRead(RotaryCLK);
  if (CLKNow != CLKPrevious  && CLKNow == 1)
  {
    if (digitalRead(RotaryDT) != CLKNow)
    {
      stepperMotorSpeed = stepperMotorSpeed - 10;
    }
    else
    {
      stepperMotorSpeed = stepperMotorSpeed + 10;
    }
    calculatedRPM = stepperMotorSpeed * 60.0 / 800.0;
    rotaryRotated = true;
  }
  CLKPrevious = CLKNow;
}
void CheckRotaryButton()
{
  RotaryButtonValue = digitalRead(RotarySW);
  if (RotaryButtonValue == 0)
  {
    if (millis() - RotaryTime > 1000)
    {
      stepperPosition = 0;
      stepper.setCurrentPosition(0);
      stepperMotorSpeed = 0;
      calculatedRPM = 0;
      RotaryTime = millis();
    }
  }
}

Nota: disculpen la tardanza.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.