Optimized TSDZ2 Firmware

mspider65

100 W
Joined
Aug 4, 2019
Messages
196
I start this new thread to share the results of my TSDZ2 Motor Firmware optimization work.

This work started out as a low priority activity, but along the way I realized that there were many things that could be improved, and in the end, I have to say that the result went beyond my expectations.

In this post I just want to share the results of some tests I did to compare the results against the original OSF firmware I started from.

The next three images show the battery current when the motor runs with a fixed duty cycle. In this situation, if the motor is well controlled, the current (and the motor speed) should be almost constant. High current ripples are a typical sign of a poor motor control.

The first image is with the original OSF Firmware, the last two with the new Firmware.
In the first two images the motor is running at the same speed (400 ERPS). In the third image the motor speed was increased to 500 ERPS (close to the maximum nominal speed of 533 ERPS or 4000 rpm) in order to measure a higher current. But also, in this situation the current shows only few spikes

Screenshot_1s.png
Screenshot_2s.png
Screenshot_3s.png

The following images show the results of a test where the current consumption was measured running the motor without load at different speeds.
Testers.png
App-s.jpg
TestMotoreBT.jpg

As you can see, in this situation the current consumption at the same speed is 25-30% lower than the original firmware.

Surely the same result cannot be obtained even in the case of high load. But even if the gain were only 5%, the impact on motor temperature would still be significant since the less current consumption correspond exactly to less Power losses. To carry out measurements under load I would need tools that I do not have available such as a power meter capable of measuring high continuous currents and a training roller capable of measuring power

Due to the cold and snow, I have not yet had the opportunity to test the new firmware on the road for a long time. As soon as the weather allows it, I want to try it uphill and under stress.

At the end of the work I must say that, even if our controller does not allow to do a true Field Oriented Control, by putting in place a whole series of tricks it is still possible to obtain an excellent result that is close to a true FOC.

The code is available on Github on my TSDZ2_ESP32 Project page (TSDZ2-ESP32)

For those interested in the technical details, in the next coming posts I will describe the changes introduced with the new firmware.

Edit:
Technical details 1: SW optimization
Technical details 2: Hall Sensors optimization
Technical details 3: SW motor control parameters optimization
 
Last edited:
mspider65 said:
For those interested in the technical details, in the next coming posts I will describe the changes introduced with the new firmware.
Waiting for it and thanks for sharing!!
 
Do I understand correctly that your modifications are based on the 0.20.0 version of the OSF? And which battery voltage are you using and is the motor labeled as "36V" or "48V"? Would you be able to test your modifications also with casainho's FW version 1.1.0?

I'm curious as I'm now running the casainho's FW with a 52V battery and "36V" labeled motor and the motor kind of stutters and loses power at 400 ERPS (even with field weakening enabled). Would these improvements be available to FW without ESP32 as well at some point?
 
ilu said:
Do I understand correctly that your modifications are based on the 0.20.0 version of the OSF? And which battery voltage are you using and is the motor labeled as "36V" or "48V"? Would you be able to test your modifications also with casainho's FW version 1.1.0?

I'm curious as I'm now running the casainho's FW with a 52V battery and "36V" labeled motor and the motor kind of stutters and loses power at 400 ERPS (even with field weakening enabled). Would these improvements be available to FW without ESP32 as well at some point?

The 0.20.0 version and the new casainho's 1.1.0 version uses about the same code for the motor control.
Not much of the original code is left in my current code, so it's hard to tell where I started with the changes.

In any case, the comparison I made is with the SW equivalent to that of 1.1.0 (PWM freq @ 19KHz).

My motor is a 36V version and i'm also using a 36V battery, but anyway the changes are not specific to the motor type and can be applied to both versions (36V and 48V).
 
In this post I will describe the main changes made to the motor control SW.

I give a short introduction which for some will contain some obvious things.

Motor control is based on precise knowledge of the rotor position. The resolution we have available for the rotor position is 1/256 of a turn which corresponds to about 1.4 degrees. Let me call this unit "step" so that we can understand each other later.

TSDZ2 motor runs quite fast and at the rated speed of 533 ERPS it performs a full electrical rotation in 1.875 ms and moves of 1 step in 1875/256 = 7.32 us.

This means that in order to have a correct control, the ideal SW must control the time factor very tightly and must not introduce errors greater than about 7us (or less if we want to have a good control also over the rated speed).

The SW uses the information coming from the Hall sensors to know the actual rotor position and the first problem of the original OSF firmware is that it samples the state of the Hall sensor each PWM cycle. The PWM frequency is 19 KHz which corresponds to a period of 52.6 us and this means that it detects the transitions of the Hall sensor with a variable delay that can reach up to 52.6us which correspond to about 7 steps at the target speed.

During the PWM interrupt routine, the SW performs various computations and finally updates the PWM counters of the 3 different motor phases.
The delay T with which it performs this operation with respect to the start of the interrupt also has an impact. In fact, during this time T the rotor is moving, and it is essential that what is written in the counters at time T is consistent with the position of the rotor at the same time T.
Unfortunately, this time T is not constant and varies from time to time according to the different branches of the code that are executed. I have measured that this time T can vary up to 15 us which correspond to about 2 steps at the target speed.

Finally, in total the current OSF SW, at the rated speed, introduces up to 9-10 steps of random error which is really significant.

To solve the first problem the new firmware uses the Hardware interrupt to detect the Hall sensor transitions. HW interrupt latency is low (less than 1us) and this means that we can totally remove the Hall sensor detection delay error.

The new SW also uses a dedicated 16 bit counter (TIM3) for the Hall sensor running at 250KHz (4 us resolution) This counter replace the original SW counter incremented by the PWM interrupt (52.6 us resolution).
Note: TIM3 was previously used to generate a 1ms clock and this function is replaced by the 8-bit TIM4 counter previously not used.

To solve the second problem, the new SW breaks the SW algorithm into two parts and triggers the PWM interrupt twice every PWM cycle. The first interrupt activates when the PWM counter is counting down and during this cycle all calculations related to motor control are performed and the second interrupt activates when the PWM is counting up and the first instruction is updating the PWM counters of the three phases using the result of the first calculation.
In this way the delay T is constant, and the value is 26.3 us (52.6 / 2). This delay can now be managed simply by adding a value of 6 to the Hall counter (6 * 4 = 24us) when the SW interpolates to calculate the rotor position.

Now the SW does not introduce significant errors that could influence the motor control and if the Hall sensors are perfect everything should be OK.

But the Hall sensors of the TSDZ2 motor are far from perfect and this part will be covered in a new post coming soon.
 
Last edited:
Curious for next part. I think I did understood everything up to now.
 
:bigthumb:
This sounds very interesting and a real further improvement to motor efficiency!
Is there a way to get this implemented into mbrusas std Display code?
I would think that many people who use mbrusas code are like me and mostly interested in motor efficiency of the osfm and don‘t need / want the additional goodies of the non std displays or BT App options.
Therefor getting your code implemented there would be really, really great.
 
In this new post I will talk about Hall sensors, the errors they introduce and how they can be corrected.

Also this time I will give a short introduction on hall sensors for those who are not familiar with them.

Hall sensors are likewise switches activated by a magnetic field. The TSDZ2 motor has three sensors that are out of phase by 120 degrees and when the motor rotates, they each provide a square like wave which will in turn be out of phase by 120 degrees.
The following image shows the signal sent by the Hall sensors during the rotation of the motor.

Hall.png

As you can see, the sensors provide an information that changes every 60 degrees and when a change in the signal is detected the SW is able to know the exact position of the rotor.

Now the story.
After rewriting the SW as described in the previous post, I did some tests and, although there was a clear improvement, there were still current spikes that shouldn't have been there.

My initial hypothesis was that perhaps the signal from the hall sensors was not perfect with one edge every 60 degrees, but that due to mechanical imperfections or a difference in sensitivity of the three sensors, the duration of the different states was different.

So I decided to measure the duration of the 6 different states of the signal coming from the Hall sensors. It was enough to run the motor at a fixed speed for a while and, using the 250 KHz timer, measure the average duration of each state and of the entire rotation to see if there were any differences.

The result of this test, however, surprised me because, even if the measurements at a given motor speed were perfectly repeatable, the result I obtained changed significantly as a function of the motor speed.

In particular, I noticed a pattern: as the speed of the motor increased, the duration of the 1,4,2 states increased while that of the 5,6,3 states decreased correspondingly

At this point, it was clear that I was missing something. And thinking about it, it became clear to me that there was something related to the time that was missing.

And the first hypothesis that came to my mind is that Hall sensors and all the related circuits probably have some delay in reacting to the variation of the magnetic field, and perhaps this delay is different in the two transitions 0->1 and 1->0

I will call Trise the delay with which the controller detects a variation that causes a transition 0->1 and Tfall the delay with which the controller detects a variation that causes a transition 1->0. The states 5,6,3 start with a delay of Trise and end with a delay of Tfall and the states 1,4,2 start with a delay of Tfall and end with a delay of Trise. For example, if Trise is longer than Tfall, the states 1,4,2 will have a duration increase equal to Trise-Tfall while the states 5,6,3 will have a duration reduction equal to Trise-Tfall.

To verify this hypothesis, I added to the SW the possibility to perform a Hall sensor calibration.
The calibration let run the motor at different speeds, and for each speed calculates the duration of each Hall state and the duration of the full revolution and finally perform a linear regression based on the following formula.

Code:
Cx = slope x Cr + k

Cr is the measured Hall sensor ticks of the complete revolution, Cx is the Hall sensor ticks measured during the state x. The linear regression calculates the value of the slope and k variable for each Hall state.

slope should be a value close to 0,1666 (60/360)

k should be Trise-Tfall for states 4,2,1 and Tfall-Trise or -(Trise - Tfall) for states 5,6,3.

[youtube]0fh6AJjchpo[/youtube]

And this is the result of the regression for my motor.

AppHallCalibration.png

R2 is the coefficient of determination of the linear regression and a value of 1 indicates a perfect fit or that the samples are perfectly aligned in a straight line.

So, the hypothesis was correct and as you can see, there is a huge 21 tick difference or 84us between Trise and Tfall (Hall counter has a 4 us resolution) and also the angle difference between the Hall states is not exactly 60 degrees but varies between 55 and 64 degrees.

This means that the Hall 0->1 transition is detected with a delay which is 84 µs greater than the delay of the 1->0 transition.
This delay could be managed adding a value of 21 to the Hall sensor counter only for the states 6,3,5 when the SW performs the interpolation to calculate the rotor position. In this way we re-align the detected rotor angle to the correct position.

The error in the position of the hall sensors is corrected by updating the reference positions of the different transitions which will no longer be 30,90,150,210,270,330 degrees but will be recalculated based on the calibration result.

Now there is one last problem to be solved. We have accurately calculated the difference between Trise and Tfall but we do not know the absolute value of Tfall or Trise and in the same way we know precisely the relative position of the different hall states, but we do not know with the same precision the absolute position of our reference system. The SW assign a position of 30 degrees to the Hall state 6 but is just an estimate done at the beginning of the OSF project.

This is the last part I will cover in the next post.
 
Last edited:
Good. And yes, I remember to measure my h more noise in the current at high speeds.

Have you ever tough if was possible to estimate the rotor position with the math models done on the STM32 motor control era or such? What I understand for your explanation is that for higher speeds, that error timings are more relevant - may an estimator could make a better angle value??
I must say I do not understand nothing about this but other developers like Stancecoke implemented an estimator based on VESC estimator.
 
casainho said:
an estimator based on VESC estimator.

I think, this is not possible with the slow 8 bit processor, a lot of math has to be done....
But you could use a PLL instead of extrapolating the rotor position from the last hall event.
I did this in the Lishui-project branch "reverse and regen", with this you calculate the "speed", saying the angle increment per PWM cycle.
The hall events are only used for tuning the PLL.
It works very well, but you have to use different gains for different motors, therefore I haven't pushed it to the master. This would be no problem in the TSDZ2 project, as there is only one motor :wink:

Looking forward to see @mspider65 's solution :)


regards
stancecoke
 
stancecoke said:
casainho said:
an estimator based on VESC estimator.
I think, this is not possible with the slow 8 bit processor, a lot of math has to be done....
But you could use a PLL instead of extrapolating the rotor position from the last hall event.
I did this in the Lishui-project branch "reverse and regen", with this you calculate the "speed", saying the angle increment per PWM cycle.
The hall events are only used for tuning the PLL.
It works very well, but you have to use different gains for different motors, therefore I haven't pushed it to the master. This would be no problem in the TSDZ2 project, as there is only one motor :wink:
Thanks for the help.
 
casainho said:
Good. And yes, I remember to measure my h more noise in the current at high speeds.

Have you ever tough if was possible to estimate the rotor position with the math models done on the STM32 motor control era or such? What I understand for your explanation is that for higher speeds, that error timings are more relevant - may an estimator could make a better angle value??
I must say I do not understand nothing about this but other developers like Stancecoke implemented an estimator based on VESC estimator.

I don't know about the STM32 project and I don't even know the VESC estimator. As soon as I have some time I try to read up and see if I can understand something even if I have little familiarity with mathematical models.

However, I think that part of this deviation from the ideal behavior is caused by mechanical imperfections and the fact that, if the Hall sensors are not of excellent quality, they have a different sensitivity from sample to sample.

This type of errors, being random, cannot be predicted with a model but only calculated with an experimental approach.
 
mspider65 said:
casainho said:
Good. And yes, I remember to measure my h more noise in the current at high speeds.

Have you ever tough if was possible to estimate the rotor position with the math models done on the STM32 motor control era or such? What I understand for your explanation is that for higher speeds, that error timings are more relevant - may an estimator could make a better angle value??
I must say I do not understand nothing about this but other developers like Stancecoke implemented an estimator based on VESC estimator.

I don't know about the STM32 project and I don't even know the VESC estimator. As soon as I have some time I try to read up and see if I can understand something even if I have little familiarity with mathematical models.

However, I think that part of this deviation from the ideal behavior is caused by mechanical imperfections and the fact that, if the Hall sensors are not of excellent quality, they have a different sensitivity from sample to sample.

This type of errors, being random, cannot be predicted with a model but only calculated with an experimental approach.
Thanks. Maybe we can discuss this new ideas in the end of your presentation. I hope you can continue.
 
mspider65 said:
I don't even know the VESC estimator.

some read for long winter nights ;)

http://cas.ensmp.fr/~praly/Telechargement/Journaux/2010-IEEE_TPEL-Lee-Hong-Nam-Ortega-Praly-Astolfi.pdf

regards
stancecoke
 
endlessolli said:
:bigthumb:
This sounds very interesting and a real further improvement to motor efficiency!
Is there a way to get this implemented into mbrusas std Display code?
I would think that many people who use mbrusas code are like me and mostly interested in motor efficiency of the osfm and don‘t need / want the additional goodies of the non std displays or BT App options.
Therefor getting your code implemented there would be really, really great.

The code is open source and available to everyone. I hope that the explanations I have provided will also help those who want to use these optimizations in their projects.
 
In this third post I will explain how I estimated the Tfall value discussed in my previous post and the correct angular reference of the Hall states.

In practice, it is a matter of calculating an offset in degrees with respect to our angular reference estimated at the beginning of the OSF project and a Hall tick offset with respect to an initial value defined empirically.

Let's start for example with a Hall Offset value of 8 for states 1,2,4 and a value of 29 for states 3,5,6 since in our previous calibration we calculated a difference of 21 ticks between Trise and Tfall.

And let's start using the same rotor offset angle of 10 steps defined in the original OSF firmware.
#define MOTOR_ROTOR_OFFSET_ANGLE 10

Once fixed these values, the idea is again to do a linear regression running the motor at different speeds.
For each speed we then want to find the Phase angle shift with which the battery current is minimum.

Unfortunately, the current measurement provided by the controller is not accurate and and so I used a multimeter.
I was able to do a precise current measurement since I have an app that connect to the multimeter (it has a BT interface) and calculates a rolling average over many samples.

I have also added a Motor Test tool to my Android App with which it is possible to change the phase angle and the duty cycle step by step.
MotorTest.png

In this way it is possible to change the phase angle and then adjust the duty cycle in order to reach the target reference speed.

These are the mesures taken.

CurrentMeasures.png

And this is the result of the regression.

AngleRegression.png

Again, the linear regression is precise (r2 = 0.999) and, according to the results, the correct motor parameter should be:

Rotor Offset = 4
Hall 1,2,4 Offset = 23 (92 us)
Hall 3,5,6 Offset = 44 (176 us)

And these are the values I used to compare with the original OSF firmware.

And regarding our Hall sensors (remember that the SW adds a constant delay of 26.3us):
Tfall = 92-26 = 66us
Trise = 176-26 = 150us
 
This thread has really improved my knowledge of motor control... the wisdom here is quite extraordinary!

Very interested to hear if this improved motor control firmware brings any noticeable changes when riding.
 
Facinating, and even though i have little understanding of the technology, i imagine apparently good gains in motor efficiency.
A suggestion if i may..i
Rather than let the weather dictate your testing schedule, why dont you just buy a $50 indoor bike trainer stand to allow you to better trial and test whilst monitoring multiple parameters of the motor under load..
 
Hillhater said:
Facinating, and even though i have little understanding of the technology, i imagine apparently good gains in motor efficiency.
A suggestion if i may..i
Rather than let the weather dictate your testing schedule, why dont you just buy a $50 indoor bike trainer stand to allow you to better trial and test whilst monitoring multiple parameters of the motor under load..

Thanks,
at first I also looked for a trainer, but I didn't find any at a reasonable cost that was compatible with my mtb (29 inch, boost)
In the end, however, I managed to get all the information I wanted.

Now the weather is improving and the snow is melting, and as soon as the maintenance of the motor is finished (now it is completely disassembled on my workbench) i will start to ride with the new firmware.
 
@mspider65, I am still thinking on the differences on the signal of the hall sensors... I wish there was a better was to automatically do the calibration and so avoid one more configuration to user do... - I will asks to some colleagues more experienced about this problem.
 
casainho said:
@mspider65, I am still thinking on the differences on the signal of the hall sensors... I wish there was a better was to automatically do the calibration and so avoid one more configuration to user do... - I will asks to some colleagues more experienced about this problem.

I think it's not a big deal to do it even without an Android App.
The app is especially useful to have everything under control and to check the result.
The procedure is similar to the one used to calibrate the PAS in advanced mode, there is just a little more math to do.

Probably it is possible even without a specific procedure but it is little more complex since it is necessary to sample the Hall counters at different motor speeds ...
 
I don't see why this couldn't be fully automated apart from the unreliable battery amp sensing from the controller?

Maybe this could be soved by the right filtering, since only a relative measurement is needed?
 
This is a really intriguing discussion. I had very similar problems when I was writing my code.

I wanted to keep my code portable, so although I had access to the timer 3/4 I chose not to use it, instead relying on sampling the pins at the adc conversion complete interrupt. The other problem with the interrupt pin/timer count is that normally hall sensors are buried inside motors and the noise in their lines can be terrible.

I count the number of pwm pulses between hall sensor state changes, and use this along with a hall table to determine the position.

Originally I did this by interpolation, but this resulted in the jitter mrspider describes and terrible performance.

Later I moved to a crude pll - estimating the error each time I detect a hall state change and subtracting this error (with a correction factor of about 0.2) from my pll increment.

The result is no abrupt changes in angle, and a hugely reduced sensitivity to errors in hall sensor placement. Combined with a more accurate way of determining hall sensor position (basing it on the timing of edges is prone to error, much better to integrate the angle for each state over a revolution) and pll gains set reasonably I went from "just about ridable with frequent over current" to "beautiful sinusoids" and about 2x the current before tripping.

I only have a few motors though, and my time has been under huge pressure over there past few months so I've not really had time to progress this. There are other massive holes in my firmware; I have no svpwm (I'm bottom clamping), no ability to change pid parameter except through reflash, no meaningful UI... So I wouldn't try to port my code (you're welcome to look at it though, the estimator runs pretty fast and uses uint16_t for the angle); I'm getting 35kHz pwm and running FOC every cycle with time left over for an rtos on an f303 @72MHz...

Stancecoke has one of my controllers coming to him, I'll be intrigued to know how it goes for him.
 
This paper might be of interest -
http://koreascience.or.kr/article/JAKO201620240596781.pdf

There is a method of calculating the relative hall errors in real time, and an absolute error using back-emf. What’s interesting is that the absolute error is only calculated on startup, and they note that it was consistent across restarts. Meaning that possibly could be a manually set value (initial “tuning”) and then have the algorithm correct for the relative position errors real time.

I must admit some of the maths is beyond me so it might not be a usable approach. And/or the processing might be too involved. There are a couple of divide-by-3’s, but from memory that can be accomplished to a reasonable level of precision without wasting too many cycles by sum’s of bit shifts.

The other thing I can’t really get from the paper is if it only applies to a steady state speed.

I’m really keen to try mspider65’s firmware updates, but my display is an 860c so not sure how to at this stage. It’s unfortunately beyond my coding skills to port these changes back into casainho’s code that works with that display.
 
Back
Top