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

Happy enough, the controller is working again. :p There were just two mosfets burned....

casainho said:
That also means that OC Over Current code did not work/protect :-(
When the mosfets have a short circuit, the OC protection can't help..... (I don't want to test it again :wink: )

Lessons learnt: Never use an unfused battery, when experimenting with unsafe code 8)

Code:
motor_set_current_max (8); // 1 --> 0.5A
In my code the value was set to "6". That means the my calibration is just a little different, obviously. Perhaps we should add an auto-zero function at startup.

casainho said:
I will be able to give a look just tomorrow. I want to start using your code, but with the Kunteng LCD, that is the one I have and I also think we should go with.
feel free to adapt the Kunteng protocol to my Kingmeter-solution :D


casainho said:
Can you please tell if your battery has a BMS, because if so, it should act as a fuse and should avoid that situation.
As wrote, I used an unfused battery. Without BMS.

I have deleted the TORQUESENSOR EXPERIMENTING branch, due to synconisation problems with eclipse. I pushed my recent code to the new "Merged_motor_and_J-LCD" branch.

Regards
stancecoke
 
stancecoke said:
Happy enough, the controller is working again. :p There were just two mosfets burned....

casainho said:
That also means that OC Over Current code did not work/protect :-(
When the mosfets have a short circuit, the OC protection can't help..... (I don't want to test it again :wink: )

Lessons learnt: Never use an unfused battery, when experimenting with unsafe code 8)
Good that you could repair and have it working again :)
Looking at schematic, I would say a short circuit on mosfets, would flow the current from the VCC to MGND and that should trigger the OC. That would not happen if the short were from VCC to GND...

stancecoke said:
Code:
motor_set_current_max (8); // 1 --> 0.5A
In my code the value was set to "6". That means the my calibration is just a little different, obviously. Perhaps we should add an auto-zero function at startup.
That was failing, I guess it needs a delay at start for ADC to read ok. But can you please printf you zero value? because the ADC is only 8 bits and may accommodate hardware differences and the current measurement may be not linear, depending on motor inductance or something.

So your motor is different from mine, how would a user setup a new motor on the firmware with a lab power supply to protect the tests??
- yes, you need to put MOTOR_ROTOR_DELTA_PHASE_ANGLE_RIGHT with the same value as before, but this value is not used on the 6 steps/startup
- the motor now starts with 6 steps and the sequence may be different in your motor...

I can't build your code:
/home/cas/software/stm8-binutils/bin/sdcc -IStdPeriphLib/inc -I. -mstm8 --std-c99 --nolospre --out-fmt-elf --debug main.c StdPeriphLib/src/stm8s_itc.rel StdPeriphLib/src/stm8s_clk.rel StdPeriphLib/src/stm8s_gpio.rel StdPeriphLib/src/stm8s_exti.rel StdPeriphLib/src/stm8s_uart2.rel StdPeriphLib/src/stm8s_tim1.rel StdPeriphLib/src/stm8s_tim2.rel StdPeriphLib/src/stm8s_adc1.rel gpio.rel utils.rel cruise_control.rel uart.rel adc.rel brake.rel timers.rel pwm.rel motor.rel PAS.rel SPEED.rel update_setpoint.rel

?ASlink-Warning-Undefined Global '_ui8_msg_received' referenced by module 'main'

?ASlink-Warning-Undefined Global '_UART2_IRQHandler' referenced by module 'main'

?ASlink-Warning-Undefined Global '_display_init' referenced by module 'main'

?ASlink-Warning-Undefined Global '_display_update' referenced by module 'main'
Makefile_linux:69: recipe for target 'main' failed
make: *** [main] Error 1

And the MOTOR_ROTOR_DELTA_PHASE_ANGLE_RIGHT is not defined!! Must have a value!!

And the motor.c file is not the same as on motor branch, it does not use 6 steps, looks like you didn't update it.

I want to use your branch, make it working with my motor and my LCD, then I will know that it should work for you also.
 
casainho said:
I can't build your code...
And the MOTOR_ROTOR_DELTA_PHASE_ANGLE_RIGHT is not defined!! Must have a value!!

Have you tried the new "Merged_motor_and_J-LCD" branch ? The motor.c is the version of your motor branch, copied yesterday morning....

edit: I've just updated the "Merged_motor_and_J-LCD" branch, again something went wrong with pushing via eclipse yesterday.

Have you added the display.c and display_kingmeter.c to the EXTRASRCS in your makefile?
The MOTOR_ROTOR_DELTA_PHASE_ANGLE_RIGHT is defined in the config.h, to make it settable with the Java-Tool.

I hope you'll have success!

Regards
stancecoke
 
Hmm, now I tested your motor.c, obviously something went wrong with merging, yesterday.
But the the result is sobering :(

If you power up the system, the motor makes a jerk. Then the motor is turning very slow (without throttle ) with a high noise (I think this beep is at 15.xx kHz PWM frequency)
If you rise throttle, the motor starts with 6steps quite noisy, sometimes it works to switch to noisy 60° without interpolation, switch to 360° interpolation always fails...


Regards
stancecoke
 
Today I implemented the motor speed controller (PI controller). It works well, I tested only on Q85 motor.
I also found that motor were failing when changing from 6 steps to sinewave and vice-versa, when increasing slowly the duty_cycle/speed. I added hysteresis and now seems to work well, much more robust.

There are 2 functions on file motor_speed_controller.c:
- void motor_speed_controller_set_erps (uint16_t erps);
- void motor_speed_controller (void); // call every 100ms

The code is not that much but took me some time to debug. The motor_speed_controller () takes as input the desired motor speed, the actual motor speed and outputs PWM duty_cycle value to motor_set_pwm_duty_cycle_target ():
Code:
void motor_speed_controller_set_erps (uint16_t erps)
{
  target_erps = erps;
}

// call every 100ms
void motor_speed_controller (void)
{
  i16_error = target_erps - ((int16_t) motor_get_motor_speed_erps ());
  i16_p_term = i16_error * MOTOR_SPEED_CONTROLLER_KP;
  i16_i_term += i16_error * MOTOR_SPEED_CONTROLLER_KI;
  // windup control
  if (i16_i_term > MOTOR_SPEED_CONTROLLER_OUTPUT_MAX) i16_i_term = MOTOR_SPEED_CONTROLLER_OUTPUT_MAX;
  else if (i16_i_term < 1) i16_i_term = 0;
  if (target_erps < 3) i16_i_term = 0; // avoid I term errors when target_erps = 0

  i16_output = i16_p_term + i16_i_term;
  // limit max output value
  if (i16_output > MOTOR_SPEED_CONTROLLER_OUTPUT_MAX) i16_output = MOTOR_SPEED_CONTROLLER_OUTPUT_MAX;
  else if (i16_output < 1) i16_output = 0;
  i16_output >>= 5; // divide to 32, as MOTOR_SPEED_CONTROLLER_KP and MOTOR_SPEED_CONTROLLER_KI are 32x; avoid using floats

  motor_set_pwm_duty_cycle_target ((uint8_t) i16_output);

//  printf("%d, %d\n", i16_error, (uint8_t) i16_output);
}

Real time log (from the next video), showing error value (that need to be reduced up to zero) and the output value of this controller that is PWM duty_cycle value:
Screenshot_from_2017-10-13_16-44-30.png


[youtube]GoClvVO1KSw[/youtube]
 
stancecoke said:
If you power up the system, the motor makes a jerk. Then the motor is turning very slow (without throttle ) with a high noise (I think this beep is at 15.xx kHz PWM frequency)
If you rise throttle, the motor starts with 6steps quite noisy, sometimes it works to switch to noisy 60° without interpolation, switch to 360° interpolation always fails...
You first need to make sure you are running only at 6 steps and make sure that at low speed the motor works well and not asking to much current. I don't know but if it does not work well, maybe you need to find the right commutation sequence that may be different from my Q85 motor.

But please use my last code on SVM_7, as you can see on my last message, I had to improve the motor code.
 
casainho said:
I don't know but if it does not work well, maybe you need to find the right commutation sequence that may be different from my Q85 motor.
There is definitly something wrong in 6 step mode. How do I change the sequence?

Here is the log of a start up, the erps and the interpolation_state don't fit to each other in every time?!

Regards
stancecoke
 

Attachments

  • output_2017-10-13_19-00-32.zip
    1.2 KB · Views: 19
stancecoke said:
casainho said:
I don't know but if it does not work well, maybe you need to find the right commutation sequence that may be different from my Q85 motor.
There is definitly something wrong in 6 step mode. How do I change the sequence?

Here is the log of a start up, the erps and the interpolation_state don't fit to each other in every time?!
Each step is 60 degrees. You may look at you initial angle and compare to my value of my motor, to try figure out how many steps you need to advance.

Code:
      case 5:
      if (ui8_motor_interpolation_state == NO_INTERPOLATION_60_DEGREES)
      {
	pwm_phase_a_disable (ui8_duty_cycle);
	pwm_phase_b_enable_low (ui8_duty_cycle);
	pwm_phase_c_enable_pwm (ui8_duty_cycle);
      }
      else if (ui8_motor_interpolation_state == INTERPOLATION_60_DEGREES)
      {
	ui8_motor_rotor_absolute_position = ANGLE_300 + MOTOR_ROTOR_DELTA_PHASE_ANGLE_RIGHT;
      }
      break;
So that case 5 happens at 1 specific step. You need to exchange/advance that sequence of pwm_phase_a/b/c, as each sequence represent the signals at each motor phase wires.

I can now go and improve the variable names, like to be block_commutation (6 steps) instead of NO_INTERPOLATION_60_DEGREES.
 
Alan B said:
If the original controller firmware did automatic phase mapping before then the wiring will not be the same on everyone's motors.
Alan, let's see if I could understand your information.

The original firmware may be able to "learn" the correct sequence, and I don't know how such algorithm could work, would be great to add to the firmware, if someone can explain the algorithm...

We did develop our OpenSource firmware from scratch. We are not using any information from the original firmware, we are hardcoding the sequence on our firmware and for now we need to change it for each motor before building the firmware for that specific motor.
 
casainho said:
Each step is 60 degrees. You may look at you initial angle and compare to my value of my motor, to try figure out how many steps you need to advance.

So that case 5 happens at 1 specific step. You need to exchange/advance that sequence of pwm_phase_a/b/c, as each sequence represent the signals at each motor phase wires.

OK, but I still don't know how to change, as there are many possibilities.
In your code you've set

0° Case 4
60° Case 6
120° Case 2
180° Case 3
240° Case 1
300° Case 5

Should I just change the case numbers by trial and error?!

Regards
stancecoke
 
stancecoke said:
casainho said:
Each step is 60 degrees. You may look at you initial angle and compare to my value of my motor, to try figure out how many steps you need to advance.

So that case 5 happens at 1 specific step. You need to exchange/advance that sequence of pwm_phase_a/b/c, as each sequence represent the signals at each motor phase wires.

OK, but I still don't know how to change, as there are many possibilities.
In your code you've set

0° Case 4
60° Case 6
120° Case 2
180° Case 3
240° Case 1
300° Case 5

Should I just change the case numbers by trial and error?!

Regards
stancecoke
Advance/shift/rotate that values!!
 
casainho said:
Advance/shift/rotate that values!!

I still don't understand. Can you give an example, please? How many possibilities are there???

regards
stancecoke
 
It is not just rotation.

There are 12 distinct configurations out of 36 possible arrangements. Three are exact rotations, so only 12 are distinct.

By manipulating either the inputs or the outputs only 6 combinations can be achieved. To get the total 12 one interchange must occur on the other set. When I do this with physical wires, the motor wires are usually the easiest to change due to the individual connectors. The other swap, if needed, must be done on the hall sensor wires.

Example of signal or wire map for say the motor outputs:

0 ABC one side, held constant
1 abc nothing swapped
2 bac swap left
3 acb swap right
4 cba swap ends
5 bca swap ends and left pair
6 cab swap ends and right pair

On the other side, just swap any two signals (in this case the hall sensor inputs) for the rest of the combinations, running through the above six again. Handle this at the edges so the main routines don't get involved in the confusing remapping.

In software I would define a single mapping parameter 0-11 or 1-12, and use boolean logic to do the swapping. Then the user can just try the combinations, perhaps with a parameter that can be adjusted without recompiling. At some point you may upgrade it to automatic determination, but later.
 
I now printed out the sequence of the cases by turning the motor by hand (I think backwards due to the freewheel)
Code:
if (ui8_hall_sensors != ui8_hall_sensors_last){ //for examining the signal sequence
	hallarray[hallarraycounter]=ui8_hall_sensors;
	hallarraycounter++;
	if (hallarraycounter>5){
	    for (b = 0; b < 6;b++){
	    printf("%d\n", hallarray[b]);
	    }
	    hallarraycounter=0;
	}
	}
I get the sequence 1-3-2-6-4-5. That's exactly the sequence thats in the recent code if you read it backwards. It's just shifted by 60° if you assume

0° Case 5
60° Case 4
120° Case 6
180° Case 2
240° Case 3
300° Case 1

regards
stancecoke
 
I am not at home so it is difficult to me to help.

The hall sensors sequence are correct because your motor works with sinewave. But your start angle is different from my motor and so the 6 steps should also start at a different number.

So in case 5 you have:
Code:
pwm_phase_a_disable (ui8_duty_cycle);
	pwm_phase_b_enable_low (ui8_duty_cycle);
	pwm_phase_c_enable_pwm (ui8_duty_cycle);

Now place that code instead on next case, case 4. And move the one on case 4 to case 6 and so on.
That is going in one direction, 60 degrees each time. Maybe you can look at the different between my and you start angle to see how many 60 degrees step you should shift. Anyway, max will be just 5.
Maybe you will need to shift on contrary direction.

Thank you everyone.
 
casainho said:
I am not at home so it is difficult to me to help.
Stancecoke, I am now at home and can help you further. Could you get some advance? in what can I help you now?
 
I'm still not happy. 6 step sequence seems to be OK. Motor starts in 6 steps if it reaches the 200 erps it switches to 60° interpolation but the erps fall back immediately, so it switches back to 6 step mode (even without load). If I then accelerate further, the switch to 60° interpolation works OK and is stable. The switching points are far too high for my motor, the switch to 360° interpolation happens almost at full throttle... :cry:

I was much more satisfied without the six step start thing...

Regards
stancecoke
 
stancecoke said:
I'm still not happy. 6 step sequence seems to be OK. Motor starts in 6 steps if it reaches the 200 erps it switches to 60° interpolation but the erps fall back immediately, so it switches back to 6 step mode (even without load). If I then accelerate further, the switch to 60° interpolation works OK and is stable. The switching points are far too high for my motor, the switch to 360° interpolation happens almost at full throttle... :cry:

I was much more satisfied without the six step start thing...
I am pretty sure that erps values are to much higher for my direct drive motor!! If that is the same in your case, please try lower all that values.
I remember that 360º didn't worked on my direct drive motor... maybe you can see if there is any advantage to use them.

And please create a new motor type:

Code:
#define MOTOR_TYPE_Q85 1
#define MOTOR_TYPE_EUC2 2

#define MOTOR_TYPE MOTOR_TYPE_Q85

About not using 6 steps, at least Q85 also could start well but then I did discover that it didn't had torque for startup... but my direct drive motor seems to have torque, and I remember that my EUC direct driver original firmware didn't use 6 steps!!

But we know that S06S original firmware uses 6 steps + sinewave, I documented that!!
- https://opensourceebikefirmware.bitbucket.io/Motor_controllers--BMSBattery_S_series--BMSBattery_S06S--PWM_signals.html
- https://opensourceebikefirmware.bitbucket.io/Motor_controllers--BMSBattery_S_series--BMSBattery_S06S--PWM_signals--very_low_speed_-_6_steps.html
- https://opensourceebikefirmware.bitbucket.io/Motor_controllers--BMSBattery_S_series--BMSBattery_S06S--PWM_signals--low_speed_up_to_max_speed_-_sineware.html

Also, can you please tell me what is the value of motor current zero value of your hardware? -- I need to see If I need to spend 1 day to implement that feature.
 
I have added an offset function for six step in the code, but without offset it works best, but not good :)
With some offsets the motor runs backwards, with others not at all.

I think I have to combine the offset with change in the PWM pattern.

Is there a table of reasonable patterns somewhere?

Regards
stancecoke
 
stancecoke said:
I have added an offset function for six step in the code, but without offset it works best, but not good :)
With some offsets the motor runs backwards, with others not at all.

I think I have to combine the offset with change in the PWM pattern.

Is there a table of reasonable patterns somewhere?

See avr194 app note, on google. Seems that you are looking of info about 6 steps/block commutation.
 
I now tried several examples i found in the internet, but your original pattern works the best, but still not good. I don't know, if I have to learn more about motor theory to unterstand what is going wrong...

regards
stancecoke
 
stancecoke said:
I now tried several examples i found in the internet, but your original pattern works the best, but still not good. I don't know, if I have to learn more about motor theory to unterstand what is going wrong...

regards
stancecoke
Please record a video, starting very slow. I would like to understand why is not good.
 
now I have figured out, that sometimes 6 steps runs in pwm_init_bipolar_4q mode. I can reproduce it, if I release the throttle very slowly. Then in 6 step mode with pwm_init_6_steps mode it suddenly changes to pwm_init_bipolar_4q

stancecoke
 
In the video the motor starts in 6 steps, with reaching 200 erps it switches to 60° interpolation and immediatly falls back to 6 step, but the shown erps are suddenly lower than before, but you don't recognize the Chainwheel is turning slower ?!

Code:
correction angle 127, Current 192, PWMMode 0, InterpolationState 2, dutycycle 59, setpoint 52, erps 192
correction angle 127, Current 192, PWMMode 0, InterpolationState 2, dutycycle 59, setpoint 52, erps 195
correction angle 127, Current 128, PWMMode 0, InterpolationState 2, dutycycle 60, setpoint 53, erps 200
correction angle 127, Current 0, PWMMode 1, InterpolationState 3, dutycycle 60, setpoint 53, erps 256
correction angle 127, Current 0, PWMMode 0, InterpolationState 2, dutycycle 60, setpoint 53, erps 122
correction angle 127, Current 0, PWMMode 0, InterpolationState 2, dutycycle 67, setpoint 59, erps 139

Then accelerating again until erps = 200 (with much higher rpm of the Chainwheel than at the initial start) and switching to stable 60°interpolation, but again with high drop of shown erps...

Code:
correction angle 127, Current 192, PWMMode 0, InterpolationState 2, dutycycle 91, setpoint 61, erps 197
correction angle 127, Current 192, PWMMode 0, InterpolationState 2, dutycycle 91, setpoint 76, erps 190
correction angle 127, Current 128, PWMMode 0, InterpolationState 2, dutycycle 98, setpoint 31, erps 190
correction angle 127, Current 64, PWMMode 1, InterpolationState 3, dutycycle 77, setpoint 0, erps 202
correction angle 127, Current 192, PWMMode 1, InterpolationState 3, dutycycle 99, setpoint 52, erps 137
correction angle 127, Current 64, PWMMode 1, InterpolationState 3, dutycycle 99, setpoint 76, erps 137
correction angle 127, Current 192, PWMMode 1, InterpolationState 3, dutycycle 99, setpoint 86, erps 137

then lowering speed to near zero with fall back to 6 step, suddenly it switches to PWM bipolar

Code:
correction angle 127, Current 64, PWMMode 0, InterpolationState 2, dutycycle 18, setpoint 25, erps 30
correction angle 127, Current 64, PWMMode 0, InterpolationState 2, dutycycle 18, setpoint 25, erps 28
correction angle 127, Current 64, PWMMode 0, InterpolationState 2, dutycycle 18, setpoint 25, erps 28
correction angle 127, Current 64, PWMMode 1, InterpolationState 3, dutycycle 15, setpoint 22, erps 1420
correction angle 127, Current 64, PWMMode 1, InterpolationState 2, dutycycle 15, setpoint 22, erps 98
correction angle 127, Current 128, PWMMode 1, InterpolationState 2, dutycycle 15, setpoint 22, erps 98
correction angle 127, Current 128, PWMMode 1, InterpolationState 2, dutycycle 15, setpoint 22, erps 100

It's all a little mysterious...

[youtube]vPIjCoHd5O8[/youtube]

regards
stancecoke
 
Back
Top