Two simpleFOC shields operate on the same motor gives very different results

SimpleFOC seems to be amazing. But I face a problem that seems to be hard to solve as a beginner:

I have two simpleFOC shield 2.0.4. I adjust so that one use A0,A2 and the other use A1,A3 for current sensing. When I try to test the position (angle) control example on a GM4108-120T using these two sheilds. The one that use A0, A2 pin for current sensing works. But the other one uses A1, A3 pin for current sensing failed and the log it gave is below:

From the shield that doesn’t work for angle control:

MOT: Monitor enabled!

MOT: Init

MOT: Enable driver.

MOT: Align sensor.

MOT: sensor_direction==CW

MOT: PP check: fail - estimated pp: 60.61

MOT: Zero elec. angle: 0.00

MOT: No current sense.

MOT: Ready.

Motor ready.

From the shiled that works well:

MOT: Monitor enabled!

MOT: Init

MOT: Enable driver.

MOT: Align sensor.

MOT: sensor_direction==CW

MOT: PP check: OK!

MOT: Zero elec. angle: 2.90

MOT: No current sense.

MOT: Ready.

Motor ready.
  • Both has no current sense
  • The good one PP check is OK but the failed one also fails at PP check (this motor’s PP is 11)
  • The good one find zero elec. angle but the failed one only report a 0

Why different shields can operate so differently? I am a bit confused here.

Please advice!

Below is the code I am using (MOT1, ENC1 and MOT2, ENC2 are used for two shields)

#include <SimpleFOC.h>

// MOT1 Pinout test (PASS)
#define MOT1_A 16 //5
#define MOT1_B 13 //9
#define MOT1_C 27 //6
#define MOT1_EN 12 //8

#define ENC1_A 19 //12 (change to 12->19)
#define ENC1_B 26 //2

// MOT2 Pinout test (PASS)
#define MOT2_A 25 //3
#define MOT2_B 5 //10
#define MOT2_C 23 //11
#define MOT2_EN 14 //7

#define ENC2_A 39 // (12->19), (A5->39), (3->25)
#define ENC2_B 36 // (A4->36), (2->26)

// Motor instance
BLDCMotor motor = BLDCMotor(11);
BLDCDriver3PWM driver = BLDCDriver3PWM(MOT1_A, MOT1_B, MOT1_C, MOT1_EN);
// BLDCDriver3PWM driver = BLDCDriver3PWM(MOT2_A, MOT2_B, MOT2_C, MOT2_EN);

// encoder instance
Encoder encoder = Encoder(ENC1_A, ENC1_B, 500); // changing from 2048 to 500 helps reducing motor jitter by a lot !
// Encoder encoder = Encoder(ENC2_A, ENC2_B, 500); // changing from 2048 to 500 helps reducing motor jitter by a lot !

// Interrupt routine intialisation
// channel A and B callbacks
void doA() {
void doB() {

// angle set point variable
float target_angle = 0;
// instantiate the commander
Commander command = Commander(Serial);
void doTarget(char* cmd) {
command.scalar(&target_angle, cmd);

void setup() {

// initialize encoder sensor hardware
encoder.enableInterrupts(doA, doB);

// link the motor to the sensor

// driver config
// power supply voltage [V]
driver.voltage_power_supply = 12;
// link the motor and the driver

// aligning voltage [V]
motor.voltage_sensor_align = 12;
// index search velocity [rad/s]
motor.velocity_index_search = 3;

// set motion control loop to be used
motor.foc_modulation = FOCModulationType::SpaceVectorPWM;
motor.controller = MotionControlType::angle;

// contoller configuration
// default parameters in defaults.h

// velocity PI controller parameters
motor.PID_velocity.P = 0.3f;
motor.PID_velocity.I = 0.7f;
// default voltage_power_supply
motor.voltage_limit = 12;
// jerk control using voltage voltage ramp
// default value is 300 volts per sec ~ 0.3V per millisecond
motor.PID_velocity.output_ramp = 10000;

// velocity low pass filtering time constant, lower value means less filtering
motor.LPF_velocity.Tf = 0.1f; // ! very important to filter more

// angle P controller
motor.P_angle.P = 20;
// motor.P_angle.I = 0.5f;
// maximal velocity of the position control
// motor.velocity_limit = 10;

// For many motion control applications it will make sense run multiple torque control loops for each motion control loop. This can have a great impact on the smoothness and can provide better high-speed performance.
// Therefore this library enables a very simple downsampling strategy for the move() function which is set using the parameter motor.motion_downsample:
motor.motion_downsample = 5; // - times (default 0 - disabled)

// use monitoring with serial
// comment out if not needed

// initialize motor
// align encoder and start FOC

// add target command T
command.add(‘T’, doTarget, “target angle”);
Serial.println(F(“Motor ready.”));
Serial.println(F(“Set the target angle using serial terminal:”));

void loop() {
// Serial.println(encoder.getAngle());
// main FOC algorithm function
// the faster you run this function the better
// Arduino UNO loop ~1kHz
// Bluepill loop ~10kHz

// Motion control function
// velocity, position or voltage (defined in motor.controller)
// this function can be run at much lower frequency than loopFOC() function
// You can also use motor.move() and set the in the code

// function intended to be used with serial plotter to monitor motor variables
// significantly slowing the execution down!!!
// motor.monitor();

// user communication;

It’s probably not the shields, more likely the wiring changed or there is more noise. Is the pullup resistor in place if this is I2C? Is it all grounded properly? Also there are mode pins on some angle sensors that may need to be grounded or pulled up. Check all the wiring with a magnifying glass.

Thanks for replying! I’ve checked the encoder by printing them out, and manually rotate the motor. Both shields works fine with the encoder (AMT103-V). There is no need for a pull up resistor for this encoder. Other wire connection are all checked with a multimeter.


Clearly, from your description, there is a problem with the encoder here for the second motor. If you say it is working in some of your tests, but not when you run the motor code, then there is some mistake in the pin definitions in the code, or the pin connections in the hardware, that’s incorrect for the test…

I assume you configured the encoder for 500 PPR?

Thanks for the feedback!

I would clarify that there is only one motor and only one encoder here. Yes I change the pin definition in the code when using two different simpleFOC shield. I indeed configure the encoder to 500 and it works great for reporting the shaft angle by the encoder.

Please advise the thought process to identify that there is a encoder issue here? The same encoder and motor works great with the other shield board.

Would be greatly appreciate the help here!

How is the encoder wired? Is it connected via the SimpleFOC shield? The SimpleFOC shield has solder jumpers on it for configuring the pins… is each shield configured to match the pins being used?

The AMT103-V encoder were connected via A/B/GND/5V pins on the simpleFOC shield. I tested by manually rotating the same motor, which ratates the shaft that go through the encoder. I can get approximately correct angle (using encoder example) with both simpleFOC shields.

But one shield would fail at closed-loop position (angle) control example. I just found that the failed shield board also failed at open-loop position (angle) control example, it doesn’t rotates smoothly but just wobble a tiny bit when I type a targeted angle.

Well this changes the picture!

In this case you need to check the PWM pins used match the configuration of the shield, maybe there is a problem with this?

Do you have an oscilloscope you can use to check the driver input pins? If not you can at least check for connectivity with a multimeter… maybe even if the settings are correct, one of the solder-points is not good or something like this?


I only have a multimeter around me, cool. I will go to check those three PWM output connection.

I just solder all relevant pins at the back of the board and test the connections. It looks all correct to me.

But when I test in the open/closed-loop angle control it still failed. It only wobbles and produce loud sound in open-loop test without rotating.

So it is using pins 5, 9 and 6 for the PWM - is this also what you have configured in the code?
And the other one is using 3,10 and 11…

But you are using different pins in the code - is it for ESP32? Have you checked if the pins are used in another way on the MCU board, maybe connected to some peripheral chip?
Have you checked that these pins are all available for use, and capable of output? ESP32 has many restrictions on the pins…

Yes, I did check all those from the begning. I did not report a important information. These pins and code has worked out in the begining. I left the power on there and went to a dinner. I came back a few hours later and found it stops working. During the time I left the motor is not turning, I checked the current from my power is around 0.8A@12V. After it stop working, I never make it work again. The motor I use has an internal resistance of 11 ohm, so its phase resistance is around 5.5 ohm. Is it because of that reason I cannot left it powering on for hours?

May I ask what is the limitation of this board on how much power/current it can handle? Thanks!

Yes, it is used with a “wemos D1 R32”.

Ah, this is different… we cannot know exactly what happened, because no one saw it :frowning:

Based on how you describe it, I think we can assume that there was some kind of problem while you were away - maybe too much current, maybe too much heat…

The driver used on the SimpleFOC shield can handle 5A peak current, maybe 3-4A continuous, but only with additional thermal management, e.g. heat sinks and/or fans. With a naked shield, 2A continuous should be possible.

The chip has both thermal and overcurrent protection, so normally it has a certain amount of safety and people find it quite robust.

I’m going to guess so, yes… while tuning a new system it is important to watch it carefully, and check the components, especially driver and motor - these can get very hot if things are wrong in the system, either in the software or the hardware. It’s important to check that things don’t just keep getting hotter - a motor driver will always develop some heat, but it should max out at some level that all the components can handle. If this does not happen naturally for the system you’re working on, then you need active temperature management in the control.

You could check now which part of the system is broken - it sounds like the driver… its unusual because 12V is well within this driver’s capability, and the motor is quite high resistance - like I said, the driver is normally fairly robust.
The motor has survived the problem it seems - often the motor will get too hot and “burn out” - either demagnetising, or melting its insulation and shorting out. But this has not happened in your case.
Another problem can be the MCU pins - if they received too much voltage for some reason they could be damaged.

Thanks for all those helps here. I really appreciate it. Following your suggestion, I have now soldered both shields using the same configuration. I then tested both shields with the same connections and code. The results are still the same: one shield works, but the other does not. I also tested both using the ‘find_pole_pair_number.ino’ example. With the working shield, the motor rotates and correctly identifies the motor PP number as exactly 11. However, with the faulty shield, the motor only jitters slightly and is unable to rotate, resulting in an indefinite PP number.

jitters slightly and is unable to rotate during pole pair check? It’s driven open loop. Either the current is too low or one of the phases of the motor is not connected or not getting power for some other reason.

if you help it along and it rotates, current is too low for some reason.

If it goes back and forth slightly then one phase is not connected.

Thanks for your input. The strange thing is one shield always works and the other doesn’t even their pin configuration and code are the same. I purchased another shield and will post the following test once it arrives.

Yeah, it very much looks like that one shield has a problem with one of its chips or in the soldering or internal connections. It happens, unfortunately. Doing the direct comparison like you did is the best test you can do for this, I think.

Still not a bad idea to figure out exactly what’s wrong with it though, also people often miss a wire here or there and are convinced they didn’t. I’d poke around with an oscope and try to figure out what’s up before buying another board, but suit yourself.