I know that SimpleFOC is focused on sine wave commutation. It is smooth and powerful. This all is valid if I use the library and the motor for positioning or for slow movement (as in gimbal applications).
I also would use the sine wave for acceleration from 0 RPM where older implementations use open-loop till about 500 RPM. But when speed gets higher sine wave is inefficient and gives a high load to the mcu. Hence, the outer control-loop is slowing down. And whenever I make some calculations in the loop() I get in trouble with the behaviour of the motor.
OK, using a blackpill eliminate most of the problems, but in Germany we call that solution “shooting with cannons on sparrows”.
Do you think it is easy and possible to implement block commutation?
I talked to Antun about this yesterday. We think it would be easy to implement. Would need to add another switch case in
setPhaseVoltage(). I expect it would be about 10-20 lines of code.
The algorithm would have two parts.
- establish which of the 6 commutation sectors we are in
sector = (electrical angle % (2PI / 6)
- set Ua, Ub, Uc to be appropriate value for that sector (+ multiply by Uq)
This gist I wrote a week or two ago might help to show relationship with sectors and Ua, Ub, Uc. It is for 6PWM but 3PWM will be quite similar.
A couple of complications:
- switching between modulation types on the fly would require new block/six_step modulation to be aligned with existing modulations (Sine, SpaceVector) otherwise the transition won’t be smooth
- the auto calibration might need tweaking (I think it’ll work as the calibration steps are 60 degrees which is the same distance as each of the 6 commutation steps)
This might be a good
first commit if someone is interested in implementing.
@Owen_Williams I guess there is all said by your comment. I would implement it if I could. But frankly speaking I’m to bad in coding. This is the disadvantage of a management position. My C++ capabilities are faded out over the last 20 years
It is very important that the block-commutation keeps in-sync with the other commutations.
In many projects I saw the guys struggling with the challenge of combining full/over-torque start, perfect control and efficiency at higher load/speed.
Usually you need two sensors. One for low-speed (usually a magnetic) and another for high-speed (usually halls).
That leads to my conclusion: Probably it could also an option to switch not only the setPhaseVoltage but in some cases also the sensor type. We could init all sensors we intend to use and switch them.
Another idea of implementation is the reduction of items in the _sin - list to 1. Or using an alternative list or value. List might be better to keep the data-structure. But probably I have a weak overview to the SimpleFoc library.
Thank you for thinking about it.
As Owen suggested, it is not a big change and it might be implemented in the version 1.7 of the library.
Basically the simplest version would be to round the _sin() function (not too efficient one though).
I will try to implement a table for block commutation and I’ll make sure to align it with the sine wave.
I am actually not sure that either of the two is really a problem. In theory zero for sine/space vector will be zero for the block commutation as well. The only difference that can happen maybe is that the voltage vectors are commutated in different directions. But the alignment should not be a big problem.
Anyway, I think it is a cool (and not too complicated) addition to the library and Im happy to spend some time on it.
What are the conditions we monitor to set the changeover point? How? Assuming it can be a dynamic point, not a static RPM determined at compile time.
If CPU load is the determining factor, is loop period/RPM a sufficient metric?
If motor intrinsic properties determine the changeover, is there a programmatic method better than trial and error?
Might need to build in some hysteresis to prevent commutation mode oscillation around the changeover point.
@slomobile: Every of your arguments is absolutely worth to think about.
Hysteresis is an option. At the other hand what would be the problem of a switch at every loop of the outer cycle? Only a challenge for the PID But hysteresis would be more elegant.
The usual changeover condition is RPM given at compile time. But this is not smart. For the first step I would suggest a property that can be set in the setup() and in loop() to speak in the wording of the arduino IDE. If you have an idea about how to make it more smart please tell.
There are some motor intrinsic properties that determine the changeover. (moment of inertia, PP…) But it could also just the decision of the designer to switch in block commutation when perfect control isn’t needed anymore. It is also not efficient to make a sine wave commutation at higher speed.
I think the main problem is that as the RPMs get high the encoders, and other parts of the system aren’t fast enough any more.
I have a Excel sheet I made to help me understand these timing related questions, but I can’t seem to attach Excel files here… I’d love to share it.
I think there are 2 problems:
- fast turning motors typically have low winding resistances, and SimpleFOC currently has no current limiting - so you would have to use a driver with this function to ensure you don’t burn up your MOSFETs when SimpleFOC is holding a position, for example.
- as the RPM increase the encoders/magnetic sensors can’t keep up, so reliably detecting the time to switch to the next commutation step is a problem.
It could be solved by adding a HallSensor which drives commutation based on interrupts from Hall Sensors, but this is currently not a part of SimpleFOC.
Or it could maybe be possible using current measurement, to monitor for the zero crossings in the BackEMF, but AFAIK this is implemented by setting one of the phases to non-connected (both MOSFETs off), so can only work with specific hardware. But again none of this is currently implemented in the library.
By adding a new modulation scheme for BlockCommutation in addition to SinePWM and SpaceVectorPWM one could quickly add 6 step commutation, and potentially reduce calculation times per iteration, but I don’t think it would solve the problems mentioned above.
It would be handy for the changeover algorithm, and any user to know when his encoders can no longer keep up, and/or when his processor can no longer handle the rate of interrupts gracefully.
Either can be discovered programatically, but such function is of little use (waste of code space) in the finished user program. Perhaps a compile time #define StressTest conditionally compiles the stress test code to run alongside user code. It sounds easy but there are so many ways for the user to break it. Is it reasonable to ask a user to run once with StressTest defined, write down a few numbers, then load the real sketch with the limits defined? Limits for that specific configuration of processor, encodor, motor, and user code. Perhaps we could even have them temporarilly install a shunt resistor into a female header during this StressTest sketch to determine duty cycle which equates to a desired current limit.
I like the idea of many commutation options. We can see what calculations are common to several modes and make those values static(global).
I wouldn’t put such things in the library itself - that will create all kinds of support problems, and how to provide feedback about these error conditions?
I’d put this kind of thing either offline - I made an Excel sheet, I’m sure many people have done the same. When designing your system and choosing components, you can use external tools to check design choices. It could be built into the SimpleFOC website for example
Or I would make it part of an PC-hosted configuration utility. Various ESC / Motor drive solutions come with a “Tuning App” that allow you to set parameters and check values. Someone could create a SimpleFOC tuning app - and these kinds of limit detection and stress tests could be built into that…
You are correct about the support problems. I originally wrote the StressTest post suggesting a seperate StressTest example sketch, then realized it wouldn’t take into account user code. So I changed it to conditional compilation. After watching SpaceX I’m appreciating the concept of “all up” testing.
A spreadsheet wont tell you at what RPM your micro begins missing interrupts. Some hardware may not have published specs, or the user can’t find it.
I like the tuning app idea. Could we just use the VESC tool?
Yeah, that’s one of the tools I was thinking of…
But I doubt very much that we could use it with simpleFOC… each tuning app is very specific to the algorithm/library being tuned, and probably also to the hardware used… that’s why its “tuning” - handling the fine details that the general solution cannot…
Its open source https://github.com/vedderb/vesc_tool
I meant fork it, keep the interface as much as possible, swap the guts where needed, and use future vesc_tool bugfixes for maintenance to the extent possible. Still lots of work, but better than starting from scratch.
You don’t need sensors for FOC and you don’t need sensors for block commutation. You just need a microcontroller with enough analog inputs. And DSP capabilities. The ST G431 evaluationboard has these and so does Microchip. Unfortunately both are not supported by SimpleFOC. ST hardware you get almost free, but they make you pay ( a lot ) for the software. Microchip chips cost more, but they give the software away for free.
Some months have passed, and you could now take a look at the SimpleFOCStudio… it is work in progress, but evolving towards a Vesc_tool-like solution.
You may not require sensors for FOC in general, but many applications require them to detect motion from external sources. I need very repeatable low speed and starting behavior without extraneous startup motion. My quadrature encoders are on gearbox outputs as close to the end effector as possible. Gear backlash shows up in software as jitter between commutation and load encoder upon acceleration, so it is handy to have them managed in the same controller. This is useful for predictive maintenance. When jitter gets larger over long periods, the gears are wearing in. If jitter reduces over short periods, the gearbox may be overheating. Hot gears expand and close the gap. If jitter changes are accompanied by higher current draw, its time to open it up, clean, inspect, and change out the grease. If I can monitor trends in the direction and degree of jitter, I can modify commutation to accelerate or decellerate dynamic loads more smoothly. This has applications in active suspension. Comparatively larger than usual differences between sensorless computed motor position and load encoder indicate the lubrication layer has collapsed and the mechanical system is overloaded even if the electrical system is not.
That reminds me of my father. 50 Years ago computers were very rare. My father worked with large diesel engines of which he could tell if it needed maintenance by just listening to them. Which was special, as he had otherwise bad hearing. I think you could pick up gear-noises with a small microphone and analyse them with tensorflow.
Wow. Similar experience. Off-topic, I know… I person I knew very very long time ago (that was back in late 1970s) got hired by a well known US steel smelter (US steel was really big back then) he could tell the steel composition by running the sample over a grinder looking at the sparks. A fast-acting industrial spectrophotograph back then cost nearly a million and needed lab and trained lab scientists. They replaced everything with one single guy that literally stuck the slag probe into a grinder and in a few seconds ratted out the content withing a few percent error. Talk about job security.