Link

实现自定义传感器

GenericSensor简易FOC 的一个新类,它简化了新传感器的实现过程。通过这个类,你可以在一个 Arduino 文件中添加自定义传感器并将其与电机连接起来。

步骤 1. 实现读取传感器的函数

基本上,你在 Arduino 代码中需要做的就是实现一个读取传感器并返回 0 到 2π 之间弧度角度的函数:

float readMySensorCallback(){
 // read my sensor
 // return the angle value in radians in between 0 and 2PI
 return ...;
}

此外,你还可以选择性地实现一个初始化传感器的函数

void initMySensorCallback(){
  // do the init
}

步骤 2. 实例化 GenericSensor

要初始化传感器类,你需要向它提供指向传感器读取函数的指针,以及可选的指向传感器初始化函数的指针。

// GenericSensor class constructor
//  - readCallback pointer to the function reading the sensor angle
//  - initCallback pointer to the function initialising the sensor (optional)
GenericSensor sensor = GenericSensor(readMySensorCallback, initMySensorCallback);

然后,你将能够使用电机实例访问电机的角度和速度:

motor.shaft_angle; // motor angle
motor.shaft_velocity; // motor velocity

或者通过传感器实例:

sensor.getAngle(); // motor angle
sensor.getVelocity(); // motor velocity

步骤 3. 在实时环境中使用你的传感器

有两种方式可以使用本库中实现的传感器:

  • 作为 FOC 算法的电机位置传感器
  • 作为独立的位置传感器

独立传感器

你可以将传感器用作独立传感器。要在任何给定时间获取传感器的角度和速度,可以使用以下公共方法:

class GenericSensor{
 public:
    // shaft velocity getter
    float getVelocity();
	  // shaft angle getter
    float getAngle();
}

多次调用 getVelocity

当调用 getVelocity 时,只有当前一次调用以来的经过时间长于变量 min_elapsed_time(默认 100 微秒)时,它才会计算速度。如果自上次调用以来的经过时间短于 min_elapsed_time,该函数将返回之前计算的值。如有必要,可以轻松更改变量 min_elapsed_time

sensor.min_elapsed_time = 0.0001; // 100us by default

以下是一个简单示例:

#include <SimpleFOC.h>

float readMySensorCallback(){
 // read my sensor
 // return the angle value in radians in between 0 and 2PI
 return ...;
}

void initMySensorCallback(){
  // do the init
}

// create the sensor
GenericSensor sensor = GenericSensor(readMySensorCallback, initMySensorCallback);

void setup() {
  // monitoring port
  Serial.begin(115200);

  // initialize sensor hardware
  sensor.init();

  Serial.println("My sensor ready");
  _delay(1000);
}

void loop() {
  // IMPORTANT - call as frequently as possible
  // update the sensor values 
  sensor.update();
  // display the angle and the angular velocity to the terminal
  Serial.print(sensor.getAngle());
  Serial.print("\t");
  Serial.println(sensor.getVelocity());
}

用于 FOC 算法的位置传感器

要将传感器与本库中实现的 foc 算法一起使用,一旦你初始化了 sensor.init(),只需通过执行以下操作将其链接到 BLDC 电机:

motor.linkSensor(&sensor);

因此,一般来说,你的代码会是这样的:

#include <SimpleFOC.h>

float readMySensorCallback(){
 // read my sensor
 // return the angle value in radians in between 0 and 2PI
 return ...;
}

void initMySensorCallback(){
  // do the init
}

// create the sensor
GenericSensor sensor = GenericSensor(readMySensorCallback, initMySensorCallback);

....
BLDCMotor motor = ....
...

void setup() {
   ....
  // initialize sensor hardware
  sensor.init();
  // link to the motor
  motor.linkSensor(&sensor);
  ...
  motor.initFOC();
  ...
}
void loop() {
  ....
}

新传感器支持完整示例 - ESP32 硬件编码器

以下是一个基于 ESP32 架构实现的基于硬件计数器的编码器示例代码,简易FOC 默认不支持该架构。

为了设置计数器和所有硬件参数,这里我们使用 ESP32Encoder 库,示例的完整代码如下:

#include <SimpleFOC.h>
#include <ESP32Encoder.h>

// create the ESP32Encoder class
ESP32Encoder encoder;
// define the sensor cpr (500x4)
int64_t cpr = 2000;
// function intialising the sensor
void initMySensorCallback(){
  // use pin 25 and 26 (Arduino pins 2,3) for the encoder
  encoder.attachFullQuad(25, 26);
}
// function reading the encoder 
float readMySensorCallback(){
  // return the value in between 0 - 2PI
  float a = ((float)(encoder.getCount()%cpr)*_2PI/((float)cpr));
  return a > 0 ? a : a + _2PI;
}
// create the generic sensor
GenericSensor sensor = GenericSensor(readMySensorCallback, initMySensorCallback);

// BLDC motor & driver instance
BLDCMotor motor = BLDCMotor(11);
BLDCDriver3PWM driver = BLDCDriver3PWM(16, 27, 5, 12); // (Arduino pins 5,6,10,8)


// commander communication instance
Commander command = Commander(Serial);
void doMotor(char* cmd){ command.motor(&motor, cmd); }

void setup() {

  // initialize sensor hardware
  sensor.init();
  // link the motor to the sensor
  motor.linkSensor(&sensor);

  // driver config
  // power supply voltage [V]
  driver.voltage_power_supply = 12;
  driver.init();
  // link driver
  motor.linkDriver(&driver);

  // set control loop type to be used
  motor.controller = MotionControlType::torque;

  // use monitoring with serial for motor init
  // monitoring port
  Serial.begin(115200);
  // comment out if not needed
  motor.useMonitoring(Serial);

  // initialise motor
  motor.init();
  // align encoder and start FOC
  motor.initFOC();

  // subscribe motor to the commander
  command.add('M', doMotor, "motor");

  _delay(1000);
}


void loop() {
  // iterative setting FOC phase voltage
  motor.loopFOC();

  // iterative function setting the outter loop target
  motor.move();

  // user communication
  command.run();
}