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


I would like to control a BLDC Motor with hall sensor using a joystick. I’m using a electric scooter wheel (24V) with integrated hall sensor.

The idea is to control the motor with PWM. I don’t need to be fast. I mostly need torque. I don’t need to be specific either, it’s just to make a toy car for kids. So I’m not looking for speed but just enough control to get off to a good start.

I looked at how the library works in serial link but I did not understand how I could directly integrate in my code the commands to send my speed command to my motor. Until now I used an Amazon card based on the JY01 component but I would like to be able to control my motor a little better for starting and braking. The card used :ôleur-moteur-balais-12V-36V/dp/B08SWJ4DWS/ref=asc_df_B08SWJ4DWS/?tag=googshopfr-21&linkCode=df0&hvadid=526041473462&hvpos=&hvnetw=g&hvrand=6303912459023188680&hvpone=&hvptwo=&hvqmt=&hvdev=c&hvdvcmdl=&hvlocint=&hvlocphy=9056335&hvtargid=pla-1150561126753&psc=1

Here is the code :

if(xPosition >=650){ // The Joystick position / value speed= map(xPosition, 650, 1023, 0 , 100); // I transform the values 0-1023 into arduino PWM 0-255 by limiting myself to 100 so as not to go too fast analogWrite(pwm, speed); // I send to the board digitalWrite(ccw, LOW); // To set the direction forward }

I am wondering if i can use this command in my loop :


Just for the record I plan to use the PowerShield Board. I don’t have it yet, due to broken components. I am trying to order it on easy EDA.

My goal is to be sure that I will succeed in running my engine with the code. So as soon as I receive the board I can make more adjustments. Like the PID or the R and I values of my motor.

So I wanted to know if you could help me with this project, by helping me with the code. Because I’m not sure I fully understood all the code. Thank you in advance for your help.

1 Like

If you want control the speed of your motor in rads/second you have to configure your SimpleFOC controller in velocity mode and send target commands with the velocity you want your motor achieve using the Commander interface.

This function is not intended to fix the speed that you want to achieve.

Hello, thank you for your answer.

I read the command interface page. If I understood correctly I must do:

speed = map(xPosition, 650, 1023, 0 , 100);;

In the loop section.

And add this :

motor.controller = MotionControlType::velocity;

in the setup section.

I’ve read this too : but I did not understand everything.

Same for this one :

Something like that :

#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

// Joystick Ini
  pinMode(VRx, INPUT); 
  pinMode(VRy, INPUT); 
  pinMode(SW, INPUT_PULLUP); 

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

motor.controller = MotionControlType::velocity;


void loop() {

  xPosition = analogRead(VRx);  // (A0)
  yPosition = analogRead(VRy);  // (A1)
  SW_state = digitalRead(SW); 

speed = map(xPosition, 650, 1023, 0 , 100);;


I don’t have the board yet, so I’m writing the code without being able to test it. Excuse me if I make silly mistakes.

And I would like to know how I can tune my motor. Can I use the SimpleFOC software to find out the PID and motor settings in the code?

If I understood correctly the PID will allow me to reach the speed that I want gradually and smoothly.

In general, it allows better management of the motor, right?

I appreciate your help and hope my questions are not too disturbing. I hope the answers can be used by others.

Regards :slight_smile:

My advise is that you start by the begging following this step by step procedure before trying to do anything more complicated.

This is not how the commander interface works. If you want to set a target speed depending on your joystick position readings, just use this — ` = speed;` `—

The Commander interface is designed to receive commands through the serial port connection and then send them to the engine. If you’re reading your joystick on the same MCU running SimpleFOC, you don’t need a commander at all.

Hi, ok thanks for your answer. Sorry for taking a little long to answer, I didn’t have my computer.

I looked at this page but I went directly to this page since my engine has directly integrated hall sensors. In fact I am ordering the board. Components are missing due to COVID. This is why I am learning to go further, it is because I cannot experiment.

That’s why I posted the code for the hall sensors page. Because I thought my edits were good. What is certain is that for the more advanced settings (PID, …) I would wait. But I just want to make sure I have the correct code to run my motor with a joystick. So when I got the board I would just have to test and go further.

Tanks for this command I would test as soon as I got the board.

Do you know if the code works with this board : IFX007T-Motor-Control

Regards :slight_smile:

1 Like

SimpleFOC mainly depends on the MCU in which you run it. I assume that you are using a board like this one or similar.

If this is the case as far as you get running SimpleFOC in your MCU it will work. If your board has an integrated MCU I can not tell you.

Here you have, as example, a custom board to run SimpleFOC board using IFX007T, so IFX007T are perfectly suitable.

Regards !!


Yes it’s this one. As for the PowerShield I do not have the card yet but if I can not order the PowerShield I would use this one.

Yes it’s on an arduino. But I think I have some pin assignment to do with this board.

I am ordering the PowerShield but I am having trouble finding the components, do you know where I can buy some (Mosfet, Current Sense Amplifiers)?

I have a few more complex questions for my project. I would like to know the current consumption of my project when I accelerate (for example). And save the data in a .csv (I have to add a clock and an SD card). But does the card measure current or do I need to make changes?

I searched in the code but I don’t think I found it. Is there a function to brake? To reverse the rotation of the motor for example.

Once again thanks for your help ! I appreciate !

Regards :slight_smile:

As long as they are available and not out of stock due to semiconductor supply shortages as I generally buy components from LCSC because they have no minimum order and they offer quite a wide variety. MOUSER is another option that offers a wider assortment but they charge you € 50 if your order is less than that amount.

Another option, for some “popular” components, is AliExpress … but it is a bit risky because you never know if they are selling you something original or a cloned copy and if the cloned copy is going to be of quality, … is playing a bit of the lottery, it can go right or wrong.

Never used current sensing, I can not say anything for sure … but my assumption is that if you have current sensing you will be able to gather data and save it.

As far as I kano the is no “brake” functionality. What you can do if you are in velocity control mode is set target velocity to 0 when you want to stop or of you are in position control mode set target position equal to current position.


Ok thank you these are the ones I know too. And yes, the Chinese platforms have surprises in store for us.

Alright, I’ll create another topic to see if people are using it.

If I understand correctly, using this function will slow the motor down to 0. Or will it simply stop powering the motor? I understand the difference between velocity and position. But I am not sure I fully understand the behavior of the motor.

This control mode will block the engine, right?

Basically : velocity = ABS and position = Locking the wheel (skidding).

Both modes are interesting so I wonder if I can change the operating mode in the loop? Velocity mode for 90% of the time and position for the remaining 10%. Unless it is not possible…

Thank you for your time to share your knowledge !!

If you run in a closed loop mode SimpleFOc is able to know what the shaft of your motor is doing thanks to the sensor so if you are in velocity mode it will try to do as much as it can to keep the rotation velocity to 0 rads/s , it will not stop stop powering just will try to keep velocity to 0 rads/s instead of lets say 20 rads/s , 50 rads/s or whatever other target velocity. In that way If you apply an external torque to your motor to move your motor apply a torque trying to oppose to it until it reach 0 rads/s.

In closed loop position mode the engine tries to do as much as it can to keep the target position so if it is moving from one position to another and you decide to “brake/stop” by setting the new target position equal to the current position it will try to “stop” or reach the new target position as fast at it can and will try to do its best to keep the new target position. If you apply an external force to the shaft it will do its best to recover the target position. This differ from velocity mode in which only tries to keep the velocity not trying to recover any position.

Depending on your application you have to decide what is more interesting for you while breaking, try to stop the shaft without recovering any position or trying to hold a position.

Yes you can switch from any control mode to any control mode at any moment but you have to assume that you ill experience some transient behavior in control mode switching so is some the tat is not the most recommended to do continuously or at least requires som testing to see how behaves and if it stable for your particular application.

Regards !! :slight_smile:

I would like to add DigiKey, Arrow and Newark. Many silicon manufacturers use only one of these so you may not get the full picture unless you shop across all retailers.

Avoid aliexpress like fire unless you are a masochistic pyromaniac.

Best would be to go to and do a global search across all official retailers, for example:

1 Like

Hello, thank you for the info it’s super clear.

I think I’ll have to wait to decide which of the two modes I’m going to use to brake. I have to realize the behavior of the engine in each case and in different situations.

Because I want to use it to move around so the wheel is in contact with the ground. So there may be different terrains that may require different modes.

I also wanted to know how I could analyze the values of the hall sensors. My idea is if something brakes the drive wheel for too long. My idea is if something brakes the drive wheel for too long. I can detect it. This would allow me to cut the power supply so as not to pass too much current through the card at the risk of burning it. Some kind of security.

Is there a topic that talks about it ? Or an example for me to be inspired by ? Or it’s just a command line to switch modes ?

Are you a developer of the project? Or a very good expert of the library ?

Regards :slight_smile:

Hi, thanks for the information.

I would look at the different dealers especially for the transistors. And yes it is true Aliexpress is not very reliable, let’s say that it is to be ordered in addition to the rest, just in case.

You can switch control mode just by sending a command via Commander interface from another MCU using RS232 or from the same MCU using one of the following statements:

 motor.controller = MotionControlType::angle;  // poison closed loop
 motor.controller = MotionControlType::velocity; // velocity closed loop
 motor.controller = MotionControlType::velocity_openloop // velocity open loop 

Not :slight_smile: … the main developer of this awesome library is @Antun_Skuric

Yes for the sake of simplicity I will stay on the same MCU.

Can I do Something like this :

motor.controller = MotionControlType::velocity; = speed;

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

I know that the speed value must be adapted according to the type of control. 50 rad / s is different from the target position. But in the idea of sending a command. I will test which of the two methods is more efficient to stop the whell.

And to be sure that the target speed is reached and to cut off the power supply in the event of too much resistance, can I use this command:

float WheelSpeed = sensor.getVelocity();

And do something like this (in pseudo code):

float WheelSpeed = sensor.getVelocity();
if (WheelSpeed != speed)

I know that the speed sent in command cannot be constant and perfect, we must add an interval.But in the idea I can haveit like that?

And just to know, the PID is used to reach the speed or position and to maintain it the best possible is that it?

Regards :slight_smile:

Yes this is how you can modify the behavior of you motor from the same MCU where you are running SimpleFOC.

If you cut off the power supply at any moment the motor will stop and since since is not energized it will freely move if any force is applied.

Alright, that’s perfect. Easier to use than I thought.

Yes yes, sorry I misexpressed the idea. When I say “break” it is for example = 5. Or a series of commands to brake more or less quickly. Or quite simply a function which would brake more or less strongly.

Where do I need to adjust the PID and motor parameters? In .h or .cpp or can it be done in setting? We have to use the software if we want to determine the correct adjustment values for our engine, is there no function at initialization?

In fact my final idea is more than just spinning the wheel. It is to collect the data of the run to try to improve the response of the system as much as possible.
I’m looking for a topic that talks about this, but I don’t feel like people use the library for propulsion wheels like me.

You can tune PIDs be setting diferente values al compilation time or you con interactively tune it using SimpleFOCStudio

Hi, sorry I couldn’t respond quickly.

I was wondering if I could change the PID value while the wheel was spinning ? I found that there was a PID for the angle and one for the velocity on the software. But I did not see the velocity or angle attribute on the PIDController function in pid.h.

Or is the PID set for all mode ? My use must be unconventional. But if I understand correctly, the idea is that we adjust the PID and that it works whatever mode you choose (angle or velocity). Or is there a PID for each mode ?

The correct function is : PIDController(float P, float I, float D, float ramp, float limit) And do I have to put it in the setup or in the loop ?

Regards :slight_smile:

There are various PIDs … the usual is to setup your PID values at setup() using statements likes this. link this:

    //    -----   TUNNING PARAMETERS -----
    // control loop type and torque mode
    motor.torque_controller = TorqueControlType::voltage;
    motor.controller = MotionControlType::velocity_openloop;
    motor.motion_downsample = 0.0;

    // velocity loop PID
    motor.PID_velocity.P = 0.2;
    motor.PID_velocity.I = 20.0;
    motor.PID_velocity.D = 0.0;
    motor.PID_velocity.output_ramp = 1000.0;
    motor.PID_velocity.limit = 0.5;
    // Low pass filtering time constant
    motor.LPF_velocity.Tf = 0.1;
    // angle loop PID
    motor.P_angle.P = 20.0;
    motor.P_angle.I = 0.0;
    motor.P_angle.D = 0.0;
    motor.P_angle.output_ramp = 0.0;
    motor.P_angle.limit = 50.0;
    // Low pass filtering time constant
    motor.LPF_angle.Tf = 0.1;
    // current q loop PID
    motor.PID_current_q.P = 3.0;
    motor.PID_current_q.I = 300.0;
    motor.PID_current_q.D = 0.0;
    motor.PID_current_q.output_ramp = 0.0;
    motor.PID_current_q.limit = 12.0;
    // Low pass filtering time constant
    motor.LPF_current_q.Tf = 0.005;
    // current d loop PID
    motor.PID_current_d.P = 3.0;
    motor.PID_current_d.I = 300.0;
    motor.PID_current_d.D = 0.0;
    motor.PID_current_d.output_ramp = 0.0;
    motor.PID_current_d.limit = 12.0;
    // Low pass filtering time constant
    motor.LPF_current_d.Tf = 0.005;
    // Limits
    motor.velocity_limit = 50.0;
    motor.voltage_limit = 0.5;
    motor.current_limit = 0.2;
    // pwm modulation settings
    motor.foc_modulation = FOCModulationType::SinePWM;
    motor.modulation_centered = 1.0;

Do not know if it has sense to change PID configutarion except for tuning purposes while you are running your engine.