On this page
Implementing a custom sensor
GenericSensor
is a new class of the SimpleFOClibrary that simplifies the implementation of new sensors. With this class you are able to add a custom sensor to your code and link it to the motor in one arduino file.
Step 1. Implement the function reading your sensor
Basically all that you need to do in your arduino code is implement a function that reads your sensor and returns an angle in radians between 0 and 2π:
float readMySensorCallback(){
// read my sensor
// return the angle value in radians in between 0 and 2PI
return ...;
}
additionally you can optionally implement a function that initialises your sensor
void initMySensorCallback(){
// do the init
}
Step 2. Instantiate GenericSensor
class
To initialize the sensor class you need to provide it the pointer to your function reading the sensor, and optionally the pointer to the function that initialises your sensor.
// 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);
And you will be able to access the angle and velocity of the motor using the motor instance:
motor.shaft_angle; // motor angle
motor.shaft_velocity; // motor velocity
or through the sensor instance:
sensor.getAngle(); // motor angle
sensor.getVelocity(); // motor velocity
Step 3. Using your sensor in real-time
There are two ways to use sensors implemented within this library:
- As motor position sensor for FOC algorithm
- As standalone position sensor
Standalone sensor
You can use your sensor as a standalone sensor. To get the sensor angle and velocity at any given time you can use the public methods:
class GenericSensor{
public:
// shaft velocity getter
float getVelocity();
// shaft angle getter
float getAngle();
}
Calling
getVelocity
multiple timesWhen calling
getVelocity
it will only calculate the velocity if the elapsed time from the previous call is longer than the time specified in teh variablemin_elapsed_time
(default 100us). If the elapsed time from the last call is shorter thanmin_elapsed_time
the function will return previously calculated value. Variablemin_elapsed_time
can be changed easily if necessary:sensor.min_elapsed_time = 0.0001; // 100us by default
Here is a quick example:
#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());
}
Position sensor for FOC algorithm
To use the sensor with the foc algorithm implemented in this library, once when you have initialized sensor.init()
, you just have to link it to the BLDC motor by executing:
motor.linkSensor(&sensor);
So in general your code will look something like this:
#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() {
....
}
New sensor support full example - ESP32 hardware encoder
Here is an example code implementing a hardware counter based encoder implementation based on the ESP32 architecture that the SimpleFOClibrary doesn’t support by default. To setup the counters and all the hardware parameters here we use the library ESP32Encoder and the full code of the example is as follows:
#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();
}