KT motor controllers -- Flexible OpenSource firmware for BMSBattery S/Kunteng KT motor controllers (0.25kW up to 5kW)

Stancecoke, some important questions:
1. why are you using that LCD model?
2. why are you using that torque sensor model?
 
1. Because I own one. :) As mentionded before, I prefer Lishui controllers and therefore I have Kingmeter Displays. But in general I don't like any displays/switches at my handlebar. With the torquesensor there is no need to switch anything, except the main switch of the battery. (OK, I live in a plain landscape)

2. I have tested several torquesensors within the last years, see the wiki in the german forum.
I would recomment the sempu sensor as first choice at the moment.

The sensor from BMSBattery (or from other sources) has the big advantage, that it works with the 5V power supply from the PAS-connector
Other sensors usually need a higher supply voltage.
Most controllers have a suitable intermediate voltage on the board (so the S06S with 15V at the LM317), but normally no wire with this voltage is led out of the housing.


regards
stancecoke
 
stancecoke said:
1. Because I own one. :) As mentionded before, I prefer Lishui controllers and therefore I have Kingmeter Displays.

2. I have tested several torquesensors within the last years, see the wiki in the german forum.
I would recomment the sempu sensor as first choice at the moment.

The sensor from BMSBattery (or from other sources) has the big advantage, that it works with the 5V power supply from the PAS-connector. Other sensors usually need a higher supply voltage.
So I would like to make some strategic decisions here. To have a better quality firmware/system, I prefer to focus on less hardware combinations/options.

1. Maybe you will be the only user for that Kingmeter Displays. I think is preferable to choose only one display and the Kunteng is the natural choice (is the one supported by original firmware), is cheap and available on BMSBattery on a KIT with S06S.

Less if/defs code on the firmware will make it easier to maintain, with less potential bugs, which increase quality. Also for our own mobile app/cycle computer, we should maintain the same protocol to be compatible with the LCD and extend it but not change the base -- we will have much more flexibility on the mobile app/cycle computer. The idea is to keep a simple and robust interface to the outside, and if possible only one.

By the way, BMSBattery sells an S06S with bluetooth module, for 28€.

2. Again, I prefer to go with the BMSBattery for the same reasons of 1. BMSBattery sells a kit with S06S + LCD3 + torque sensor.

At the same time I think an advantage of OpenSource is to able to support more options/hardware, etc however that is cost/time. Since there isn't yet a good stable version of firmware, I would prefer to go small/simple first to have that stable and good documented version. Maybe later start adding that options, ideally I think it should have many options.

I think the throttles, brakes, PAS, torque sensors may be more or less equal between them. The LCD stick with LCD3/LCD5. Put our efforts instead to support different motors and battery packs voltages(although here probably 24, 36 and 48V are the standard).
I would like to have a hardware pack, with a good documentation on how to connect them (this is a big fail from BMSBattery) and configure the firmware on java application.

So, to resume:
- Target to have a good quality as possible firmware, with not many hardware options.
- I want to keep only the code for Kunteng LCD3/LCD5. I will implement that using your code, because the structure should be near, like using the UART interrupt for receiving, etc.
- As for the torque sensor, I don't know but maybe the code is just the same
- Will implement your update_setpoint () on throttle_pas_torque_sensor_controller (). Some code is already implemented, like battery under/over voltage protection, on the motor_controller_high_level ();
 
casainho said:
To have a better quality firmware/system, I prefer to focus on less hardware combinations/options.
I agree, but consider that we have a full working solution for a bluetooth-connection to a professional smartphone app with the J-LCD protocol. I don't know, if the Kunteng bt-module/App system is stable and uses the "standard" LCD3/LCD5 protocoll....
(By the way, I read that you are not really happy with your Kunteng Display :wink: )

casainho said:
- As for the torque sensor, I don't know but maybe the code is just the same
Yes, the signals are the same for most sensors, we just have to adjust the calibration values.

casainho said:
Will implement your update_setpoint ()
Thank you for that! I'm still concentrating on getting my motor run with your recent motor code at the moment. It is to be feared that we don't have a stable solution for a wide variety of different motors yet.
BTW: is the start of the recent SVM table related to the zero crossing with positive edge of phase A current?!
edit:
obviously not,as I found now.
my interpretation: the first value in the SVM table, belongs to 30° rotorposition if zero crossing with positive edge of phase A current is definded as rotorposition = 0°

again edit: I found that your SVM Table isn't based on the sinodial functions used in the upper link. If I add substract Phase B values from Phase A values in your .ods table, I get a sine wave without shift relative to Phase A values.... But with your table you get no higher amplitude of the sum, but that is the idea of SVM?!

I'm still wondering why the switching to sine mode at the beginning of case1 (rotor position =0°, 240° from the switch case + 300° from the MOTOR_ROTOR_DELTA_PHASE_ANGLE_RIGHT + 180° from the ui8_position_correction_value, 240+300+180= 720 =2*360=0) works, as the 6-Step pattern assumes, the switch should happen (again edit:) 90° earlier?!
The sketch shows the currents in a (in my eyes) syncronized state...

regards
stancecoke

phaseCurrent syncronisation-90.JPG
 
stancecoke said:
casainho said:
To have a better quality firmware/system, I prefer to focus on less hardware combinations/options.
I agree, but consider that we have a full working solution for a bluetooth-connection to a professional smartphone app with the J-LCD protocol. I don't know, if the Kunteng bt-module/App system is stable and uses the "standard" LCD3/LCD5 protocoll....
(By the way, I read that you are not really happy with your Kunteng Display :wink: )
Makes sense it uses the same protocol, just like that other one you use. The app is available here with name "KTSmartBicycle" - seems that was updated 10 days ago: https://www.pgyer.com/jofl

I am happy with Kunteng Display, it is cheap and works ok. But I would prefer something with graphic display and with the same STM8 or other that we could program -- seems we need to do our EBike cycle computer (but also do the mobile app; a lot of things to do). The LCD you use is very similar, the same information and options, like the error codes, etc.
stancecoke said:
casainho said:
Will implement your update_setpoint ()
Thank you for that! I'm still concentrating on getting my motor run with your recent motor code at the moment. It is to be feared that we don't have a stable solution for a wide variety of different motors yet.
We need to focus on that!! We need to get more and more knowledge.

stancecoke said:
BTW: is the start of the recent SVM table related to the zero crossing with positive edge of phase A current?!
I'm still wondering why the switching to sine mode at the beginning of case1 (rotor position =0°, 240° from the switch case + 300° from the MOTOR_ROTOR_DELTA_PHASE_ANGLE_RIGHT + 180° from the ui8_position_correction_value, 240+300+180= 720 =2*360=0) works, as the 6-Step pattern assumes, the switch should happen 90° earlier?!
The sketch shows the currents in a (in my eyes) syncronized state...
While I still used a lot of time, I also did as quick as possible. Don't take my code as without errors, just because it works for me :)
 
stancecoke said:
I'm still wondering why the switching to sine mode at the beginning of case1 (rotor position =0°, 240° from the switch case + 300° from the MOTOR_ROTOR_DELTA_PHASE_ANGLE_RIGHT + 180° from the ui8_position_correction_value, 240+300+180= 720 =2*360=0) works, as the 6-Step pattern assumes, the switch should happen (edit:) 60° earlier?!
The sketch shows the currents in a (in my eyes) syncronized state...
I don't know. But I think the angle with 6 steps don't need to be the same as on sinewave - maybe it is like 30 degrees or 10 degrees difference...
Are you using an oscilloscope? because you can then see the phase current and the hall sensors.
 
Another improvement to my developer tools :)

[youtube]6JcclC9Pod8[/youtube]

This training roller offers some degrees of resistance (magnetic brake inside the roller) which is great to put load on the motor. With another trainer on back wheel, I can even test the bicycle in full, like using a torque sensor. I bought it locally on Decathlon, for about 100€.
 
I implemented the code for the following errors:
- battery under volt: // motor will stop and battery symbol on LCD will be empty and flashing
- motor over current: // motor will stop and error symbol on LCD will be shown
- throttle error: // verify if throttle is connect; if error: error symbol on LCD will be shown

I also corrected cruise_control.

Here is the actual code for throttle_pas_torque_sensor_controller (); that is called on main loop every 100ms:
 
stancecoke said:
Thank you!

Suggestion for a name:

C#ROME-B

Custom ROM for E-Bikes
Speak as two words: CHROME- BEE
I like the idea, I just don't like using symbols, as I think they are hard to memorize and also bad for online search motors. I will be back to this subject later.
 
After trying for another two hours, I have to say, that I can't get your code running on my motor, even with exactly the same compiler-options as in the test ADC branch.
I'm not sure if it's the right way, we are going actually, as even the code you 've compiled with Linux doesn't work properly for me. I think we have to go 5 steps backwards an start again from the last stable code that worked for both of us...

sorry
stancecoke
 
stancecoke said:
After trying for another two hours, I have to say, that I can't get your code running on my motor, even with exactly the same compiler-options as in the test ADC branch.
I'm not sure if it's the right way, we are going actually, as even the code you 've compiled with Linux doesn't work properly for me. I think we have to go 5 steps backwards an start again from the last stable code that worked for both of us...
Wait, the issue is that ADC phase B is always near 127? Is just that?
 
What I vwrieid today:
1. transition to sinewave sometimes fails...
2. duty cycle should be reduced when entering in sinewave as the speed and current increases a lot (in fact after speeds reduces because of the speed controller and keeps on sinewave because of the big gap of histeresys)

Stancecoke, maybe 2. Is not helping you...
 
three things, where I'm not happy with your .hex:

1. Motor makes a noisy jump when switching on the system
2. displayed correction angle stays at 127 all the time
3. efficiency is bad (may be related to #2)

Regards
stancecoke
 
stancecoke said:
three things, where I'm not happy with your .hex:

1. Motor makes a noisy jump when switching on the system
2. displayed correction angle stays at 127 all the time
3. efficiency is bad (may be related to #2)
1. As I found, not even my transition to sinewave works everytime and also there is a big difference/jump higher in speed and current.

Let's compare our motors. My Q85 24V 328RPM, I expect to run at a wheel speed of 29km/h and will then run at 390 erps. Can you please give this data about your motor?

2. Very strange.
3. Yes. On my Q85 I found that if I disable FOC with motor without load, makes no big difference, I can't see any increase on the current. And this result makes sense because on this situation, the value of angle that FOC adjust are just a few values.
 
stancecoke said:
For #1 I mean switching on the battery without touching the throttle.
Can you please record a video, trying a few times?Try also switch on but with brakes active.
 
Stancecoke, you may have right. Now that I can test with a constant load, seems that at same speed on sinewave is much less efficient than with 6 steps - I need to do some good tests and figure out what is wrong. Will start tomorrow.
 
ThierryGTLTS said:
Interesting, I would like to know why it's less efficient in sinewave.
Was very quick tests as I am not permitted to develop on weekends.......

Was clear for me that my motor switchs no sinewave arround 14km/h. Just before were using 1A and just after jumps to 2A!!! So really bad efficency. Something is wrong for sure.
 
I've done a lot of thinking and drawing now :?

After I had shifted all the correction angles to zero (See the new branch at github) it was more transparent to see what has to happen to make the motor run properly.

Definition: The rotorposition is zero when phase B current is crossing zero with a falling edge. This is the point that we use to do the FOC, speak where we read the electric feedback of the motor.

regards
stancecoke
 
I think my approach will be:
- is there any angle value that current is equal or lower than 6 steps (maintain the same velocity, power output)? To find, I will disable the FOC and adjust manually the angle (sending UART commands), while motor running with the speed contoller to maintain the same speed, but will ajust the duty_cycle automatically to get that speed, meaning that will automatically adjust the power input to maintain the same power output -- this is correct, right??
- hopefully, I will find that is possible and then I need to find how to put FOC working to automatically adjust that angle value and so get the max efficiency value
 
I think you have to edit your SVM Table first. Otherwise you will never get a zero crossing of current at a hall sensor interrupt....

regards
stancecoke
 
stancecoke said:
I think you have to edit your SVM Table first. You have to take care of the 90° phase shift between voltage and current. Otherwise you will never get a zero crossing of current at a hall sensor interrupt....
I don't understand but I would like to explain how I see it, maybe I am not think correctly:
1. On pwm_apply_duty_cycle (uint8_t ui8_duty_cycle_value), I take as input the duty_cycle value and scale using that, the amplitude of the sinewave values from the SVM table. That table have all the values for a span of 360º.

I apply to phase A the table value for the corresponding actual angle, to phase B --> angle + 120º and phase C --> angle + 240º, so the phases are driven with sinewaves with 120º difference from each other:

Code:
ui8_temp = ui8_svm_table[ui8_motor_rotor_position];
ui8_value_a = ui8_temp * k;
TIM1_SetCompare1((uint16_t) ui8_value_a); // phase A

ui8_temp = ui8_svm_table[(uint8_t) (ui8_motor_rotor_position + 85 /* 120º */)];
ui8_value_b = ui8_temp * k;
TIM1_SetCompare2((uint16_t) ui8_value_b); // phase B

ui8_temp = ui8_svm_table[(uint8_t) (ui8_motor_rotor_position + 171 /* 240º */)];
ui8_value_c = ui8_temp * k;
TIM1_SetCompare3((uint16_t) ui8_value_c); // phase C
How to define the final angle that will be used as ui8_motor_rotor_position?
1.
Code:
ui8_motor_rotor_absolute_position = ANGLE_120 + MOTOR_ROTOR_DELTA_PHASE_ANGLE_RIGHT;
ui8_motor_rotor_absolute_position is defined from the hall sensor position (on the switch (ui8_hall_sensors) code). Also
is included a fixed adjustment value (MOTOR_ROTOR_DELTA_PHASE_ANGLE_RIGHT), that we may need to use to correct from motor to motor:

2.
Code:
ui8_motor_rotor_position = ui8_motor_rotor_absolute_position + ui8_position_correction_value + ui8_interpolation_angle;
The final calculation includes a sum parcel of the ui8_position_correction_value, that is increased or decreased in a way to make the phase B current signal synchronized with motor rotor position(given here by the hall sensors signal). We want the max torque per amp, that means the magnetic field created on the coils by our sinewave voltages, should be at a specific angle(distance??) from the magnets (to create the max attraction for/and rotate the rotor), seems that is when the Id current is zero per FOC definition -- we should increase/decrease ui8_position_correction_value to apply the FOC definition.

The ui8_interpolation_angle is another sum parcel that will increase the equivalent from 0 to 360º, this when we are running with interpolation 360º and starting the interpolation process once per electric rotation (360º):

NOTE: the ui8_position_correction_value depends of: I*R (motor current * motor coil resistance) and I*w*L (motor current * omega (sinewave frequency/motor rotational speed) * motor coil inductance) -- see Shane Colton "A Modified Sychronous Current Regulator for Brushless Motor Control":
 
I'm a mechanical engineneer and not that familiar with electrics. The sketch shows just the basics of a three-phase electric power with inductive load.

It's all correct what you write, but has nothing to do with the fact, that you control the voltage with the PWM. The current is a result of the voltage and is phase shifted to the voltage...

regards
stancecoke
 
stancecoke said:
It's all correct what you write, but has nothing to do with the fact, that you control the voltage with the PWM.
Yes, voltage is controlled with PWM duty_cycle. A 50% value means Voltage battery * 0.5, for instance, if motor is rotating already, it generates a voltage on his phase wires(the BEMF) and we need to put the same voltage with PWM duty_cycle, other different value is like a "short-circuit"/high currents flowing.

stancecoke said:
The current is a result of the voltage and is phase shifted to the voltage...
So we want to control/mantain the phase current synchronized with motor rotor position. We can't directly control the phase current, but we can control it indirectly by controlling(directly) the phase voltage.
We control the phase voltage by selecting the right value of ui8_motor_rotor_position(may not be the best name for this variable). A good way is to disable FOC and increase/decrease manually the value of ui8_position_correction_value - there must be a value where motor have the max efficiency/torque per amp (for this test, maintain the same motor speed and load --> to force the same motor mechanical power output while the motor electric power input will be automatically adjusted):
Code:
ui8_motor_rotor_position = ui8_motor_rotor_absolute_position + ui8_position_correction_value + ui8_interpolation_angle;
Are you with me?
 
Back
Top