Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Need accurate fuel gauge for use with OW+ with Two-X upgrade #76

Open
two-x opened this issue Jul 14, 2018 · 38 comments
Open

Need accurate fuel gauge for use with OW+ with Two-X upgrade #76

two-x opened this issue Jul 14, 2018 · 38 comments

Comments

@two-x
Copy link

two-x commented Jul 14, 2018

Kevin and I were talking about how those of us with Two-X OW+s could have accurate remaining battery indication.

The Two-X replaces 2.5Ah OW+ battery with 5Ah battery otherwise the same. But it seems the board insists on assuming it has 2.5Ah battery. Symptom is, after full charge, app says 100%. Say you use up 1.25Ah, then the app will say 50%, as if it had a 2.5Ah battery still. But with Two-X that should be 75%.

Kevin suggested (and I am fricken all about) putting a settings switch for Two-X users that corrects the gauge somehow. Is it possible to accurately estimate battery remaining with the info available to us?

My two-x forum is full of all my poor customers wondering how the hell they're gonna know how much juice they got left.

Thanks!
Soren

[email protected]
[email protected]

@ebabel
Copy link
Collaborator

ebabel commented Jul 14, 2018

My OW is broken in that it shows 100% for miles. I'd be all for an implementation that tries to gauge based on voltage. Maybe storing the min and max known voltages in sharedPrefs? Or just guessing on the min voltage?

@muellergit
Copy link

muellergit commented Jul 14, 2018 via email

@ebabel
Copy link
Collaborator

ebabel commented Jul 14, 2018

@muellergit attachment didn't work via email. Care to add directly on github?

@kwatkins
Copy link
Collaborator

kwatkins commented Jul 14, 2018

@muellergit
The %/State of Charge comes directly off the OW (0-100). I assume it keeps an internal voltage chart, that gets out of line occasionally and needing a reset by draining the battery and nosediving on Hillway ave. That's wild yours is cracked @ebabel, have you seen anything else up with the board?

Thoughts on how we can extend the model you have to any battery source? From what I can tell on https://en.wikipedia.org/wiki/State_of_charge this would be an "offline" technique reading the battery current comparing it over time w/ a hash/lookup table. The table would be the model, reset manually or when the board is 100%. Something like that. We could add another "estimated/smart/extended battery %" metric having an option to making that the primary source of truth for battery % off the board.

@two-x
Copy link
Author

two-x commented Jul 15, 2018 via email

@muellergit
Copy link

muellergit commented Jul 20, 2018 via email

@two-x
Copy link
Author

two-x commented Jul 23, 2018

I don't think that's right, that the blue light is based on voltage. When the Two-X is at half-charge, and the app says 1%, the blue light also blinks like 1%.

How about a "auto-calibrate fuel gauge" switch in the app, where, if it is turned on, then every time it hits full-charge, it begins an energy counter. Then it counts Ah in either direction as you use it. If a charger is connected before the board is fully drained, then it's a no-go, it starts over once it hits 100%.
But if the board is ridden till it dies, then it has a complete count of Ah in the battery. It can store that until the next full cycle. The fuel gauge can base its percentage off counting Ah against this.

The problem I see is the fuel gauge only works if the app is always connected. Unless the board reports Ah used? Does it?

@two-x
Copy link
Author

two-x commented Jul 24, 2018

The alternative of course is a lookup table to linearize the voltage reading into a linear fuel gauge. This would be pretty easy except the voltage is also affected by loading of the battery. And given different batteries will skew the voltage differently, now this is a 3-dimensional lookup table or a lookup table with a parameterized post-processing formula. All of a sudden it's not as easy.

But if it could be made to work then it solves the problem of a fuel gauge for alternate battery systems, and also automatically adjusts to stay accurate as a stock battery degrades with use, and wouldn't require the app to stay connected.

I wonder what other ideas people might have? Would it help if I made a ponewheel log of a full discharge/charge cycle on my two-x board for you?

Thank you so much!
Soren

@two-x
Copy link
Author

two-x commented Jul 24, 2018

I'm sorry, I don't mean to sound all preachy. I think what I'm proposing is very much like what you described, muellergit.

Let me know if I can help - I can log data, do research, or whatever (or make the customers do it ;)
S

@muellergit
Copy link

muellergit commented Jul 25, 2018 via email

@muellergit
Copy link

muellergit commented Jul 28, 2018 via email

@kwatkins
Copy link
Collaborator

a friend in the know mentioned this stand-alone fuel-gauge IC https://www.maximintegrated.com/en/products/power/battery-management/DS2782.html
if there is a library that we can implement this in software, that would be the nuts.

as soon as we get the master branch stable, i can take a pass at adding a simple voltage lookup table to at least get this moving...

@muellergit
Copy link

muellergit commented Jul 30, 2018 via email

@biell biell mentioned this issue Sep 7, 2019
@biell
Copy link
Collaborator

biell commented Sep 7, 2019

I have created pull request #92 to resolve (or at least make a first effort resolve) this issue.

@kwatkins
Copy link
Collaborator

Great stuff from mr. @biell! Did some basic smoke tests and looks to be solid enough for master. As soon as we nail down the stability issue (#91) will roll into production.
@two-x to confirm before closing after we get him a solid release :)

@two-x
Copy link
Author

two-x commented Sep 12, 2019 via email

@biell
Copy link
Collaborator

biell commented Sep 12, 2019

My pull request was a first pass to make sure @kwatkins agreed with what I was doing and the methodology was sound, since I am not a Java programmer. Now that I know that I am on the right track, I have started to update the algorithm. My goal is another pull request to get all the hooks right so he can change whatever he wants outside of a Battery.java file, and all of our remaining tweaks can be confined therein.

Luckily, we know the current being drawn, so should be able to mathematically un-do its influence on our delicate voltage value. I've experimented with this some, as well as some deep low-pass filters on the resulting values, and I think it was pretty close to a useful reading approaching 100mV precision. Seems like kinda an uphill battle though.

I would be interested in your findings on how to use draw against voltage and any other filtering ideas. My current development work has me also pulling the current Amps and using that as a smoothing agent. Right now, I am dividing current Amps by 9 and then just adding that value to the current volts. Doing this has made the reading more stable at higher speed and while going down hill.

I am interested in any data you have from full battery drains. Right now, with GEMINI, ponewheel doesn't run long enough to log a full 100% -> 1% battery drain for me to test the math against. So, I am spot-checking periodically. Some of my notes:

  • I was originally thinking the midpoint was 3.2*16=51.2, and now I am thinking it is closer to 51.6
  • I was originally thinking a single equation could model the battery drain, and now I am thinking I might need two (one for voltages above 51.6 and one for voltages below 51.6) --assuming 51.6 is actually the correct number.
  • I want to have a mode whereby, when you fully charge your OW, it uses the OW% at first, then switches to a voltage method. I started out thinking I would take the OW number, divide by 2 then add it to 50. But, I am realizing that my OW+2X more than doubles my AmpHrs, so I am looking for the right equation. Today, I am playing with OW%*55/100+55. Any ideas on that equation would be helpful too.
  • I originally believed that adding up all the cell voltages would be a more stable number and superior than just using the delivered voltage. Now, I am not so sure because the amps correction and the decaying average have made the delivered voltage more stable. Both methods will remain in the code until we can iron this out. Although, looking at the cell voltages is a very clear way to tell when the OW is about to turn off. Setting an alarm for when your first cell gets down to 2.88 will tell you that you are clearly in the danger zone. If someone is traveling at speed, probably notifying them at 2.90 is the best time to send up the red flag.
  • Today I am testing remaining=99.9/(1.0+Math.pow(3, medianVoltage-avgVolts))+1 and it seems OK above 80% battery, it has not worked for me well in the past below 20%.
  • Both 8 and 9 seem to work for an Amperage divisor as a voltage adjustment, but these are guesses and I don't know if there is already a knowledge base out there on how to calculate a draw effect on voltage properly. The appropriate equation is probably non-linear.

If we can do this in a way that also benefits CNR/VNR users, that would be ideal.

@biell
Copy link
Collaborator

biell commented Oct 15, 2019

You can check out the latest attempt, merged into master. This new method carries with it improved voltage calculations and amp draw filtering (adding up the voltage values of each cell is proving more stable than using the reported total voltage). However, that is not the exciting part. The Two-X method (which assumes that each time you charge your OneWheel, you charge it all the way) will keep track of your amphr usage across a long ride, figure out how many amphrs / remaining% there are and keep that progression going. This is proving very accurate and I think everyone will be happy with it. The only rub is that, if you turn your OneWheel on with less than 60% remaining, it doesn't have enough history to perform the calculations and has to fall back on reported cell voltages. I have ridden from 100% down to 1% reliably over a dozen times in testing.

I have about 40 charge cycles on my Two-X, anyone with more care to comment on how this might affect my math? What I am most interested in is what is the real percent battery left when the OW thinks it is at 1%. Will that stay around my personal value of 55% Two-X remaining, or will it slip closer to 50%.

At any rate, we are making progress!

You can review the math in the source tree: app/src/main/java/net/kwatts/powtools/util/Battery.java

@muellergit
Copy link

muellergit commented Nov 27, 2019 via email

@biell
Copy link
Collaborator

biell commented Nov 27, 2019

It should mostly work on your plus. I don't have an XR to test with, so the curve is probably in need of tweaking for the XR.

I would think the Output Voltage and Cell Voltage method could both be tried. I think you will find out that those two methods are highly inaccurate near 100%, and become increasingly accurate as you approach empty. The battery simply fluctuates less at lower end voltages. I think the Cell Voltages method works better.

You can either clone this repository and build it yourself or wait until we get my changes into the development app store. My goal was always to get this all released and confirmed stable first, then spend some time collecting data from people to tweak the parameters for following the voltage curve and make the whole thing more accurate, including at different speeds.

@muellergit
Copy link

muellergit commented Nov 27, 2019 via email

@ocornu
Copy link

ocornu commented Nov 27, 2019

Unfortunately, the only correct way to evaluate the State of Charge is via coulomb counting. One can't do that just using voltage, specially if there is no feedback on the load being applied at the moment of the measurement.
One easy fix would be to swap the BMS 5mΩ shunt for a 2.5mΩ one, therefore registering only half of the current passing through (equals to doubled capacity overall). However, this would also mess with BMS over-current detection circuits. Most of them are there to protect the battery, and the 16S2P of the Two-X can take twice the current, so it should not be a big safety risk.
Another more involved way would be to flash the BMS PIC16F with a custom firmware, adapted to the desired capacity (as it is, battery capacity is hardwired in the code).

@biell
Copy link
Collaborator

biell commented Nov 27, 2019

@muellergit ,

Without the BMS, there are no cell voltages so that one won't work. If the output voltage method it's using BMS data that is also why it doesn't work. But the FM app still shows battery voltage on my Plus without the BMS and so does Ponewheel. Anyway at 52.4v battery voltage the Plus is actually at about 60% charge but it showed 101% in every battery meter mode.

Did you build your own ponewheel from the master tree? 101% should never be displayed as the code sits now.

With the code, as it sits in the repository now, I have 52.3v set to 50% battery, so that is pretty close to what you are saying should show about 60% charge. The Output Voltage method is the least reliable of all the methods I have worked on, but should give you an idea of what you have left as you start to drain the battery, again, becoming more accurate at lower levels to keep you from having the OW run out of battery.

I have put the least effort into perfecting this method, and so the parameters need to be tweaked, I am sure. How amp draw and tire rotation affects the voltage output, and how to smooth that out via decaying average could all be tweaked more over time.

Of all the variables I have to work with, Output Voltage fluctuates the most, and so is the hardest to guestimate from.

@biell
Copy link
Collaborator

biell commented Nov 27, 2019

@ocornu ,

Unfortunately, the only correct way to evaluate the State of Charge is via coulomb counting. One can't do that just using voltage, specially if there is no feedback on the load being applied at the moment of the measurement.

I do use amp draw in my calculations, does that come from the BMS? If so, then I would not be able to help @muellergit, because the amp draw is a critical part of smoothing out the output voltage.

One easy fix would be to swap the BMS 5mΩ shunt for a 2.5mΩ one, therefore registering only half of the current passing through (equals to doubled capacity overall). However, this would also mess with BMS over-current detection circuits. Most of them are there to protect the battery, and the 16S2P of the Two-X can take twice the current, so it should not be a big safety risk.

You wouldn't even need pOnewheel then, right? The regular app would mostly work. My testing shows that, on my board, the max stock OW battery only goes to 44% of my total battery on a hot day and 46% on a cold day vs my Two-X capacity. So, it isn't exactly 50%, but close.

Another more involved way would be to flash the BMS PIC16F with a custom firmware, adapted to the desired capacity (as it is, battery capacity is hardwired in the code).

My guess here is that a FM firmware update to the BMS allowing a maximum Amp Hours capacity of 5.5 would make the vendor app just work with a Two-X, but I could be wrong.

My primary method for a Two-X right now is my "Fully Charged Two-X" option, which is very reliable assuming each time you charge, you charge until the charger light goes green and you start your ride with 60% or more battery remaining. Under these circumstances, I keep track of how many amp hours drawn equals what percentage of the total battery capacity, and I keep that method going for the user even after the OW thinks it is at 1%. If you start a ride with less battery, I fall back to the method of using the Cell Voltages reported, which is OK for accuracy from 20-40%, pretty good for accuracy from 10-20%, and reliable for accuracy from 1-10%.

@muellergit
Copy link

muellergit commented Nov 27, 2019 via email

@ocornu
Copy link

ocornu commented Nov 27, 2019

I do use amp draw in my calculations, does that come from the BMS? If so, then I would not be able to help @muellergit, because the amp draw is a critical part of smoothing out the output voltage.

It does come from the BMS indeed. The worst considering our issue is that only instantaneous current is transmitted to the controller. And, iirc, to the BLE app. Thus if an app looses connection at some point it cannot maintain proper coulomb counting/SoC.
Also, it's not in mA or any common unit, but a simple integration of 12-bit ADC samplings from the PIC16F. Which explains, I assume, why my version of ponewheel (at least) does not report current correctly (understand: in a meaningful unit).

You wouldn't even need pOnewheel then, right? The regular app would mostly work.

Right. In fact, this problem cannot be solved at the app level, afaik. Thus fixing it, whether via a shunt swap or a custom firmware would solve it for all apps. Which isn't a bad thing in itself, tbh.

My testing shows that, on my board, the max stock OW battery only goes to 44% of my total battery on a hot day and 46% on a cold day vs my Two-X capacity. So, it isn't exactly 50%, but close.

These numbers are all nominal. They can vary from one battery pack to another, from one season to another or, in your case, from a 1P pack to a 2P one (relationship between current draw and capacity is not linear: if you put 2 packs in parallel, you don't get exactly twice the capacity in practice, you should get more).

My guess here is that a FM firmware update to the BMS allowing a maximum Amp Hours capacity of 5.5 would make the vendor app just work with a Two-X, but I could be wrong.

There is no provision in the BMS firmware for remote update. In other words, the controller cannot upgrade the BMS firmware. So this is not going to happen, ever. :p

@ocornu
Copy link

ocornu commented Nov 27, 2019

Yeah, amp draw is from the BMS so that is why that mode doesn't work on my Zombie.

May I know what happened to your BMS? For what it's worth, i'm fixing them (in case it might help). :)

@biell
Copy link
Collaborator

biell commented Nov 27, 2019

My testing shows that, on my board, the max stock OW battery only goes to 44% of my total battery on a hot day and 46% on a cold day vs my Two-X capacity. So, it isn't exactly 50%, but close.

These numbers are all nominal. They can vary from one battery pack to another, from one season to another or, in your case, from a 1P pack to a 2P one (relationship between current draw and capacity is not linear: if you put 2 packs in parallel, you don't get exactly twice the capacity in practice, you should get more).

Right, once I have more data, and other Two-X users try the app, then I was thinking of making an application setting which could control for variations in the cell packs used and battery age/charge cycles. The BMS will do a lot of that for me, it just might mean that 44,45,46 will become 43,44,45 (or something similar).

If you came up with an easy hardware fix, I would consider it. If you could keep us up-to-date on your progress, that would be great. Right now, for my board, I can reliably draw it from 100 to 1% on every ride with my most up-to-date code. I know it isn't perfect, but it is getting the job done for me. With some external testing and code tweaking, I think it would work well enough for a bunch of other users too.

@biell biell mentioned this issue Nov 27, 2019
@ocornu
Copy link

ocornu commented Nov 27, 2019

If you came up with an easy hardware fix, I would consider it. If you could keep us up-to-date on your progress, that would be great.

Sure. Right now i've got a beta firmware for XR BMS custom capacity batteries. OW+ is a slightly different chip with a slightly different pin-out, but i'll get there eventually. ^^

@TomasHubelbauer
Copy link

Sorry for a rookie question and notification noise, but how does one get ahold of beta firmware exactly? Through reverse engineering the official app code and then guessing the update service URLs by appending ascending firmware revision numbers until there's a hit for yet-unreleased, but nonetheless at-the-URL-served firmware?

I'm asking this because I'd like to inspect the firmware of the Pint. I have no hardware experience so there's no way I'm going to be able to extract it from the chip's EEPROM and AFAIK there were no OTA updates to the Pint's firmware yet so presumably the update service the app uses shouldn't carry any updates yet? (I'm assuming the original firmware blob is never served by the update service since it comes with the board from the factory and only the OTA revisions make it to the update repository.)

@ocornu
Copy link

ocornu commented Nov 28, 2019

@TomasHubelbauer There are several micro-controllers on a OW, each with their own firmware. In this thread we're discussing the BMS firmware, which is responsible for battery monitoring and the Two-X capacity issue. From what I understand, you're looking for the controller firmware (the one that gets udpdated OTA), another beast entirely. :-)

@TomasHubelbauer
Copy link

@ocornu Thanks for entertaining the question and for the clarification. This is definitely fascinating. I will try to look into this further for a few mods that I have in mind. Thanks again and have a good one 🙂

@muellergit
Copy link

@biell I was just thinking of a potential new "Zombie" method to estimate battery capacity remaining from voltage alone while moving. I have been riding my Plus without the BMS for about a year now so to estimate my charge remaining I need to stop to check battery voltage in the app (or look at the power button pulses). Since your new Voltage based battery code uses the current amps to compensate for voltage sag, they don't work for my Zombie Plus without the BMS.

What about using a moving peak voltage over the previous minute, but throw out any voltage peak that is more than a certain amount (0.5v perhaps) above the current peak to filter out braking regen voltage spikes? Just wondering your thoughts about it based on what you have done.

Before my BMS failed I used Ponewheel to log data and so I will try to run a few simulations of the method using that data to see how noisy it is and if it can be smoothed enough to be useful. Thanks for any thoughts you have about how well this might work.

@biell
Copy link
Collaborator

biell commented Mar 18, 2020

We can work on that. Right now I have major responsibilities at work to support our COVID-19 response. But, I will help you work on this as time allows. It will be easy to add, but it will take time to tweak.

Basically, all we need to do is add another option in the drop-down, then make an output choice for that shared preference. All the variables are there, we will just be using fewer of them to make the guess. What you want to do is only about an hour of work for revision 1, once you have an idea of how the math should play out.

Maybe also think about rounding to the nearest 5 above 20 to smooth it out, as the fluctuations are quite heavy when there is a lot of battery left.

@muellergit
Copy link

I need to write a little code to run through my data to see if there is a way to get good smoothness without needing a long moving average. But a long moving average of voltage looks fairly good actually. Especially over an order of 1000 voltage measurements. But my data was sampled once per second so not sure how the smoothing works if sampling was done 10 or 100 times per second.

I have a TTGO T-wristband coming that I am going to play around with also. There is the TinyWheel project that currently shows the speed and battery level:

https://github.com/FabioBatSilva/TinyWheel

@biell
Copy link
Collaborator

biell commented Mar 19, 2020

Smoothing out does a pretty good job, and I use that technique with a rolling average. But, the equation I uses for my Voltage only line is calculated to be used with a layer of smoothing applied from current amp draw. Without that, the line may need to be adjusted slightly. We can still make a guess without amp draw, it will just be a little less accurate, We could substitute something in using speed, but that would probably mess things up when you go downhill.

That device looks pretty cool. If it supported my XR model, I would totally pick one up for that.

@muellergit
Copy link

I thought about speed as a correcting factor in place of current but speed isn't well correlated with current since you can be going the same speed while either braking, accelerating, or maintaining speed, and any additional balancing current is completely uncorrelated.

I'm getting useful looking results with Vsmooth = Vsample / 600 + Vsmooth * 599 / 600 which is simple and doesn't need to save any previous voltage samples. Vsmooth just need to initialize Vsmoothprevious to the starting voltage. I can't tell from my once per second data logging I have access to if the sampling rate will make a difference in smoothness using this method, but the Vsmooth curve looks like it tracks the expected battery discharge curve throughout the entire range of the ride. Using 600 as my smoothing "decay" factor was arbitrary also and could be adjusted more or less depending on sampling rate and smoothness needed. It doesn't look like I need to filter out any extreme regen spikes since I am only adding 1/600th of each voltage sample to 599/600th of the previous sample voltage and the positive and negative voltage spikes mostly cancel themselves out. Vsmooth using this formula and my dataset with 1 second sampling rate and 600 decay factor looks like it matches up with what the voltage would be while stopped, but that might just be a lucky coincidence about 600 samples taking 10 minutes and my riding. Not sure if you follow, but I think I have a good starting point to try out while riding and adjust based on results.

Do you know how often the Bluetooth parameters are pulled in Ponewheel?

@biell
Copy link
Collaborator

biell commented Mar 20, 2020

That is a much larger decay than my decaying average, I divide by 50:

private static final double DECAY_NEW_STEP     = 0.02;
private static final double DECAY_OLD_STEP     = 1.0-DECAY_NEW_STEP;

I can't remember how often the data comes in, but is more like seconds per data element, not data elements per second.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

7 participants