Lishui Controller Modification - Firmware Flash Project

Woosh

Trade Member
May 19, 2012
21,410
17,348
Southend on Sea
wooshbikes.co.uk
It wouldn't surprise me if your controller can't even measure phase current. Instead, it measures the battery current and derives some number based on an arbitrary calculation.

Let's say your motor is running at 200 rpm, has a reduction ratio of 8:1 and 12 poles. That would mean that each phase has 200 x 8 x 12 main pulses per minute in both forwards and backwards directions, which is 640 pulses a second. That's almost simple because the only problem is whether you want to measure a forward pulse, a backward one or both together. The net current from both is zero. It's a bit like A/C. You could count an RMS value or anything like that, but at what speed are you going to measure it because the motor speed could be anything between zero and 200 rpm.

Now it gets complicated because you have sinewave pwm controller. Each of those 640 pulsesa second is divided into say ten steps, which have a duty cycle of between zero and 100%. Obviously, the current would be half as much if the duty cycle was 50% compared with 100%, but your controller is a sinewave one, so the first and last step have a small duty cycle and the middle ones have a large one. The change in width over the ten steps follows a sinewave. Now tell me at any point in time how you're going to define current.

Here's a picture to help you visualise. What's shown happens 640 times a second:
It is not necessary to measure the current at the shunt resistors on the board. The code logic works out the percentage of maximum power and uses that to calculate the required pulse width, saving cpu time.
 
Last edited:

Sturmey

Esteemed Pedelecer
Jan 26, 2018
738
388
68
Ireland
........Looking at the code for the Watts in the display it seems it bit weird. The controller calculates the power in Watts using the current and the voltage as well as the calibration factor that I mentioned earlier. It then converts this into a number between 0 and 255 with each increment representing 0.25A. The display receives this value and multiplies it with the line voltage it measures from the battery to get the power in Watts.

Seems a bit silly to calculate in Watts then convert again to a value representing Amps then have the display convert that back into Watts. So simplified it to convert the battery current into the transmitted number. .......
Above is discussed in link below. The reason seems to be with the LCD 3 protocol which reserves for that function only one byte (or 256 values). Keep up the good work.
 
Last edited:

Sparksandbangs

Pedelecer
Jan 16, 2025
229
82
Some successes, some failures.

First off the code controlling the battery bars is ridiculously complicated. Decided to simplify it and... now it doesn't work. I think that the controller is reading the battery voltage incorrectly. This could also potentially affect the 36V code that I've added. Decided to disable the 36V part and and return to it later when I've got the basics sorted. I'll also live without the battery bars for now.

I've created a lead so I can plug the PC into the display cable via an adaptor. That should give me live readings of the controller settings and should assist with fault finding in the future. Will use this when I try to correct the battery bar issue.

Modified the torque simulation calculation now feels better, possibly a little bit too powerful. Turned the power down. Will test again on next ride.

Noticed that in level 5 after the bike hits the speed limit and then drops below it it surges back up to the speed limit. Realise that if I add some type of dampening that there is a possibility of recreating the KT issue with the delay when going over the limit down a hill and then delaying applying power when going up the next hill.
Put the dampener in but set it to deactivate if the speed reaches speed limit + 3kmph. This should hopefully stop the power hunting while travelling around the speed limit. When going well beyond it under my own steam it should stop any delay in reapplication of power. Will report back after testing.

Feel that I'm nearly there with this now.
 
  • Like
Reactions: Woosh

Sparksandbangs

Pedelecer
Jan 16, 2025
229
82
Brainwave. Voltage Sag only happens when the motor is running. Don't update the battery bars when the motor is running and problem is solved.
 

saneagle

Esteemed Pedelecer
Oct 10, 2010
9,088
4,057
Telford
Brainwave. Voltage Sag only happens when the motor is running. Don't update the battery bars when the motor is running and problem is solved.
The P5 setting looks after it. It adds a damping factor. I would guess that it does a moving average calculation and the P5 effects the number of readings or the time over which the average is taken.
 

Sparksandbangs

Pedelecer
Jan 16, 2025
229
82
I figured that was how it was done. The more that I look at it though it is far to complicated for such a minor feature. I've recreated it using two methods far simpler than using a moving average.

First is if the battery current is above 0.5A it doesn't update. This stops any major sags from being displayed.
I figure that it is unlikely that I will be continuously pedalling for a full journey. There will be points that I will coast, overspeed, brake at which time the battery bar reading is updated.

Second is creating a buffer zone between the battery levels. If the battery level falls below the preset limit the battery bar drops. It then can't rise until it goes up 0.5V above the preset limit. This stops any small fluctuations.

I haven't put the buffer in between 1 bar and empty because I think that flickering between the two is not a bad thing when you are getting near empty. The bar levels are of course preset to the users own preferences.

Code below:
Code:
if (ui32_battery_volts > ((uint16_t) BATTERY_LEVEL_4+20)) { ui8_battery_soc = 16; } // 4 bars | full
                 else if ((ui32_battery_volts > ((uint16_t) BATTERY_LEVEL_4))&&(ui8_battery_soc != 12)) { ui8_battery_soc = 16; } // 4 bars buffer zone
                 else if (ui32_battery_volts > ((uint16_t) BATTERY_LEVEL_3+20)) { ui8_battery_soc = 12; } // 3 bars
                 else if ((ui32_battery_volts > ((uint16_t) BATTERY_LEVEL_3))&&(ui8_battery_soc != 8)) { ui8_battery_soc = 12; } // 3 bars buffer zone
                 else if (ui32_battery_volts > ((uint16_t) BATTERY_LEVEL_2+20)) { ui8_battery_soc = 8; } // 2 bars
                 else if ((ui32_battery_volts > ((uint16_t) BATTERY_LEVEL_2))&&(ui8_battery_soc != 4)) { ui8_battery_soc = 8; } // 2 bars buffer zone
                 else if (ui32_battery_volts > ((uint16_t) BATTERY_LEVEL_1)) { ui8_battery_soc = 4; } // 1 bar
                 else if (ui32_battery_volts > ((uint16_t) BATTERY_LEVEL_0)) { ui8_battery_soc = 3; } // empty
                 else { ui8_battery_soc = 1; } // below empty level
 
  • Like
Reactions: Woosh

jarnold

Pedelecer
Oct 2, 2024
75
14
72
Gloucestershire
You can't really get much simpler than a moving average!
I had an algorithm for bar graphs on satellite dish alignment meters that could otherwise be very jittery, but I can't remember off the top of my head how it worked. It was a bit more complicated than a simple moving average, but gave very good results.
 

Sparksandbangs

Pedelecer
Jan 16, 2025
229
82
You can't really get much simpler than a moving average!
I had an algorithm for bar graphs on satellite dish alignment meters that could otherwise be very jittery, but I can't remember off the top of my head how it worked. It was a bit more complicated than a simple moving average, but gave very good results.
I'm happy for any coding help that you would like to share. It's beyond my abilities.
 

Woosh

Trade Member
May 19, 2012
21,410
17,348
Southend on Sea
wooshbikes.co.uk
I like your approach to problem solving. Removing the voltage sag your way is pretty effective.
 

jarnold

Pedelecer
Oct 2, 2024
75
14
72
Gloucestershire
I suppose, in an ideal world, you'd coulomb count, with auto calibration at full charge and death, but that's not really practical when the battery's charged from an external source, while the controller is off. Another way might be to somehow factor in the current draw along with the voltage to give a more accurate capacity reading? Not really worth the faff for a one off, though.
 

Tony1951

Pedelecer
Jul 29, 2025
74
26
This is a very fine project. Most interesting. Hat is off to the effort and the degree of expertise. Black box has been turned into something else entirely. Not many people can do that. Hardly any, in fact.
 
  • Like
Reactions: esuark

Sparksandbangs

Pedelecer
Jan 16, 2025
229
82
I've dumped the cadence based power levels.

Latest work is incorporating a speed based soft start. Currently runs from 0 to 9kmph ramping up from a minimum value to the assist level. It will be adaptable in the user settings so can be easily removed or modified if not required.

Going to focus solely on the power delivery for now (until I get distracted by something else). Specifically behaviour around the legal limit.

When that is sorted will work on the 36V code so I can swap batteries.

When that's done I think I should have a good base and will publish.
 
  • Like
Reactions: Jodel and Woosh

saneagle

Esteemed Pedelecer
Oct 10, 2010
9,088
4,057
Telford
I've dumped the cadence based power levels.

Latest work is incorporating a speed based soft start. Currently runs from 0 to 9kmph ramping up from a minimum value to the assist level. It will be adaptable in the user settings so can be easily removed or modified if not required.

Going to focus solely on the power delivery for now (until I get distracted by something else). Specifically behaviour around the legal limit.

When that is sorted will work on the 36V code so I can swap batteries.

When that's done I think I should have a good base and will publish.
When I tried a controller that had power based on pedal speed, the problem was that power decreased when I slowed down going up hills. You need to bear that in mind if you want to include any algorithms that relate power to speed. Also, you need very high power for hill starts. You can't get going if you have a soft start controller. This is what I like about the standard KT controller: You can set the power you want instead of getting what some programmer, who's never ridden an ebike decides.
 

Sparksandbangs

Pedelecer
Jan 16, 2025
229
82
When I tried a controller that had power based on pedal speed, the problem was that power decreased when I slowed down going up hills.
It only did that on the ramp up on pedal speed but I considered what you said previously and removed it.

Also, you need very high power for hill starts. You can't get going if you have a soft start controller.
The soft start is programmed to start from a current set by the user. I've currently got it at the same level as assist 1. So if for example if in level 5 the controller starts at the level 1 current and then ramps it up the level 5 current between 0 and 9kmph. Also this is a user setting not hard coded. If not to taste if can be reduced to 0 disabling the soft start. Also it doesn't affect the throttle settings. If you want there is nothing to stop opening it fully and getting instant full power.

You can set the power you want instead of getting what some programmer, who's never ridden an ebike decides.
Plan is to have the same if you want it but be more configurable. I'm trying to stick closely to the KT settings to get a fair comparison. At that point I will diverge to adapt it to my personal tastes. All of these will be user settings so you can go back to standard if you want.

Some of the things that can be done are wheel speed being exact by setting the wheel circumference in mm. Assistance level settings to whatever you want them to be. Level 1 not powerful enough then bump it up, level 2 not powerful enough then knock it down a bit. Start assist power on the throttle is configurable. Watt meter can be disabled. Maximum current can be set where you like. Battery bars to personal preference.
 
Last edited:
  • Like
Reactions: Woosh

Advertisers