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

stancecoke said:
casainho said:
Stancecoke,
See my clean main loop now.
I'm sad, you have thrown away all my ifdefs for the different ride modes... :(
I will concentrate on the start up procedure for my motor with 6 steps now. (And perhaps I'll understand what is happening ...)
I am just preparing a structure of the firmware and want to put it as master. As for now, I have the Kunteng LCD working (just send speed) and the main loop seems it is finished and is clean. We can now grow the firmware but (try) maintain the structure. I think should be easier for you now, and I will try to put your code back (LCD + PAS | Torque sensor) but you are also free to do it.
See here the main loop:
Code:
  while (1)
  {
    ui16_TIM2_counter = TIM2_GetCounter ();
    if ((ui16_TIM2_counter - ui16_motor_controller_counter) > 100) // every 100ms
    {
      ui16_motor_controller_counter = ui16_TIM2_counter;
      motor_controller_high_level ();
      continue;
    }

    ui16_TIM2_counter = TIM2_GetCounter ();
    if ((ui16_TIM2_counter - ui16_communications_controller_counter) > 150) // every 100ms
    {
      ui16_communications_controller_counter = ui16_TIM2_counter;
      communications_controller ();
      continue;
    }

    ui16_TIM2_counter = TIM2_GetCounter ();
    if ((ui16_TIM2_counter - ui16_throttle_pas_torque_sensor_controller_counter) > 20) // every 20ms
    {
      ui16_throttle_pas_torque_sensor_controller_counter = ui16_TIM2_counter;
      throttle_pas_torque_sensor_controller ();
      continue;
    }
  }

I recorded a video showing the LCD5 and look at the oscilloscope that is showing Phase B Current signal and you can clearly see and hear the transition from steps to sinewave, maybe it will help you.
[youtube]EaAqPi7qDiI[/youtube]

The communications controller is not big nor complex:
Code:
void communications_controller (void)
{
  static uint8_t tx_buffer[12];
  uint8_t ui8_i = 0;
  uint8_t ui8_crc = 0;
  uint16_t ui16_speed = 6 * ui16_PWM_cycles_counter_total; // * 6 works for my Q85 motor; 16 magnets; Reduction ratio: 12.6

  // B0: start package??
  tx_buffer [0] = 65;
  // B1: battery level: 0: empty box
  tx_buffer [1] = 16;
  // B2: 24V controller
  tx_buffer [2] = 24;
  // B3: speed, wheel rotation period, ms; period(ms)=B3*256+B4;
  tx_buffer [3] = (ui16_speed >> 8) & 0xff;
  tx_buffer [4] = ui16_speed & 0xff;
  // B5: error info display
  tx_buffer [5] = 0;
  // B6: CRC: xor B1,B2,B3,B4,B5,B7,B8,B9,B10,B11
  // 0 value so no effect on xor operation for now
  tx_buffer [6] = 0;
  // B7: moving mode indication, bit
  tx_buffer [7] = 2;
  // B8: 4x controller current
  tx_buffer [8] = (motor_get_current_max () - ADC_MOTOR_CURRENT_MAX_ZERO_VALUE) << 1;
  // B9: motor temperature
  tx_buffer [9] = 0;
  // B10 and B11: 0
  tx_buffer [10] = 0;
  tx_buffer [11] = 0;

  // calculate CRC xor
  for (ui8_i = 1; ui8_i <= 11; ui8_i++)
  {
    ui8_crc ^= tx_buffer[ui8_i];
  }
  tx_buffer [6] = ui8_crc;

  // send the package over UART
  for (ui8_i = 0; ui8_i <= 11; ui8_i++)
  {
    putchar (tx_buffer [ui8_i]);
  }
}
 
That's great! :)

casainho said:
As for now, I have the Kunteng LCD working (just send speed) and the main loop seems it is finished and is clean. ...
Code:
    ui16_TIM2_counter = TIM2_GetCounter ();
    if ((ui16_TIM2_counter - ui16_communications_controller_counter) > 150) // every 100ms
    {
      ui16_communications_controller_counter = ui16_TIM2_counter;
      communications_controller ();
      continue;
    }
...

Normally you don't "fire" the bytes to the display unasked, but answer to the "end of transmission" byte of received message from the display. But if it works with the Kunteng Display, it's OK... ;)


Sorry for one question: Are you sure, that FOC works on your recent SVM7 branch? Everything I try to make it work fails. Perhaps you can upload an .HEX file with the ui8_position_correction_value printed out. With hindsight, all I did yesterday was working, except the reading of PhaseB_current at interpolation mode, I think. And thats the same with your original code....

Regards
stancecoke
 
Alan B said:
I have a question - what do you folks mean by FOC?

Here's a common definition:

http://www.copleycontrols.com/Motion/pdf/Field-Oriented-Control.pdf

Is this what is being done here?
The S series controllers don't have resources to do FOC but they have more resources than the 1st gen 6 steps/commutation controllers. And the resources they have, there are no references on the literature/web about, seems Kunteng did something unique.

I tried to figure out what tricks Kunteng does and I wrote something, that again, I never read any were about -- I call it very low resolution FOC: https://opensourceebikefirmware.bitbucket.io/Various--Endless-sphere.com_forum_messages--2017.09.02_-_How_to_do_FOC_on_the_BMSBattery_S06S-Kunteng_STM8_motor_controllers.html

And the application (should read Id were is written Iq): https://opensourceebikefirmware.bitbucket.io/Various--Endless-sphere.com_forum_messages--2017.09.05_-_measuring_IQ_current_and_manually_adjusting_position_correction_value.html
 
casainho said:
Alan B said:
One thing you could do, in both cases, is adjust the PWM to allow the voltage to be within spec, reduce power in the low voltage case, or reduce regen in that case. Do the best that can be done, the rider might need to clear the intersection and cutting throttle might be a bad thing to do right at that moment.

Just something to think about.

When we built realtime systems (at work, for a career) we tried to make them do the best they could rather than just give up. This isn't regular software, it is control software.

I understand what you mean. Also I think it will bring complexity which is something I want to avoid on this phase: now I just want to have a working firmware that will not be perfect but should have a good working base. Improvements can be done after.

For instance: my Smart electric car (Daimler AG), when the battery is fully charged and I leave the garage, I need to make about 4 kms before the regen/electric brake works other way just the mechanical brake works -- this is written on manual. I see no reason to do implement different from this, at least in the first version of the firmware.

For battery low voltage, again, my Smar electric car, shows a "fuel reserve" warning and it is up to me to take care with my driving on the stage. On Kunteng LCD, since I remember, the user also gets the same warning!

So to resume, I think we need to simplify.

There's almost always a conflict between doing the simplest thing and doing the best thing. With something as critical as vehicle control there is a safety element as well. An example:

Years ago I had a Honda 4 cycle outboard that had a "low oil" alarm. When it became low on oil it would shut down. A newer model changed the feature. The updated feature sounded an alarm and turned on an alarm light, but did not shut off the engine. It should be up to the captain to make the decision, which might be between letting the boat drift into the rocks versus damaging the motor.

In our case the pilot may be in the midst of an intersection, merely shutting down could be dangerous. Cutting power a little will allow the voltage to recover and perhaps prevent an accident, or at least protect the batteries in a way that the pilot will understand.

Writing real time control software bears a great responsibility. Consider all choices carefully. If you think it is complex, then it is likely you haven't thought about it enough. :)
 
I'll agree with the "let the driver/rider/pilot/captain make the call", because it's not safe to let the machine do it--it can't know the situation, and if the operator is depending on the system to work, however poorly, for that one instant, and it doesn't, it could get them hurt or killed.

This is why I do not have an actual speed limiter on my bikes/trikes, even though I don't use them above 20MPH. There are times when someone else on the road does something that requires I accelerate as rapidly as possible to get out of the situation they created, because braking or staying at the same speed would get me hurt or killed. I don't have to go very much faster, just enough to avoid being in the same spot they're trying to occupy, and usually just long enough for them to realize I'm there and for them to stop what they're doing.

If the bike decided I couldn't go above 20MPH and I had to do that...ouch.

I could accept a controller that sounds a buzzer/lights an indicator when 20MPH is exceeded....


I also stopped wanting to use BMS on all my batteries, because I'd rather kill the battery than myself trying to get home (I ended up near heatstroke once because of it). Or have the battery dip a little below it's LVC while I finish accelerating thru an intersection or across a road rather than have the BMS shutdown and leave me there to get hit by the other traffic on the road, because I couldn't finish doing it on just my own power. A BMS that just lights up a warning and latches it on for me to see and deal with, sure, I could live with that.


Stuff could always fail and leave me in one of those positions...and that's a risk I accept.

But I don't want to use a system that might decide for me that I can't have the power needed to do a maneuver to keep me safe. ;)


At one time, years ago now, nearly a decade I guess, I started to design the "perfect" :roll: ebike systems computer, to control everything on the bike from lights to motor to battery monitoring, etc., and I hadn't yet realized all these issues--but I would if I were to do that design today.



If there were something that would actively endanger the rider by allowing them to continue, like if they're using something volatile like some RC LiPo and are using max power and it hits LVC, and it would catch on fire if allowed to continue....I could see doing more than just a warning light. But I'd still want an override button on the throttle/etc, just because someone might be in that situation where it'd be better to lose the battery and the bike to a fire than to be forced to a stop at that moment.
 
stancecoke said:
Sorry for one question: Are you sure, that FOC works on your recent SVM7 branch? Everything I try to make it work fails. Perhaps you can upload an .HEX file with the ui8_position_correction_value printed out. With hindsight, all I did yesterday was working, except the reading of PhaseB_current at interpolation mode, I think. And thats the same with your original code....
Sure it works or the motor would be working asking much more current!! Since I am suing the lab power supply, I am always looking at the motor current. Remember that you did the tests to validate the efficiency compared to original firmware and I am always looking at the current and I think I now have sensitivity to this.

So you have an oscilloscope. Suggest for you to go as I did:
- look at phase B signal with osciloscope + some hall sensor signal (see here more screenshots):
(blue: hall sensor; yellow: phase B current)
82-4.png


On gpio.c you have void debug_pin_set (void); and void debug_pin_reset (void);. You can use them to enable and disable the debug pin (you can find the pin by yourself: big via on PCB, on top left side of STM8) and look at it with oscilloscope, instead of the hall sensor pin. Let's say you can enable the pin in case 4 and disable in case 5, then you will know for sure if the phase B current zero crosses at case 4 or such. This way, it must work!!!!

And remember that there are 2 zero crosses, I find the one I use to be better for the motor, being slightly more efficient on the one I chose.
So, for me it is at:
Code:
      case 3:
      // read here the phase B current: FOC Id current
      ui8_ADC_id_current = ui8_adc_read_phase_B_current ();
Since you have a different start angle and 6 steps sequence, I would say the zero cross for you may be at other different case number than me.
 
Alan B said:
Writing real time control software bears a great responsibility. Consider all choices carefully. If you think it is complex, then it is likely you haven't thought about it enough. :)
You are correct, I haven't thought about it enough. And because I don't have time now, maybe later.

I will want to implement what I am looking for and not all the possibilities or ideas. But the firmware is OpenSource, a big advantage here:
1. Let's say amberwolf don't want the battery voltage limits: he can easily go on the firmware and put that values on top max/min and that way disable the feature or with a bit more knowledge, comment the ifs on the code.
2. Let's say Alan B want a specific feature: don't need to know/write all the firmware, just pay to a developer to implement that specific feature and not the whole firmware.

On both cases 1. and 2., it is not possible with the current EBike motor controllers that runs proprietary firmware. OUR OpenSource firmware is the very first one in the world, I mean, for commercial motor controllers.
 
casainho said:
Sure it works ...
It definitly doesn't work, when I'm compiling your code. Therefore I asked you for uploading the .hex file with the output of the correction angle.
I still have problems with compiling your branch directly. There's always this "target not defined" error.
If I copy your files to my working directory of eclipse manually, there's no error. So perhaps I have a problem with compiling.

Regards
stancecoke
 
stancecoke said:
casainho said:
Sure it works ...
It definitly doesn't work, when I'm compiling your code. Therefore I asked you for uploading the .hex file with the output of the correction angle.
I still have problems with compiling your branch directly. There's always this "target not defined" error.
If I copy your files to my working directory of eclipse manually, there's no error. So perhaps I have a problem with compiling.
I will.

"target not defined" error may be because of your makefile is expecting some .h file that don't exist anymore.
 
stancecoke said:
casainho said:
Sure it works ...
Therefore I asked you for uploading the .hex file with the output of the correction angle.
Done -- with printf of motor_get_motor_speed_erps (), ui8_position_correction_value.
 
casainho said:
Done -- with printf of motor_get_motor_speed_erps (), ui8_position_correction_value.

Thank you, where can I find the hex-file? I've seen no new commit at github.

Regards
stancecoke
 
stancecoke said:
casainho said:
Done -- with printf of motor_get_motor_speed_erps (), ui8_position_correction_value.

Thank you, where can I find the hex-file? I've seen no new commit at github.
https://github.com/OpenSource-EBike-firmware/BMSBattery_S_controllers_firmware/commit/7cf4d7ac8e6a4340277a2e30b7630730d4fa54f8
 
OK, thank you. I've solved the problem with the compiling now. It was an issue with the windows makefile.

regards
stancecoke
 
Stancecoke,

I did implement the speed and battery correct values sent to LCD:
// calc wheel period in ms
ui16_wheel_period_ms = (motor_get_er_PWM_ticks () * (MOTOR_NUMBER_MAGNETS >> 1) * MOTOR_REDUCTION_RATIO) / MOTOR_PWM_TICKS_PER_MS;

// calc battery pack state of charge (SOC)
ui16_battery_volts = motor_get_ADC_battery_voltage_filtered () * ADC_BATTERY_VOLTAGE_K;
if (ui16_battery_volts > BATTERY_PACK_VOLTS_100) { ui16_battery_soc = 16; } // 4 bars | full
else if (ui16_battery_volts > BATTERY_PACK_VOLTS_80) { ui16_battery_soc = 12; } // 3 bars
else if (ui16_battery_volts > BATTERY_PACK_VOLTS_40) { ui16_battery_soc = 8; } // 2 bars
else if (ui16_battery_volts > BATTERY_PACK_VOLTS_20) { ui16_battery_soc = 4; } // 1 bar
else { ui16_battery_soc = 1; } // empty flashing

// preparing the package
// B0: start package (?)
tx_buffer [0] = 65;
// B1: battery level
tx_buffer [1] = ui16_battery_soc;
// B2: 24V controller
tx_buffer [2] = 24;
// B3: speed, wheel rotation period, ms; period(ms)=B3*256+B4;
tx_buffer [3] = (ui16_wheel_period_ms >> 8) & 0xff;
tx_buffer [4] = ui16_wheel_period_ms & 0xff;
And using defines to be later integrated on the java software:
#define MOTOR_PWM_TICKS_PER_MS 16
#define MOTOR_NUMBER_MAGNETS 16
#define MOTOR_REDUCTION_RATIO 13


// *************************************************************************** //
// BATTERY

// Considering the follow voltage values for each li-ion battery cell
// State of charge | voltage
#define LI_ION_CELL_VOLTS_100 4.05
#define LI_ION_CELL_VOLTS_80 3.93
#define LI_ION_CELL_VOLTS_60 3.78
#define LI_ION_CELL_VOLTS_40 3.60
#define LI_ION_CELL_VOLTS_20 3.38
#define LI_ION_CELL_VOLTS_0 3.20

#define BATTERY_LI_ION_CELLS_NUMBER 7 // 7S = 24V battery pack
//#define BATTERY_LI_ION_CELLS_NUMBER 10 // 10S = 36V battery pack
//#define BATTERY_LI_ION_CELLS_NUMBER 13 // 13S = 48V battery pack

#define BATTERY_PACK_VOLTS_100 (LI_ION_CELL_VOLTS_100 * BATTERY_LI_ION_CELLS_NUMBER) * 256
#define BATTERY_PACK_VOLTS_80 (LI_ION_CELL_VOLTS_80 * BATTERY_LI_ION_CELLS_NUMBER) * 256
#define BATTERY_PACK_VOLTS_60 (LI_ION_CELL_VOLTS_60 * BATTERY_LI_ION_CELLS_NUMBER) * 256
#define BATTERY_PACK_VOLTS_40 (LI_ION_CELL_VOLTS_40 * BATTERY_LI_ION_CELLS_NUMBER) * 256
#define BATTERY_PACK_VOLTS_20 (LI_ION_CELL_VOLTS_20 * BATTERY_LI_ION_CELLS_NUMBER) * 256
#define BATTERY_PACK_VOLTS_0 (LI_ION_CELL_VOLTS_0 * BATTERY_LI_ION_CELLS_NUMBER) * 256
 
I connected the S06S with OUR OpenSource firmware to my 7S3P battery pack (which includes a BMS). Works well so far. I tested applying full brakes and not problem, even why trying to startup will full brakes. But once the BMS did cutoff the power, I had to unconnected and connect again the S06S. The LCD5 I have only shows speed and battery voltage, I wish I did bought the LCD3 that also shows power/wattage -- it is important for me to look at the motor wattage, on this tests.

Next I want to put the controller and the battery pack on the EBike and go for a ride :)
 
Good Luck for your test ride!

I'm really confused now. With your .hex file, the switch to sine-mode works pretty, but FOC doesn't work.

[youtube]ME-XtH80oZA[/youtube]

With the .hex file, that I compiled from your ADC branch (without any changes except the editing of the Windows makefile) the switch from 6 step to sine is faulty and the FOC doesn't work.

Perhaps you can try my .hex file that I uploaded to the new branch CheckADC
https://github.com/OpenSource-EBike-firmware/BMSBattery_S_controllers_firmware/tree/CheckADC

Regards
stancecoke
 
stancecoke said:
I'm really confused now. With your .hex file, the switch to sine-mode works pretty, but FOC doesn't work.
How do you know that FOC is not working??
 
the correction value is constant at 127 all the time. It has to vary with speed/load.... and current is drifting away...

regards
stancecoke
 
I am start to thinking that the LCDs are limited. I want an LCD that is graphic to be customize the info displayed + with some processing power + some pins for buttons, other throttle, sensors, etc. Any idea for build a custom LCD?? or is there any already available?

On Ebay, I can find as the most cheap the:
- 0.96" 128X64 OLED LCD
- 1.8 inch SPI TFT LCD

And the STM8 boards for the processing.
 
casainho said:
The LCD5 I have only shows speed and battery voltage, I wish I did bought the LCD3 that also shows power/wattage -- it is important for me to look at the motor wattage, on this tests.

I am sure that you already had the idea: Perhaps you can output wattage (or rather "transformed wattage") into the speed field, so that the display shows the wattage as speed?

With the display showing

Speed := f(wheel rotation period, wheel diameter)

simply create g() such that

Wattage / 10 := f(g(transformed wattage, wheel diameter), wheel diameter)

Basically you fake {wheel rotation period} such that the display, using f(), shows the wattage, but thinks that it shows the speed.

Thank you for letting the popcorn gallery participate in your exciting endeavours! :)

casainho said:
Next I want to put the controller and the battery pack on the EBike and go for a ride :)

Go, casainho, go-go-go!!! :mrgreen:
 
You may want to choose an LCD that is sunlight visible as well as in low light. Most are very poor in direct sunlight. A few, such as Transflective LCD displays are both sunlight and night visible with a backlight. This is a problem with cellphones also, most are not visible in full sun without protection such as hoods, etc.
 
stancecoke said:
I've solved the problem with the compiling now. It was an issue with the windows makefile.

Hmm, I think compiling is still the problem. I can't do exactly the same with windows than with linux as I don't have the stm8-objcopy executable file in windows. The normal objcopy.exe from MinGW gives an error :(

It's a little frustrating at the moment. Up to now there was no problem with compiling using windows.

Regards
stancecoke
 
stancecoke said:
Up to now there was no problem with compiling using windows.

In case you are willing to entertain alternative options, the combination of https://www.virtualbox.org/ and a widely used Linux distribution such as
[*] CentOS (https://www.centos.org/) - conservative, RPM-based
[*] Ubuntu (https://www.ubuntu.com/desktop) - progressive, apt/deb-based
can be a good enabler.

Alternatively, the Windows sub-system for Linux (https://msdn.microsoft.com/en-us/commandline/wsl/install_guide), as of "now" (Windows 10 Fall Update) seems to be a good option for userland, too.

Disclaimer: Every operating system has its own benefits. I know / use too many of them. Right now, Fedora 26 with KDE 5.10 is quite ok (running inside VMware on top of Windows 10, no less).
 
Thanks for your hints, but I don't want to switch to Linux. I want to keep the possibility to have an easy to use tool that a normal PC user can handle with just a few self explaining clicks. Otherwise this project will end with 3 or 4 freaky users like us....

https://www.netmarketshare.com/operating-system-market-share.aspx?qprid=10&qpcustomd=0

regards
stancecoke
 
Back
Top