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

AN8 is the battery current. When I wrote Ibat / duty it's really a divide operation, duty being the PWM's duty cycle but, as you pointed out, this is FOC and the current waveform is different from the "flat phase current" of non FOC.
 
So, I looked with oscilloscope to AN8 and seems to me that follows the shape of phase B current, but with much more noise!!

I just pushed the code that reads Id current and sends it:
Code:
      i16_temp = (((int16_t) ui16_ADC_iq_current_filtered) - 511) * ADC_PHASE_B_CURRENT_FACTOR_MA;
      i16_temp1 = (((int16_t) ui16_ADC_id_current_filtered) - 511) * ADC_PHASE_B_CURRENT_FACTOR_MA;
      printf("%d, %d, %d\n", ui16_motor_speed_erps, i16_temp, i16_temp1);

For me, it seems to work more or less. When it seems to work worst is at high speeds but there the shape is really different. But with motor load with the rider, the shape is better as should be the Id value.

stancecoke, can you please test with your motor, power supply and load?? Code is here:
commit 4d770b97a73541c08f61f6b3f69ee9659ec93075
Author: casainho <casainho@gmail.com>
Date: Tue Sep 19 16:56:18 2017 +0100
Id current is now readed and seems to be more or less correct


If Id is acceptable, I can move to make throttle working as "torque+speed" as the original firmware does. Finally, would need to use time to add robustness!!
 
I've just updated the TORQUESENSOR_EXPERIMENTING branch with the 10 bit resolution for battery current (ADC8)
The calibration is deziAmps = 1 * ADC8 - 312 for 10bit resolution.

But I think we should stop working in parallel now. I don't know how to merge the best parts of each branch to master....

regards
stancecoke
 
stancecoke said:
I've just updated the TORQUESENSOR_EXPERIMENTING branch with the 10 bit resolution for battery current (ADC8)
The calibration is deziAmps = 1 * ADC8 - 312 for 10bit resolution.

But I think we should stop working in parallel now. I don't know how to merge the best parts of each branch to master....
I wanted to look at all the bits of motor control, including seeing the oscilloscope signals. Next I will look at your speed controller before implement anything for the troque-speed throttle.
 
casainho said:
So, I looked with oscilloscope to AN8 and seems to me that follows the shape of phase B current, but with much more noise!!

Poor filtering :) You're also still dealing with low phase currents, the difference should increase as the currents get higher.
I should actually say "average battery current". ISHUNT isn't actually the phase current either, it's the phase current if you look at it only during the ON periods of the PWM cycle (but since that current is more or less maintained during the PWM OFF period, we can say it's the phase current), as depicted in my illustration of the other post.

As for the noise, how you measure has a big impact on what you see; if you're not measuring with the ground clip (not the ground lead) of the scope and at a very short (I would say keep it closer than 10mm) distance from the point you want to measure, you can't thrust what you see on the scope's screen. When I want a "rigorous" measure, I usually solder a little wire at the exact points of the PCB where I want to measure, for the probe to hold on to.
 
casainho said:
stancecoke, can you please test with your motor, power supply and load??

I've tested the recent SVM7 branch (I don't know how to load an earlier commit to eclipse :? )
The motor runs fine, but current limitation does not work....

Regards
stancecoke
 
stancecoke said:
casainho said:
stancecoke, can you please test with your motor, power supply and load??

I've tested the recent SVM7 branch (I don't know how to load an earlier commit to eclipse :? )
The motor runs fine, but current limitation does not work....
Yes because I put it very high, please look at main.h. That value should be to protect the controller and the torque controller should use Id current, at least is how I see it.

Can you please look at printed Id current and see how that value compares with power supply current? Should follow close. Testing with your load would be important.
 
so again: It would be nice, if you would put some more comments to your code.
Of course I had a look at the main.h, but my interpretation was that the current limit is set to 2 amps :? .

Code:
#define ADC_MOTOR_TOTAL_CURRENT_ZERO_AMPS 81 // 1.59V; 325 (10bits) = 81 (8bits)
#define ADC_MOTOR_TOTAL_CURRENT_MAX 32 // 32 (8bits) ~ 2 Amps
#define ADC_MOTOR_TOTAL_CURRENT_MAX_POSITIVE 95 // +2A
#define ADC_MOTOR_TOTAL_CURRENT_MIN_NEGATIVE 76//76 // -2A

Regards
stancecoke
 
stancecoke said:
so again: It would be nice, if you would put some more comments to your code.
Of course I had a look at the main.h, but my interpretation was that the current limit is set to 2 amps :? .
I am sorry, next I need to explain the changes you need to do/prepare so you can use. The values I used were:
//#define ADC_MOTOR_TOTAL_CURRENT_MAX_POSITIVE 81 // +1A
//#define ADC_MOTOR_TOTAL_CURRENT_MAX_POSITIVE 85 // +2A

The thing is that I am trying to go the faster as I can and I am doing just prototyping/experimenting and not final code. I want to find/learn the paths that will work and do it quickly as possible. The code I am doing is no way final.
 
I was not happy with Id readings, they were clearly not reflecting the real value of current, there was almost not increment in Id with increased lab power supply current and motor speed.

Looking over Internet, seems that my power supply may look at average value or RMS value of the current and not just considering it is a sinewave. For RMS, we need to do a multiply every PWM cycle, not possible with STM8. For average, we just need to sum up every PWM cycle the value and do a division every eRPS, seems ok to me for STM8. I did implement it and before filtering that value, I could saw it working!! Than I had filtering and I saw the motor started to work more slowly... I went to look at oscilloscope and the code on the PWM cycle were over the 64us :-( :-(

Code to sum up the current, just every positive value, on every PWM cycle:
Code:
  if (ui8_motor_state == MOTOR_STATE_RUNNING_INTERPOLATION_360_DEGREES)
  {
    adc_select_channel (ADC1_CHANNEL_PHASE_CURRENT_B);
    ui16_ADC_id_current = adc_read ();

    if (ui16_ADC_id_current > 511)
    {
      ui32_ADC_id_current_sum += ui16_ADC_id_current;
      ui16_ADC_id_current_sum_counter++;
    }
  }

So, I think I need to drop resolution, maybe in some cases will work as low pass filter and even help reducing processing time. I need to try use only 8 bits. For start, I will implement an ADC read only for 8 bits and other for 16 bits when needed. Let's see if I can do the code in a way it works.....
 
stancecoke said:
What about the idea to read in the adc value into an array each pwm cycle and do the evaluation of the array in the slow main loop. I did this already in one commit of the old feature_torque_sensor branch,
This worked for me.
Thanks, I will remember this.

Another simplification/optimization:

Code:
void hall_sensors_read_and_action (void)
{
(...)
    switch (hall_sensors)
    {
      case 3:
      // read here the phase B current: FOC Iq current
      adc_select_channel (ADC1_CHANNEL_PHASE_CURRENT_B);
      ui8_ADC_iq_current = ui8_adc_read ();
(...)
      break;

      case 1:
      if (ui16_motor_speed_erps > 7)
      {
            if (ui8_ADC_iq_current > 127)
            {
                  ui8_position_correction_value++;
            }
            else if (ui8_ADC_iq_current < 125)
            {
                  ui8_position_correction_value--;
            }
      }
(...)
      break;

That way I avoided to do the filtering and the control loop is now the faster possible.
The code avoided:
Code:
      ui16_ADC_iq_current_accumulated -= ui16_ADC_iq_current_accumulated >> 2;
      ui16_ADC_iq_current_accumulated += ui8_ADC_iq_current;
      ui8_ADC_iq_current_filtered = ui16_ADC_iq_current_accumulated >> 2;

And guess what, seems to me that now I can run even faster the motor/higher eRPM without seeing short-circuit signal on the lab power supply.
 
I verified that ADC reading was taking to much time. I decided to try make it run all channels, scan conversion (buffered), starting on PWM cycle and should take less than a period. It happens automatically and at end of period I have and readings in the ADC buffer and so read is very fast.

I am seeing a lot of noise on the calculated phase B current average value.... I need to debug because the results aren't what I expected, maybe something is wrong.
Without phase B current average value ok, I can't move to control the motor torque (throttle using mode "torque+speed").
 
casainho said:
have one big question: which signal use to find current motor torque?? so we can use it to finally implement the throttle using mode "torque + speed"!!

I can try read Id from the very low resolution FOC but looking at oscilloscope I can see it will be very noise, because the phase B current signal is not a perfect sinewave (always changing) -- but on the FOC algorithm, the Id is the torque!!

Id is not the torque producing vector in FOC, you want Id to be zero, unless you want field weakening or are controlling an internal magnet motor, and Iq is the torque producing vector that you need to control. Take a look at this excellent Texas Instruments video on FOC: https://www.youtube.com/watch?v=cdiZUszYLiA
 
kiwifiat said:
casainho said:
have one big question: which signal use to find current motor torque?? so we can use it to finally implement the throttle using mode "torque + speed"!!

I can try read Id from the very low resolution FOC but looking at oscilloscope I can see it will be very noise, because the phase B current signal is not a perfect sinewave (always changing) -- but on the FOC algorithm, the Id is the torque!!

Id is not the torque producing vector in FOC, you want Id to be zero, unless you want field weakening or are controlling an internal magnet motor, and Iq is the torque producing vector that you need to control. Take a look at this excellent Texas Instruments video on FOC: https://www.youtube.com/watch?v=cdiZUszYLiA
Thank you to point this out. I am a fan of David Wilson videos from TI!!
Yes, Iq for quadrature, the 90 degrees.

I am right now controling Id to be 0 and the motor works very well but now I want to read Iq to control tje torque, but I have only one phase current and an 8bits 16Mhz microcontroller :)
 
I testet your commit 894eb52. The current limitation worked, but caused much noise, I agree, we have to improve the control loop. iq (torque) measurement from phaseBcurrent did not work.

I still don't understand, why you want to read in the "peripheral" signals so often. I think for torque (battery current from ADC8), Battery Voltage and Throttle it is absolutely sufficient to read only in the slow main loop. I think the difference between iq (taken from phaseB current) and the low pass filtered current on ADC8 will be just academic... (peak value vs. average value).

I would prefer the torque (ADC8) in 10bit resolution because with 8bit the steps of the signal are too big to make a good working control loop (see the TORQUESENSOR_EXPERIMENTING branch)

regards
stancecoke
 
stancecoke said:
I testet your commit 894eb52. The current limitation worked, but caused much noise, I agree, we have to improve the control loop. iq (torque) measurement from phaseBcurrent did not work.

I still don't understand, why you want to read in the "peripheral" signals so often. I think for torque (battery current from ADC8), Battery Voltage and Throttle it is absolutely sufficient to read only in the slow main loop. I think the difference between iq (taken from phaseB current) and the low pass filtered current on ADC8 will be just academic... (peak value vs. average value).
For the torque/current control you tested, I used ADC/battery current signal and did the control every PWM duty_cycle but still there are some oscillations on the motor speed!! I would say that a slower control loop like you propose would increase the oscillations.
And I saw on the oscilloscope, that current quick increases in just a few PWM cycles. I was trying to limit the current when the eRPM is very high and that is just possible with very fast control loop.

For instance, the control loop for Id current/FOC was done before on the slow main loop and after going to the PWM cycle loop, seems to me the motor/higher eRPM increased without seeing short-circuit signal on the lab power supply.

8. Sample often.

Unlike an analog control system, a digital controller only gets discrete moments in time to observe and respond to the system’s behavior. This can reduce system performance if your sampling frequency is too low. Imagine driving your car while texting, and you only look up once every 10 seconds to sample your surroundings! The same effect can happen with your motor control processor. If it is too busy doing other tasks, and not looking at your motor feedback signals frequently enough, your motor will crash! For position and velocity loops, the minimum sampling frequency is dictated by the mechanical poles of your system. It is common to find position and velocity loops running at sampling frequencies of around 2-5 KHz. However, most motor control designs also include current loops. The electrical poles are much higher than the mechanical poles, so sampling frequencies for the current loops are typically between 10-20 KHz. For low inductance motors, this figure can be even higher!
https://e2e.ti.com/blogs_/b/motordrivecontrol/archive/2011/12/20/the-ten-commandments-of-digital-control-part-2

About using ADC/battery current signal for torque control, you are probably right. Since FOC is working, all the current flowing from battery should be almost equal Iq current, I think. I will try use that signal and try implement PI controller for that value, defined by the throttle.

But I ended up averaging the phase B current signal and would like to show the results, that are what I expected except for the relatively much noise. Every value of ADC represents 0.24 amps, so for 1A is only 4 and 2A value of 8. Next pictures shows at purple the unfiltered signal and green the filtered signal, done on main loop, for 1 and 2 amps respectively. The filtered signal seems good for me for such small values but is slow/have a noticeable delay which may be bad for the control loop.

1amp.png


2amps.png


The code I used on every PWM cycle:
Code:
    ui8_temp = ui8_adc_read_phase_B_current ();
    if (ui8_temp > 127)
    {
      ui8_ADC_id_current = (ui8_ADC_id_current >> 1) + (ui8_temp >> 1);
    }
That was a way to use only 8 bits for quick storage of the value.

And the filtered code on main loop:
Code:
      ui16_ADC_id_current_accumulated -= ui16_ADC_id_current_accumulated >> 4;
      ui16_ADC_id_current_accumulated += ui8_temp1;
      ui8_ADC_id_current_filtered = ui16_ADC_id_current_accumulated >> 4;

      printf("%d, %d, %d\n", ui16_motor_speed_erps, ui8_temp1, ui8_ADC_id_current_filtered);
 
casainho said:
I would say that a slower control loop like you propose would increase the oscillations.
I think the oscillation can be avoided with less proportional part and more integral part of a PI-control.

casainho said:
For instance, the control loop for Id current/FOC was done before on the slow main loop and after going to the PWM cycle loop, seems to me the motor/higher eRPM increased without seeing short-circuit signal on the lab power supply.
For FOC of course it makes sense to do the control in the fast loop. The fast loop should concentrate on proper driving the motor phases. Everything else should be done in a slower loop. Therefore I wrote "peripheral signals".

I suggest three timings:
1. fast loop for PWM control
2. slow loop (about 50 Hz) for control of current/torque or speed
3. very slow loop (about 10 Hz) for communication (uart for debugging or display comunication)

Regards
stancecoke
 
stancecoke said:
casainho said:
For instance, the control loop for Id current/FOC was done before on the slow main loop and after going to the PWM cycle loop, seems to me the motor/higher eRPM increased without seeing short-circuit signal on the lab power supply.
For FOC of course it makes sense to do the control in the fast loop. The fast loop should concentrate on proper driving the motor phases. Everything else should be done in a slower loop. Therefore I wrote "peripheral signals".

I suggest three timings:
1. fast loop for PWM control
2. slow loop (about 50 Hz) for control of current/torque or speed
3. very slow loop (about 10 Hz) for communication (uart for debugging or display comunication)
I went on a different path (controlling the motor current every PWM cycle) and tested the current control from battery (which I prefer to call motor current). The results are ok, seems to me. Next I hope to add speed controller that would superimpose to this current controller, when the load is very low. But this are all almost experiences, for instance, the startup almost always fail now...

[youtube]BrAh5Resppo[/youtube]
 
Njay said:
Have you already tried sudden full throttle with a blocked rotor?
Yes and it does not work!! Even the startup is almost always failing... the FOC does not work with stopped motor, just 6 steps... I need to play and think about all this.

With the EUC motor I got very good results on blocked motor with constant torque, I wish to have the same on this firmware:

[youtube]m6DIowR6jxQ[/youtube]
 
stancecoke said:
casainho said:
I would say that a slower control loop like you propose would increase the oscillations.
I think the oscillation can be avoided with less proportional part and more integral part of a PI-control.

casainho said:
For instance, the control loop for Id current/FOC was done before on the slow main loop and after going to the PWM cycle loop, seems to me the motor/higher eRPM increased without seeing short-circuit signal on the lab power supply.
For FOC of course it makes sense to do the control in the fast loop. The fast loop should concentrate on proper driving the motor phases. Everything else should be done in a slower loop. Therefore I wrote "peripheral signals".

I suggest three timings:
1. fast loop for PWM control
2. slow loop (about 50 Hz) for control of current/torque or speed
3. very slow loop (about 10 Hz) for communication (uart for debugging or display comunication)
Ok, I saw your code for the speed controller, PAS, etc. It seems ok to me and modular. I see it uses speed from the external sensor and I wonder if it can be avoided for the correct motor function, as you know the motor works on original firmware without that speed sensor.

I think the motor controller should be kind of modular and robust. I am proposing the following structure that seems modular, like what you did already. See that motor controller have have as inputs duty_cycle and motor_current_max and as output the motor_speed:
 
casainho said:
I see it uses speed from the external sensor and I wonder if it can be avoided for the correct motor function, as you know the motor works on original firmware without that speed sensor.
This may work with a direct drive, but with a geared motor with a freewheel, you get no speedsignal if motor is not running while your bike is rolling. Serveral geared motors have an "extern" speedsensor internally already (white wire of the hall-sensor connector)

I just updated the TORQUESENSOR_EXPERIMENTING branch with the 50 Hz control loop and 10 Hz communicaton loop. It works so far, Current and Speed is displayed correctly, Speed- and Current- Limitations work with P-control. This could be improved with a PI-control.

I think I will take a break at this point until somebody implements the display communication....

Regards
stancecoke
 
stancecoke said:
I think I will take a break at this point until somebody implements the display communication....

I get repeated delivery advisories for the battery, already, and I hope that I can donate the kit controller to the power gods. ;)

Anyway, I'd be happy to volunteer implementing all of this blind (the protocal seemed to be awfully trivial, to be honest). After all, we all know that once it compiles, it's done. Riiiiight?

I'll get started by getting at least some branch to compile locally.
 
Back
Top