2025-12-16 9:08 AM - edited 2025-12-19 6:35 AM
Hello,
In a seperate post I received help allowing my B-G431-ESC1 to accept PWM input from an ESP32 to vary the speed of a 24V hoverboard motor with hall sensors using FOC.
My goal now is to be able to vary the direction of the motor's rotation by varying the PWM.
Given that the acceptable range of values is 1060us to 1860us, I had hoped to be able to do this by having values 1060us to 1460us correspond to rotation in one direction, and the values from 1460us to 1860us correspond to rotation in the opposite direction.
I was unsure of any official documentation on bidirectional control, but i noticed that when using the motor pilot to manually set speeds, I was able to set the speed reference to be both positive and negative. I found a github with a guide on how to implement bidirectional control and after following the steps it mentioned, I found that when the motor driver was viewed on the motor pilot, the speed reference did indeed switch between positive and negative values with the appropriate PWM input.
However, when the speed reference was negative, the motor would attempt to rotate in the positive direction, crash, restart, attempt again, crash again, etc...
I have written this post to ask for help in resolving this issue of the speed reference showing up as negative, but the motor not actually being driven in the correct direction and then also crashing when it attempts to
Or if there were any easier ways to achieve the bidirectional control I described, I would also be very grateful to hear of how I should go about implementing this :)
the modifications I have made are as follows:
int16_t hDirection;__weak void MCI_SetDirection(MCI_Handle_t *pHandle, int16_t hDir)
{
#ifdef NULL_PTR_CHECK_MC_INT
if (MC_NULL == pHandle)
{
/* Nothing to do */
}
else
{
#endif
pHandle->hDirection = hDir;
#ifdef NULL_PTR_CHECK_MC_INT
}
#endif
}__weak void MCI_ExecSpeedRamp(MCI_Handle_t *pHandle, int16_t hFinalSpeed, uint16_t hDurationms)
{
#ifdef NULL_PTR_CHECK_MC_INT
if (MC_NULL == pHandle)
{
/* Nothing to do */
}
else
{
#endif
if (pHandle->hDirection < 0)
{
hFinalSpeed = -hFinalSpeed;
}
else
{
hFinalSpeed = hFinalSpeed;
}
pHandle->hFinalSpeed = hFinalSpeed;
pHandle->lastCommand = MCI_CMD_EXECSPEEDRAMP;
pHandle->hDurationms = hDurationms;
pHandle->CommandState = MCI_COMMAND_NOT_ALREADY_EXECUTED;
pHandle->LastModalitySetByUser = MCM_SPEED_MODE;
#ifdef NULL_PTR_CHECK_MC_INT
}
#endif
} if(pHandle->Ton_value < (pESC_params->Ton_max + pESC_params->Ton_min)/2 ){
MCI_SetDirection(pMCI[pESC_params->motor], -1);
}
else{
MCI_SetDirection(pMCI[pESC_params->motor], 1);
}motor workbench: Version: 6.4.1 Build: 250722.154358
STM32 cubeIDE: Version 2.0.0
STM32 cubeMX: Version 6.16.0
Board: B-G431-ESC1
Motor:
I have been unable to find a spec sheet for this motor, I believe it comes from the zimx hb1 hoverboard. Below is the information I currently have about it.
24V, 5Apk, 15 pole pairs, max RPM 600,
2025-12-17 2:27 AM
My recommendation would be to first confirm if the motor runs in the reverse direction in the entire range of PWM input without any issues, then you can go for bidirectional control. For the reverse direction try to change as below.
__weak void MCI_ExecSpeedRamp(MCI_Handle_t *pHandle, int16_t hFinalSpeed, uint16_t hDurationms)
{
#ifdef NULL_PTR_CHECK_MC_INT
if (MC_NULL == pHandle)
{
/* Nothing to do */
}
else
{
#endif
pHandle->lastCommand = MCI_CMD_EXECSPEEDRAMP;
pHandle->hFinalSpeed = -hFinalSpeed;
pHandle->hDurationms = hDurationms;
pHandle->CommandState = MCI_COMMAND_NOT_ALREADY_EXECUTED;
pHandle->LastModalitySetByUser = MCM_SPEED_MODE;
#ifdef NULL_PTR_CHECK_MC_INT
}
#endif
}that is negative of hFinalSpeed and verify if it runs, i assume that as per the ST recommendation you are running in FOC sensor less mode.
2025-12-17 4:38 AM - edited 2025-12-18 1:18 AM
Hello,
I am currently running with STO-PLL as the main sensor with hall sensors as an auxiliary sensor.
I believe I did try this and had the speed references be only negative values, rotate in the same direction as when the values are positive and crash and restart the whole time it was powered.
I won't be able to work on it today so testing and further responses from me will be delayed. Thank you for the help you have already given and thank you for taking a look into this task :)
EDIT 18/12/2025:
Back working on it for a little bit today, and yeah I tried editing the code as described and it rotates in the same direction as normally and then crashes and restarts continually.
2025-12-18 3:53 AM - edited 2025-12-18 3:54 AM
I tried a few different things to fix this but ultimately they didn't work, mainly feel stumped and confused by the fact that the pilot recognises the negative speed reference I supply it.
The current angle I was beginning to explore was editing line 177 in revup_crtl.c
pHandle->hDirection = -hMotorDirection;My thinking was that since the revup was defined for a positive direction, if it was made negative, then maybe the opposite of what I was experiencing would happen, i.e. negative speed commands would all come through fine and positive speed commands would rotate in the negative direction, crash, restart, etc... And if that worked then I could have the driver be restarted whenever I needed to switch directions and have the revup occur in the appropriate direction.
Instead what I observed was that with negative speed references, the motor would begin to move in the negative direction, then slow down and begin shaking back and forth very quickly, then crash, then repeat. Then for positive speed references, they operated as normal, in the positive direction with no issues.
2025-12-19 8:11 AM
Tried some more things but no progress. My next thoughts were to try and alter methods that are more directly powering the motor windings. I tried looking into the mc_tasks_foc.c file but I wasn't sure exactly what to look for and what would actually affect the motor running. I also tried seeing what information I could gather from the registers in the motor pilot but again, not exactly sure what to look for. I did get pictures of the status and fault flag registers. The status register alternates between several states. It starts off idle, enters the start state, briefly enters the run state before reentering the idle state and repeating. A few times it does reach the switch over stage but also seems to crash. The fault register during all of this remains at 0.