Control a BLDC motor (3 Hall sensor) with a Joystick

Hi, thanks for the info !

The problem is that there are no resistors for the hall sensors on the board and I do not have the equipment to solder such small resistors.

So I soldered my BTNs. (I also soldered the pads on the back)



I am rather satisfied with my welds.

However the card does not work :sleepy:

I’ve tried this code to see the position of the wheel (just to see if the sensor worked). But it didn’y worked. And this code does not depend on BTNs? As they are from Aliexpress I would already like to see if I can at least look at the position of the wheel.

#include <SimpleFOC.h>

// Hall sensor instance
// HallSensor(int hallA, int hallB , int cpr, int index)
//  - hallA, hallB, hallC    - HallSensor A, B and C pins
//  - pp                     - pole pairs
HallSensor sensor = HallSensor(2, 3, 4, 11);

// Interrupt routine initialization
// channel A and B callbacks
void doA(){sensor.handleA();}
void doB(){sensor.handleB();}
void doC(){sensor.handleC();}

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

  // check if you need internal pullups
  sensor.pullup = Pullup::USE_EXTERN;
  
  // initialize sensor hardware
  sensor.init();
  // hardware interrupt enable
  sensor.enableInterrupts(doA, doB, doC);

  Serial.println("Sensor ready");
  _delay(1000);
}

void loop() {
  // display the angle and the angular velocity to the terminal
  Serial.print(sensor.getAngle());
  Serial.print("\t");
  Serial.println(sensor.getVelocity());
}

And I’ve tried the code of my previous post. But the motor was not declared. I use a 24V battery and sensors built into my wheel.

I don’t know why I don’t have signal (I specify that I connected the power supply of the hall sensors to the 5V).

Can you help me to figure out what’s the issue ?

Ps : What code must be loaded into the Arduino to use the SimpleFoc software ?

Thanks a lot ! :slight_smile:

Hi !

Yes, I’ve solder the top of my BTN and it seems to be pretty good. It didn’t work but it’s clean :rofl:

This is because I have female connectors on my motor cable. I know it’s not ideal, but unfortunately I don’t have anything else to do.

Regards ! :slight_smile:

1 Like

Hey @Jekylleur,

Powershield should have the pullup resistors for the hall sensors, and from the image they seem to be on the board. You just have to enable them from behind (solder the three soldering pads).

Your code will not work with arduino UNO, because it does not have the hardware interrupts on pins 10,11,12 where the encoder/hall sensor connector is connected to.
You will need to use the software interrupts. See the example with the software interrupts for hall sensors in the library examples.

Btw, arduino uno only has 2 hadrware interrupts on pins 2 and 3; so if you would have used both of them as it is done in your code you would still need to use the sftware interrupts for the third one pin 4.

And it is very easy to setup: Hall sensors | Arduino-FOC

Hey @Jekylleur,

Powershield should have the pullup resistors for the hall sensors, and from the image they seem to be on the board. You just have to enable them from behind (solder the three soldering pads).

Your code will not work with arduino UNO, because it does not have the hardware interrupts on pins 10,11,12 where the encoder/hall sensor connector is connected to. see tables:

You will need to use the software interrupts. See the example with the software interrupts for hall sensors in the library examples.
https://github.com/simplefoc/Arduino-FOC/blob/master/examples/utils/sensor_test/hall_sensors/hall_sensor_software_interrupts_example/hall_sensors_software_interrupt_example.ino

Btw, arduino uno only has 2 hadrware interrupts on pins 2 and 3; so if you would have used both of them as it is done in your code you would still need to use the sftware interrupts for the third one pin 4.

And it is very easy to setup:

Hey @Antun_Skuric,

Thanks a lot for all these informations !

About this passage I was talking about the board of Infineon.

Yes I soldered them so I will check that the soldering is well done. I just hadn’t taken any pictures.

Thank you very much for the advice and information. The subtlety of the interruptions had escaped me.

I’ve now something like this :

#include <SimpleFOC.h>
#include <PciManager.h>
#include <PciListenerImp.h>

// Hall sensor instance
// HallSensor(int hallA, int hallB , int cpr, int index)
//  - hallA, hallB, hallC    - HallSensor A, B and C pins
//  - pp                     - pole pairs
HallSensor sensor = HallSensor(2, 3, 4, 11);

// Interrupt routine initialization
// channel A and B callbacks
void doA(){sensor.handleA();}
void doB(){sensor.handleB();}
void doC(){sensor.handleC();}

PciListenerImp listenA(sensor.pinA, doA);
PciListenerImp listenB(sensor.pinB, doB);
PciListenerImp listenC(sensor.pinC, doC);

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

  // check if you need internal pullups
  sensor.pullup = Pullup::USE_EXTERN;
  
  // initialize sensor hardware
  sensor.init();
  
  PciManager.registerListener(&listenA);
  PciManager.registerListener(&listenB);
  PciManager.registerListener(&listenC);

motor.controller = MotionControlType::velocity;

}

void loop() {

motor.target = 20;

}

But the issue is about motor.controller = MotionControlType::velocity;. He don’t know the motor. I believe that I did not declare it correctly but I do not quite understand how I should declare it.

Should I use this line?

BLDCMotor motor = BLDCMotor(11);

I’m a little confused sorry for all of his questions :sweat_smile:

I appreciate your help !

Regards :slight_smile: !

Here is an example code for the powershield, based on the encoder, but you can just replace the encoder with your hall sensor code:

Hello @Antun_Skuric and @JorgeMaker !

Sorry for the one month absence, I was on vacation and couldn’t test any codes. I just got back to it today !

Also know that I would not leave this forum without having succeeded and having shared the result of this project to be able to help other people :wink: :grinning:

I tested the codes you sent me and I have several results :sweat_smile:

First I tested the code for the hall sensors :

#include <PciManager.h>
#include <PciListenerImp.h>

#include <SimpleFOC.h>

// Hall sensor instance
// HallSensor(int hallA, int hallB , int cpr, int index)
//  - hallA, hallB, hallC    - HallSensor A, B and C pins
//  - pp                     - pole pairs

HallSensor sensor = HallSensor(10, 11, 12, 13);

// Interrupt routine initialization
// channel A and B callbacks
void doA(){sensor.handleA();}
void doB(){sensor.handleB();}
void doC(){sensor.handleC();}

// sensor interrupt init
PciListenerImp listenA(sensor.pinA, doA);
PciListenerImp listenB(sensor.pinB, doB);
PciListenerImp listenC(sensor.pinC, doC);

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

  // check if you need internal pullups
  sensor.pullup = Pullup::USE_EXTERN;

  // initialize sensor hardware
  sensor.init();
  // interrupt initialization
  PciManager.registerListener(&listenA);
  PciManager.registerListener(&listenB);
  PciManager.registerListener(&listenC);

  Serial.println("Sensor ready");
  _delay(1000);
}

void loop() {
  // display the angle and the angular velocity to the terminal
  Serial.print(sensor.getAngle());
  Serial.print("\t");
  Serial.println(sensor.getVelocity());
}

Thanks to this code I have the angle and the velocity. BUT ! I don’t know what the 13 corresponds to in my hall sensor setup… (I’ve solder the pins to activate the encoders on the back of the card.)

And with this code (which I think is functional) I wrote this code :

#include <PciManager.h>
#include <PciListenerImp.h>

#include <SimpleFOC.h>

// BLDC motor & driver instance
BLDCMotor motor = BLDCMotor(7);
BLDCDriver3PWM driver = BLDCDriver3PWM(9, 5, 6, 8, 4, 7);

// encoder instance
///Encoder encoder = Encoder(10, 11, 500);

//Hall sensor
HallSensor sensor = HallSensor(10, 11, 12, 13);
void doA(){sensor.handleA();}
void doB(){sensor.handleB();}
void doC(){sensor.handleC();}

// sensor interrupt init
PciListenerImp listenA(sensor.pinA, doA);
PciListenerImp listenB(sensor.pinB, doB);
PciListenerImp listenC(sensor.pinC, doC);

/*
// channel A and B callbacks
void doA(){encoder.handleA();}
void doB(){encoder.handleB();}
*/

// inline current sensor instance
InlineCurrentSense current_sense = InlineCurrentSense(0.001, 50.0, A0, A1);

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

void setup() {

  // monitoring port
  Serial.begin(115200);

  // check if you need internal pullups
  sensor.pullup = Pullup::USE_EXTERN;

  // initialize sensor hardware
  sensor.init();
  // interrupt initialization
  PciManager.registerListener(&listenA);
  PciManager.registerListener(&listenB);
  PciManager.registerListener(&listenC);

  Serial.println("Sensor ready");
  _delay(1000);

/*  
  // initialize encoder sensor hardware
  encoder.init();
  encoder.enableInterrupts(doA, doB); 
  // link the motor to the sensor
  motor.linkSensor(&encoder);
  */

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

  motor.voltage_sensor_align = 1;
  // set control loop type to be used
  motor.torque_controller = TorqueControlType::foc_current;
  motor.controller = MotionControlType::torque;

  // contoller configuration based on the controll type 
  motor.PID_velocity.P = 0.05;
  motor.PID_velocity.I = 1;
  motor.PID_velocity.D = 0;
  // default voltage_power_supply
  motor.voltage_limit = 12;
  
  // velocity low pass filtering time constant
  motor.LPF_velocity.Tf = 0.01;

  // angle loop controller
  motor.P_angle.P = 20;
  // angle loop velocity limit
  motor.velocity_limit = 20;

  // use monitoring with serial for motor init
  // monitoring port
  Serial.begin(115200);
  // comment out if not needed
  motor.useMonitoring(Serial);
  motor.monitor_downsample = 0; // disable intially
  motor.monitor_variables = _MON_TARGET | _MON_VEL | _MON_ANGLE; // monitor target velocity and angle
  
  // current sense init and linking
  current_sense.init();
  motor.linkCurrentSense(&current_sense);

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

  // set the inital target value
  motor.target = 0;

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

  // Run user commands to configure and the motor (find the full command list in docs.simplefoc.com)  
  Serial.println(F("Motor commands sketch | Initial motion control > torque/current : target 0Amps."));
  
  _delay(1000);
}


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

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

  // motor monitoring
  motor.monitor();

  // user communication
  command.run();
}

… who is not functional.

I mixed the code from single_full_control with the first one. And the board is smoking …

I handed in the code to know the position and it seemed to work. So I don’t know if I burnt out the BTNs or the wheel. But I’m pretty sure this code doesn’t work … :sweat_smile:

In addition, I would like to remind you that my BTNs come from Aliexpress. So I cannot be sure that they are working well … but I have more of them if needed.

In addition I tested (before seeing smoke) the single_full_control code without any modifications and the engine shuddered slightly. Which leads me to say that only a few small tweaks are missing for it to work, but I don’t know which ones …

I can’t seem to see what I’m missing, can you help me (again) ? :sweat_smile:

A big thank-you, regards :slight_smile:

I’ll look into your message more in depth tomorrow, for now the only quick fix i see is that number 13 is the pole pairs number and it should be the same as the motor one.
So if you use 7 pole pair motor you should set number 7 to the hall sensor as well :smiley:

Hi !

Thanks a lot for your prompt response :slight_smile: :wink:

I did not know my pole pair number. So, I open my hub motor :rofl:

Here are some pics :


And to save you counting, we have 30 magnets and 27 coils.

But I found out that in this line :

HallSensor sensor = HallSensor(10, 11, 12, 30);

It’s better to put 15 rather than 30. Because I have 3.14 rad at 180° with 15. And with 30 I have 3.14 rad at 360. This is why I think 15 is better than 30. I don’t know if I’m clear :sweat_smile:

This is just to give more info about my hub :slight_smile:

And I’ve tried the full_control_serial code

/**
 * Comprehensive BLDC motor control example using Hall sensor
 * 
 * Using serial terminal user can send motor commands and configure the motor and FOC in real-time:
 * - configure PID controller constants
 * - change motion control loops
 * - monitor motor variabels
 * - set target values
 * - check all the configuration values 
 * 
 * See more info in docs.simplefoc.com/commander_interface
 */
#include <SimpleFOC.h>
// software interrupt library
#include <PciManager.h>
#include <PciListenerImp.h>

// BLDC motor & driver instance
BLDCMotor motor = BLDCMotor(15);
BLDCDriver3PWM driver = BLDCDriver3PWM(9, 5, 6, 8);
// Stepper motor & driver instance
//StepperMotor motor = StepperMotor(50);
//StepperDriver4PWM driver = StepperDriver4PWM(9, 5, 10, 6,  8);

// hall sensor instance
HallSensor sensor = HallSensor(10, 11, 12, 15);

// Interrupt routine intialisation
// channel A, B and C callbacks
void doA(){sensor.handleA();}
void doB(){sensor.handleB();}
void doC(){sensor.handleC();}
// If no available hadware interrupt pins use the software interrupt
PciListenerImp listenC(sensor.pinC, doC);


// commander interface
Commander command = Commander(Serial);
void onMotor(char* cmd){ command.motor(&motor, cmd); }


void setup() {

  // initialize encoder sensor hardware
  sensor.init();
  sensor.enableInterrupts(doA, doB); //, doC); 
  // software interrupts
  PciManager.registerListener(&listenC);
  // link the motor to the sensor
  motor.linkSensor(&sensor);

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


  // choose FOC modulation
  motor.foc_modulation = FOCModulationType::SpaceVectorPWM;
  // set control loop type to be used
  motor.controller = MotionControlType::torque;
  // contoller configuration based on the controll type 
  motor.PID_velocity.P = 0.2;
  motor.PID_velocity.I = 20;
  motor.PID_velocity.D = 0;
  // default voltage_power_supply
  motor.voltage_limit = 12;

  // velocity low pass filtering time constant
  motor.LPF_velocity.Tf = 0.01;

  // angle loop controller
  motor.P_angle.P = 20;
  // angle loop velocity limit
  motor.velocity_limit = 50;

  // 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();

  // set the inital target value
  motor.target = 2;

  // define the motor id
  command.add('A', onMotor, "motor");

  // Run user commands to configure and the motor (find the full command list in docs.simplefoc.com)
  Serial.println(F("Motor commands sketch | Initial motion control > torque/voltage : target 2V."));
  
  _delay(1000);
}


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

  // iterative function setting the outter loop target
  // velocity, position or voltage
  // if tatget not set in parameter uses motor.target variable
  motor.move();

  // user communication
  command.run();
}

The motor won’t move but if I turn it in the initialisation I have this :

Regards

I also have this question, how can we control a BLDC motor (sensor 3 Hall) with a joystick?

Hello, I’m trying to do it too. If you succed send me a message :wink:

Hi, I found an issue with my code :sweat_smile: . So now I have the good output on the BTN’s :pray: .

I’ve used this code :

// BLDC driver standalone example
#include <SimpleFOC.h>


// BLDC driver instance
  BLDCDriver3PWM driver = BLDCDriver3PWM(9, 6, 5, 8, 7, 4); //BTN1 BTN2 BTN3

void setup() {
  
  // pwm frequency to be used [Hz]
  // for atmega328 fixed to 32kHz
  // esp32/stm32/teensy configurable
  driver.pwm_frequency = 32000;
  // power supply voltage [V]
  driver.voltage_power_supply = 25.2;
  // Max DC voltage allowed - default voltage_power_supply
  driver.voltage_limit = 25.2;

  // driver init
  driver.init();

  // enable driver
  driver.enable();

  _delay(1000);
}

void loop() {
    // setting pwm
    // phase A: 3V
    // phase B: 6V
    // phase C: 5V
    driver.setPwm(13,16,15);
}

But I still have not managed to run my motor.
I used this code:

#include <SimpleFOC.h>
  #include <PciManager.h>
  #include <PciListenerImp.h>

// BLDC motor & driver instance
  BLDCMotor motor = BLDCMotor(15);
  BLDCDriver3PWM driver = BLDCDriver3PWM(9, 6, 5, 8, 7, 4); //BTN1 BTN2 BTN3
  //BLDCDriver3PWM driver = BLDCDriver3PWM(9, 10, 11, 12);

// commander communication instance
  Commander command = Commander(Serial);

void setup() {

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

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

// default voltage_power_supply
  motor.voltage_limit = 30;

// use monitoring with serial for motor init
// monitoring port
  Serial.begin(115200);
// comment out if not needed
  motor.useMonitoring(Serial);
  motor.monitor_downsample = 0; // disable intially
  motor.monitor_variables = _MON_TARGET | _MON_VEL | _MON_ANGLE; // monitor target velocity and angle
  
// initialise motor
  motor.init();
// align encoder and start FOC
  motor.initFOC(); 


// Run user commands to configure and the motor (find the full command list in docs.simplefoc.com)
  Serial.println(F("Motor commands sketch | Initial motion control > velocity openloop : target 2 rad/s."));
  
  _delay(1000);
}


void loop() {

  
  float motor_target = 2;
  
// iterative setting FOC phase voltage
  motor.loopFOC();

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

// motor monitoring
  motor.monitor();

// user communication
  command.run();

}

I progress little by little and I approach the goal but I do not understand what I need to succeed in controlling the wheel …

If you have any ideas or advice I am interested :wink:

Regards :slight_smile:

Why your motor limit is high, use voltage limit 1. Also, your motor will not move because you set the motor_target =2 in the main loop. So it will keep the target value to 2. Move that command in the setup and than change your target value using serial.command.

I hope this helps you.

Regards,
Moid Khan

Hi,

It’s just because I was doing different tests. I’ve try with your recommandations and it didn’t work either. In fact I have the impression that my problem comes from the initialization. This is from the Serial Monitor.

This one shows a problem with the sensors (maybe it’s looking for something other than hall sensors?). I also tried with something other than 2 rad / s. It did not work.

246760132_405119331022400_427737337984629982_n

And this one keep stuck to the alignement process but nothing change (even when i rotate the motor with my hands). :upside_down_face: