Arduino SimpleFOC库-006-位置传感器
时间:2022-08-21 03:30:00
该库目前支持以下类型的位置传感器:
- 编码器:
- 传感器计数
A
,B
并index
引导脉冲估计位置。 - 例子:
- 光学:10000欧姆龙P
- 电容:AMT103 CUI
- 磁性:AS5047U- 使用 ABI
- 传感器计数
- 磁传感器:
- 用精确的磁场测量来估计位置的传感器。
- 它们有多种不同的通信标准,如:SPI、SSI、I2C、ABI、UVW、PWM……
- 支持通信:(发布)
- SPI、I2C、模拟、PWM
- UVW(使用霍尔传感器接口)
- ABI(使用编码器接口)
- 例子:AS5048A,AS5047U,AS5600
- 用精确的磁场测量来估计位置的传感器。
- 霍尔传感器:
- 传感器通过读取转子上的磁铁位置来估计转子位置。
- 示例:49E 霍尔探测器,105 霍尔传感器
所有类型的传感器都是通用的,以支持尽可能多的版本。
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 库运行编码器。
- 使用硬件外部中断
- Arduino UNO(Atmega328) 引脚
2
和3
- STM32板任何引脚
- ESP32 任意引脚
- Arduino UNO(Atmega328) 引脚
- 通过使用PciManager库使用软件引脚变化中断
- 仅适用于 Arduino 设备(Atmga328 和 Atmage2560)
软件中断
硬件外部中断的使用通常会产生更好、更可靠的性能,但软件中断将以较低的速度工作。特别是在硬件中断引脚不够的板上,这个功能基本上可以在这些板上使用 FOC。
硬件外部中断
Arduino的UNO两个硬件外部中断引脚2
和3
,ArduinoMega有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
#include
下一步与之前相同,您只需初始化新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
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());
}