ESP32 Board with AS5600 Magnetic Sensor in PWM Mode

Hi all,

I have an ESP32 Board (Deng FOC, see Deng FOC Board - Easy to use!) with an AS5600 magnetic sensor, which I’d like to use in PWM mode. Unfortunately, there is no sample code in the GIT repo pointed to by the above mentioned post). The sensors are connected to the ports I0 and I1 of the driver. However, my code always prints out 0 for the angle.

Code:

#include <SimpleFOC.h>

MagneticSensorPWM sensor = MagneticSensorPWM(I0, 4, 904);
MagneticSensorPWM sensor1 = MagneticSensorPWM(1, 4, 904);

BLDCMotor motor = BLDCMotor(14);
BLDCDriver3PWM driver = BLDCDriver3PWM(32,33,25,22);

BLDCMotor motor1 = BLDCMotor(14);
BLDCDriver3PWM driver1 = BLDCDriver3PWM(26,27,14,12);

float target_velocity = 0;
Commander command = Commander(Serial);
void doTarget(char* cmd) { command.scalar(&target_velocity, cmd); }

void setup() {
sensor.init();
sensor1.init();

motor.linkSensor(&sensor);
motor1.linkSensor(&sensor1);

driver.voltage_power_supply = 16.8;
driver.init();

driver1.voltage_power_supply = 16.8;
driver1.init();

motor.linkDriver(&driver);
motor1.linkDriver(&driver1);

motor.foc_modulation = FOCModulationType::SpaceVectorPWM;
motor1.foc_modulation = FOCModulationType::SpaceVectorPWM;

motor.controller = MotionControlType::angle;
motor1.controller = MotionControlType::angle;

motor.PID_velocity.P = 0.2;
motor1.PID_velocity.P = 0.2;
motor.PID_velocity.I = 20;
motor1.PID_velocity.I = 20;

motor.P_angle.P = 20;
motor1.P_angle.P = 20;

motor.voltage_limit = 12;
motor1.voltage_limit = 12;

motor.LPF_velocity.Tf = 0.01;
motor1.LPF_velocity.Tf = 0.01;

motor.velocity_limit = 40;
motor1.velocity_limit = 40;

Serial.begin(115200);
motor.useMonitoring(Serial);
motor1.useMonitoring(Serial);

motor.init();
motor1.init();

command.add(‘T’, doTarget, “target velocity”);

Serial.println(F(“Motor ready.”));
Serial.println(F(“Set the target velocity using serial terminal:”));
}

void loop() {
Serial.print(sensor.getAngle());
Serial.print(" - ");
Serial.print(sensor1.getAngle());
Serial.println();
motor.loopFOC();
motor1.loopFOC();

motor.move(target_velocity);
motor1.move(target_velocity);

command.run();
}

Does anyone has an idea where the problem is? Using I2C, I have no problems obtaining the angle (in radians) from the matnetic sensor. However, I have to make it work in PWM mode (don’t ask why pls).

Thanks.

Hi @foobar47 , welcome to SimpleFOC!

Is the number of the pole pairs really 14? It’s possible, but it’s an unusual number. Are you sure it’s not 14 poles and therefore 7 pole pairs?

The PWM Sensor type is the one with the worst performance, unfortunately. And using 2 of them in PWM mode will limit your loop speed to one update per motor every 2ms, or 500 updates per second. This will greatly limit the overall systems performance.
I’d advise against using 2 sensors in PWM mode.

Looking at your code, you can’t print each time through the main loop. Maybe once or twice per second should be enough to see the angle values, and won’t overload your main loop with blocking calls to println().

For the first sensor you specify the pin as I0, while for the second you just write ‘1’. Is that correct?

You’re running it in angle mode, but I would definately make sure torque-voltage mode is working first before moving on to the other closed loop modes…

If your sensors are already working in I2C mode, I would strongly urge you to use them in this mode. It will still be too slow really for 2 motors, but at least it will be better than PWM, and is already working…

If you continue along the PWM path, please try to use the interrupt-driven configuration by supplying an interrupt callback function like in this example: https://github.com/simplefoc/Arduino-FOC/blob/master/examples/utils/sensor_test/magnetic_sensors/magnetic_sensor_pwm/magnetic_sensor_pwm_example/magnetic_sensor_pwm_example.ino

I’m using the AS5600 in analog mode. Didn’t know they can do PWM too?
The analog mode is way faster than i2c, but it’s noisy so I added a “running average” to filter out misreads. ( learned here, it’s a LowPassFilter )

//example of running average 
//pseudo code
angle= (previous.angle *0.9 + sensor.GetAngle() * 0.1);

Hey,

You can switch between analog and PWM modes on the out pin. You select the mode via I2C commands (OUTS bits in CONF register).

You could also use the SimpleFOC LPF class - it will take the time into account, which will lead to a better response, since you’re not sampling the sensor at a constant rate.
Adding this type of filter to the sensor position will add quite a bit of lag to the position, for obvious reasons. This will affect the FOC algorithm, since it will effectively be working with an old position rather than the correct one.

Good to know, but it sounds crazy to use PWM-mode, when I already need a i2c connection to set this mode.
In i2c mode, I couldn’t move the motor much faster than 1rpm, while analog allowed much faster turns ( the limit was the 12V supply)

Hi @runger,

first of all, thanks for the warm welcome. As you can imagine, I am relatively new to micro controller programming, especially to SimpleFOC.

The motor specific code is more or less taken over from an example from the GIT repo and it works fine, see https://github.com/ToanTech/Deng-s-foc-controller/blob/master/Dengs%20FOC%20V3.0/Dengs%20FOC%20V3.0%20测试例程(支持库SimpleFOC%202.2.1)/2_双电机开环位置控制/2_open_loop_position_example/2_open_loop_position_example.ino

Motor speed is not a primary goal for the implementation. I have to check if the speed will be sufficient once I have a working code using PWM.

Good point. However, currently the main problem is that I always get 0 as the angle. I don’t think this is due to the overload of println() statements.

No, I0 is a mistake. It should be 0 and 1 since the sensor is connected via the PINS I0 and I1 to the driver. However, I am not sure if 0 and 1 is really correct for the pins I0 and I1.

Ok, I’ll try out torque mode and see if it makes any difference.

There are two problems with I2C mode. First of all, its not possible to use it for design reasons (The BLDCs are basically embedded into some kind of robot and its not possible to integrate I2C as there are two many wires - I am just responsible for doing the programming stuff, someone else does the hardware - Let’s just assume I2C can’t be done). Second, I have the problem that I can move the engines without using a sensor, but as soon as I initialize the sensor, the engines do not move anymore (I guess there is something wrong with the code, but it’s not really important due to the first reason).

Ok, that sounds reasonable once the sensors returning any usable value.

You’re absolutely right. But once the sensor is working, the motor still won’t work due to the printlns.

Ok, it’s good if you don’t need to go fast, but be aware that it will affect performance in other ways as well. It’s not just the top speed you can reach, but also how quickly you can react to changes of any kind. The PWM sensor usually also exhibits a bit of “discontinuity” around the 0-point. And it will introduce a large lag between the measured and the actual sensor position, which translates into inefficiency in the motor control (more power used for less torque, more heat generated in the motor).

this seems odd to me - within the software, when using Arduino for ESP32, pins are usually referred to by their GPIO number - so ESP32 GPIO6 is pin ‘6’.

Do you have a schematic or pinout diagram we could use to figure out where these pins connect to the MCU?

ok, we always like a challenge :slight_smile:

I assume the sensor is emitting a PWM signal, and not analog, as @o_lampe pointed out?

Because you mention the too many wires, the I2C mode would need 4 (pwr, gnd, sda and scl) while PWM or analog mode need 3 (pwr, gnd and signal). But for 2 sensors, they need the same amount of wires: sda and scl can be shared by both sensors, while for PWM each sensor needs a separate signal line, bringing the total to 4 lines for 2 sensors in both cases.

It is the case that the driver and the sensor share a common GND, right?