该库目前支持以下类型的位置传感器:
- 编码器:
- 传感器计数
A ,B 并index 引导脉冲以估计位置。 - 例子:
- 磁性传感器:
- 使用精确的磁场测量来估计位置的传感器。
- 它们具有多种不同的通信标准,例如:SPI、SSI、I2C、ABI、UVW、PWM……
- 支持通信:(发布)
- SPI、I2C、模拟、PWM
- UVW(使用霍尔传感器接口)
- ABI(使用编码器接口)
- 例子:AS5048A,?AS5047U,?AS5600
- 霍尔传感器:
所有类型的传感器都以通用方式实现,以支持尽可能多的版本。
1. 实例化Encoder 类
要初始化编码器,您需要提供编码器A 和B 通道引脚、编码器PPR 和可选的index 引脚。
// Encoder(int encA, int encB , int cpr, int index)
// - encA, encB - encoder A and B pins
// - ppr - impulses per rotation (cpr=ppr*4)
// - index pin - (optional input)
Encoder encoder = Encoder(2, 3, 8192, A0);
?2. 配置
当 Encoder 类被实例化时,我们需要对其进行配置。我们可以配置的第一个功能是启用或禁用Quadrature 模式。如果编码器在正交模式下运行,PPR 则通过检测每个CHANGE 信号A 和B - ,其每次旋转的脉冲数 (?) 将增加四倍CPR = 4xPPR 。在某些应用中,当编码器PPR 很高时,Arduino 可能无法处理太多,因此最好不要使用Quadrature 模式。默认情况下,所有编码器都使用Quadrature 模式。如果您想启用或禁用此参数,请setup() 在init() 调用前在 Arduino函数中执行此操作:
// Quadrature mode enabling and disabling
// Quadrature::ON - CPR = 4xPPR - default
// Quadrature::OFF - CPR = PPR
encoder.quadrature = Quadrature::OFF;
CPR, PPR?!
PPR(每转脉冲数) - 这是编码器每转脉冲的物理数量。CPR(每转计数) - 这是编码器完全旋转后您将在计数器中拥有的数量。现在,根据您是否使用正交模式(计算脉冲的每个边沿)或不使用(仅计算上升沿),对于相同的 PPR,您将有不同的 CPR。对于正交模式,您将获得 CPR = 4xPPR,如果不使用正交模式,您将获得 CPR=PPR
此外,编码器还有一个更重要的参数,即上拉位置。许多编码器都需要上拉,如果您有一个需要上拉的编码器而您手上没有,您可以使用 Arduino 上拉。这是通过更改encoder.pullup 变量的值来设置的。默认值设置为,Pullup::USE_EXTERN 但如果您想将其更改为使用 MCU,请执行以下操作:
// check if you need internal pullups
// Pullup::USE_EXTERN - external pullup added - default
// Pullup::USE_INTERN - needs internal arduino pullup
encoder.pullup = Pullup::USE_INTERN;
Arduino 上拉 20kΩ
使用内部上拉时要小心,Arduino 具有 20kΩ 左右的相对较高值的上拉,这意味着您可能会在更高速度(短脉冲持续时间)下遇到一些问题。推荐的上拉值介于 1kΩ 和 5kΩ 之间。
3. 编码器中断设置
您可以通过两种方式使用 Simple FOC 库运行编码器。
软件中断
使用硬件外部中断通常会产生更好和更可靠的性能,但软件中断对于较低的速度会很好地工作。特别是在没有足够硬件中断引脚的板上,具有此功能基本上可以在这些板上启用 FOC。
硬件外部中断
Arduino的UNO有两个硬件外部中断引脚,为引脚2 和3 ,Arduino?Mega有6个中断引脚,引脚2 ,3 ,18 ,19 ,20 和2 而STM32板如Nucleo and Bluepill可以使用所有的数字引脚作为中断引脚,这使得实现更加容易。对于 Arduino Uno,编码器通道A 和B 必须准确连接到 pisn2 和3 ,以便使用硬件中断。
简单的 FOCEncoder 类已经实现了初始化以及编码器A 和B 通道回调。您需要做的就是定义两个函数doA() and?doB() ,编码器回调函数的缓冲函数encoder.handleA() 和encoder.handleB() 。
// interrupt routine initialization
void doA(){encoder.handleA();}
void doB(){encoder.handleB();}
并将这些函数提供给编码器中断 init 函数?encoder.enableInterrupts()
// enable encoder hardware interrupts
encoder.enableInterrupts(doA, doB)
您可以根据需要命名缓冲函数。将它们提供给encoder.enableInterrupts() 函数很重要。此过程是可扩展性和简单性之间的权衡。这允许您将多个编码器连接到同一个 MCU。您需要做的就是实例化新Encoder 类并创建新的缓冲区函数。例如:
// encoder 1
Encoder enc1 = Encoder(...);
void doA1(){enc1.handleA();}
void doB1(){enc1.handleB();}
// encoder 2
Encoder enc2 = Encoder(...);
void doA2(){enc2.handleA();}
void doB2(){enc2.handleB();}
void setup(){
...
enc1.init();
enc1.enableInterrupts(doA1,doB1);
enc2.init();
enc2.enableInterrupts(doA2,doB2);
...
}
索引引脚配置
为了有效地读取索引引脚,简单的 FOC 库使您能够使用与通道A 和B .?首先,您需要为Encoder 类提供索引引脚号:
Encoder encoder = Encoder(pinA, pinB, cpr, index_pin);
如果您使用的是 Arduino Mega 和类似的 Arduino 板,并且您有 2 个以上的硬件中断,则可以将索引引脚连接到硬件中断引脚(例如 Arduino Mega 引脚21 )。您的代码将如下所示:
Encoder encoder = Encoder(2,3,600,21);
// A and B interrupt routine
void doA(){encoder.handleA();}
void doB(){encoder.handleB();}
void doIndex(){encoder.handleIndex();}
void setup(){
...
encoder.enableInterrupts(doA,doB,doIndex);
...
}
该函数enableInterrupts 将为您处理所有初始化。
如果您使用 Arduino UNO 来运行此算法并且您没有足够的硬件中断引脚,您将需要使用软件中断库,例如PciManager 库。使用带索引的编码器的 Arduino UNO 代码可以是:
Encoder encoder = Encoder(2,3,600,A0);
// A and B interrupt routine
void doA(){encoder.handleA();}
void doB(){encoder.handleB();}
void doIndex(){encoder.handleIndex();}
// software interrupt listener for index pin
PciListenerImp listenerIndex(encoder.index_pin, doIndex);
void setup(){
...
// hardware interrupts for A and B
encoder.enableInterrupts(doA,doB);
// software interrupt for index
PciManager.registerListener(&listenerIndex);
...
}
如果您的应用程序使您用完硬件中断引脚A ,B 则可以对引脚执行相同的过程。软件中断非常强大,可以产生与硬件中断相当的结果,尤其是在您别无选择的情况下。index pin每转产生一次中断,因此并不重要,因此软件或硬件中断在性能方面不会发生太大变化。
为了更好地探索编码器功能与硬件和软件中断方法的区别,请查看示例encoder_example.ino 和encoder_software_interrupts_example.ino 。
软件引脚变化中断
如果您无法访问您的引脚2 和3 Arduino UNO,或者您想使用多个编码器,则必须使用软件中断方法。我建议使用PciManager 库。
在代码中使用这个库的步骤与硬件中断非常相似。该SimpleFOCEncoder 类仍然为您提供所有的回调A ,B 和Index 通道,但简单FOC库不会初始化中断你。
为了使用该PCIManager 库,您需要将其包含在您的代码中:
#include <PciManager.h>
#include <PciListenerImp.h>
下一步与之前相同,您只需初始化新Encoder 实例。
Encoder encoder = Encoder(10, 11, 8192);
// A and B interrupt callback buffers
void doA(){encoder.handleA();}
void doB(){encoder.handleB();}
然后你声明监听器PciListenerImp? :
// encoder interrupt init
PciListenerImp listenerA(encoder.pinA, doA);
PciListenerImp listenerB(encoder.pinB, doB);
最后,在运行之后,encoder.init() 您跳过 的调用encoder.enableInterrupts() 并调用PCIManager 库来注册所有编码器通道的中断。
// initialize encoder hardware
encoder.init();
// interrupt initialization
PciManager.registerListener(&listenerA);
PciManager.registerListener(&listenerB);
就是这样,非常简单。如果你想要多个编码器,你只需初始化新的类实例,创建新的A 和B 回调,初始化新的监听器。这是一个快速示例:
// encoder 1
Encoder enc1 = Encoder(9, 10, 8192);
void doA1(){enc1.handleA();}
void doB1(){enc1.handleB();}
PciListenerImp listA1(enc1.pinA, doA1);
PciListenerImp listB1(enc1.pinB, doB1);
// encoder 2
Encoder enc2 = Encoder(13, 12, 8192);
void doA2(){enc2.handleA();}
void doB2(){enc2.handleB();}
PciListenerImp listA2(enc2.pinA, doA2);
PciListenerImp listB2(enc2.pinB, doB2);
void setup(){
...
// encoder 1
enc1.init();
PciManager.registerListener(&listA1);
PciManager.registerListener(&listB1);
// encoder 2
enc2.init();
PciManager.registerListener(&listA2);
PciManager.registerListener(&listB2);
...
}
您可以查看HMBGC_example.ino 示例以查看此代码的实际效果。
索引引脚配置
在软件中断的情况下使能索引引脚非常简单。您只需要将它Encoder 作为附加参数提供给类初始化。
Encoder encoder = Encoder(pinA, pinB, cpr, index_pin);
之后,您创建与A andB 通道相同类型的回调缓冲函数,并使用PCIManager 工具初始化和注册index 通道的侦听器,如为A and?B 。这是一个快速示例:示例:
// class init
Encoder encoder = Encoder(9, 10, 8192,11);
void doA(){encoder.handleA();}
void doB(){encoder.handleB();}
void doIndex(){encoder.handleIndex();}
// listeners init
PciListenerImp listenerA(encoder.pinA, doA);
PciListenerImp listenerB(encoder.pinB, doB);
PciListenerImp listenerIndex(encoder.index_pin, doIndex);
void setup(){
...
// enable the hardware
enc1.init();
// enable interrupt
PciManager.registerListener(&listenerA);
PciManager.registerListener(&listenerB);
PciManager.registerListener(&listenerIndex);
...
}
?4. 实时使用编码器
有两种方法可以使用在这个库中实现的编码器:
- 作为 FOC 算法的电机位置传感器
- 作为独立的位置传感器
FOC算法的位置传感器
要将编码器传感器与在此库中实现的 foc 算法一起使用,在初始化encoder.init() 它并启用中断后,encoder.enableInterrupts(...) 您只需通过执行以下命令将其链接到 BLDC 电机:
motor.linkSensor(&encoder);
独立传感器
要在任何给定时间获取编码器角度和速度,您可以使用公共方法:
class Encoder{
public:
// shaft velocity getter
float getVelocity();
// shaft angle getter
float getAngle();
}
#include <SimpleFOC.h>
Encoder encoder = Encoder(2, 3, 8192);
// interrupt routine initialization
void doA(){encoder.handleA();}
void doB(){encoder.handleB();}
void setup() {
// monitoring port
Serial.begin(115200);
// enable/disable quadrature mode
encoder.quadrature = Quadrature::ON;
// check if you need internal pullups
encoder.pullup = Pullup::USE_EXTERN;
// initialize encoder hardware
encoder.init();
// hardware interrupt enable
encoder.enableInterrupts(doA, doB);
Serial.println("Encoder ready");
_delay(1000);
}
void loop() {
// display the angle and the angular velocity to the terminal
Serial.print(encoder.getAngle());
Serial.print("\t");
Serial.println(encoder.getVelocity());
}
|