Making a torque throttle instead of a speed throttle for a cheap controller

Joined
Feb 9, 2018
Messages
37
Location
Prescott, Arizona
Hello all, I recently made this device and thought I'd share it with the community, both to help others and to possibly get others to help me.

Essentially, it's an Arduino hooked up to the signal from the twist/thumb throttle, a PWM smoothing circuit which is in turn connected to the throttle signal the controller receives, and a contactless-type current sensor, like this one: https://www.amazon.com/Current-WCS1...2R/ref=olp_product_details?_encoding=UTF8&me=. It is powered by the power wire that goes to the throttle from the controller.

It works by mapping the throttle input to a target current, then modulating the throttle output signal to achieve this current. It should work with any controller that has a hall sensor throttle signal.

The smoothing circuit doesn't have to be perfect, just enough that the controller won't receive an unfiltered PWM signal, because it won't recognize that as a throttle signal. It can also never receive a straight 5 volts, or whatever the throttle power voltage is, because it will trigger a "stuck throttle" condition in the controller and cause it to shut down throttle input as a safety measure.

I will soon be implementing a proportionality to the feedback function so that it will change the throttle more drastically when it is farther from its target current. This will reduce throttle lag and increase safety, because as of right now, it takes a long time to "spool up" and "spool down" the throttle signal, essentially meaning that there is a significant delay between punching the throttle and getting to full current, or releasing it and getting to zero. This delay is on the order of a second or two. As such, I recommend that until there is such a proportionality, only those who have brake lever shutoffs use this. I do not have such sensors, and so have had a couple of instances where I was fighting the motor with my brakes while making a sudden stop. I take no responsibility for any harm or damage to you or your property or the property of others incurred by messing about with your throttle signal.

Proportionality is only a part of a Proportional-Integral-Derivative control loop, though, so if someone who has more experience with Arduino could point me in the right direction to implement the rest, I would be grateful for the extra help and smoothness of the control.

Code here. Sorry if it's over-commented, I just wanted to make sure someone who isn't familiar with Arduino can still understand what is happening.
Code:
const int throttleOutPin = 9; // The pin on which the throttle output to the controller is located. If you change this, you may also need to change the address
                            // of the referenced clock in the second-last line of the setup section. See https://playground.arduino.cc/Main/TimerPWMCheatsheet for more info.
const int throttleInPin = A0; // The pin on which the arduino will receive the incoming throttle signal
const int currentInPin = A1;  // The pin on which the arduino will recieve the current reading


const int minVoltIn = 1222;   // The minimum voltage the arduino should expect to receive from the throttle in mV. Measure your own throttle for a perfect value, but 1200 will do.
const int maxVoltIn = 4257;   // The maximum voltage expected from the throttle in mV. I set mine a little higher than actual so that the arduino never goes to 100% pwm duty cycle.
const int minVoltOut = 980;   // The minimum voltage the arduino will output in mV. It is higher than the throttle's because my smoothing circuit reduces the voltage slightly.
const int maxVoltOut = 4999;  // The maximum voltage the arduino will output in mV. It is higher than the throttle's because my smoothing circuit reduces the voltage slightly.
const int maxCurrent = 22000; // The maximum current the arduino will ever attempt to maintain flowing to the motor. Set this to the max of your motor or controller, whichever is lower.


int targetCurrent = 0;        // A placeholder for the current the arduino aims to maintain in mA
int throttleIn = 0;           // A placeholder for the present value of the throttle input
int throttleOut = 0;          // A placeholder for the present value of the throttle output
int current = 0;              // A placeholder for the present value of the measured current


int maxOut = 0;               // A placeholder for the maximum output pwm, with 255 being 100% duty cycle
int minOut = 0;               // A placeholder for the minimum output pwm, with 0 being 0% duty cycle
int maxIn = 0;                // A placeholder for the maximum throttle input voltage, with 1023 being 5 Volts
int minIn = 0;                // A placeholder for the minimum throttle input voltage, with 0 being 0 Volts


void setup() {
  // Mapping the throttle voltages from voltages to numbers the arduino can use
  maxOut = map (maxVoltOut, 0, 5000, 0, 255);
  minOut = map (minVoltOut, 0, 5000, 0, 255);
  maxIn = map (maxVoltIn, 0, 5000, 0, 1023);
  minIn = map (minVoltIn, 0, 5000, 0, 1023);


  // Changing the clock speed of the clock which controls the ouput pin to the highest setting, to make the pwm output easier to smooth out
  TCCR1B = (TCCR1B & 0b11111000) | 0x01;


  // Start the serial communication with the computer, to be able to troubleshoot faulty operation. Comment this out to increase operation speed and reduce lag.
  Serial.begin(9600);
}


void loop() {
  throttleIn = analogRead(throttleInPin);                         // Read the throttle setting
  targetCurrent = map(throttleIn, minIn, maxIn, 0, maxCurrent);   // Generate a target current based on the throttle setting
  targetCurrent = targetCurrent - 0;                              // A line to reduce or increase the current manually, if you need to do that for whatever reason. I don't.
  current = map(analogRead(currentInPin), 0, 1023, 0, 5000);      // Read the analog voltage from the current sensor and map it to a range from 0 to 5000 mV
  current = current - 2500;                                       // Set the numeric value to the voltage at which your current sensor reads zero. If your sensor is installed facing
                                                                // the other way, you may need to reverse "current" and the numeric value in the subtraction.
  current = current * 12;                                         // Set the numeric value to the ratio of mA to mV of your particular sensor.


  // The feedback loop to keep current stable. Ideally, this would be a PID control, but I don't really know how to implent that, so the controller surges a little at low currents.
  if (current > targetCurrent) {
    if (throttleOut > minOut) {
      throttleOut = throttleOut - 2;
    }
  }
  if (current < targetCurrent) {
    if (throttleOut < maxOut) {
      throttleOut = throttleOut + 2;
    }
  }


  analogWrite(throttleOutPin, throttleOut);   // Send the output that's been calculated to the controller


  // Tell any computer attached by serial connection the status of key values. This requires the "Serial.begin" line to be enabled. Comment these out to increase operation speed and reduce lag.
  Serial.print(throttleIn);
  Serial.print( "\t" );
  Serial.print(targetCurrent);
  Serial.print( "\t" );
  Serial.print(current);
  Serial.print( "\t" );
  Serial.println(throttleOut);
}



Let me know what you think, I'd like to receive some feedback on this project that isn't just a series of numbers! :p
 
AviatorTrainman said:
Essentially, it's an Arduino hooked up to the signal from the twist/thumb throttle, a PWM smoothing circuit which is in turn connected to the throttle signal the controller receives, and a contactless-type current sensor, like this one.
Like which one? (you don't have any images attached to the post, or links to anything (like parts lists or circuit diagrams, etc) elsewhere),


It works by mapping the throttle input to a target current, then modulating the throttle output signal to achieve this current. It should work with any controller that has a hall sensor throttle signal.
So kind of like the Cycle Analyst's alternate throttle methods?

I don't know enough about programming to read the code included, but:

If you:

-- assign a 0%-100% to the throttle input voltage, where 0% = the lowest possible throttle voltage from your particular throttle, and 100% = the highest possible voltage from your particular throttle

-- assign a minimum battery current, presumably zero amps to the 0% throttle, and a maximum battery current, presumably the maximum amps your controller can pull under load, to the 100% throttle

-- map everything between linearly, so it's all a 1:1 control

Then it should do about what a controller with torque (current) throttle would do directly, although at least some (probably most) of those actually monitor phase current, rather than battery.


The smoothing circuit doesn't have to be perfect, just enough that the controller won't receive an unfiltered PWM signal, because it won't recognize that as a throttle signal.

It does need to have a short enough time between pulses that controllers with a fast response time (no "soft start") will not "see" the pulses and react to them by pulsing it's motor output. (which might or might not be detectable or feelable, depending on system and conditions). Most controllers probably won't be designed to react very quickly to throttle input, but some may be able to, especially those that are higher-end or programmable throttle response (though these may already have torque (current) throttle control).

But...why (presumably) PWM a digital output? Why not just use an analog output and actually set the voltage there directly? (preferably using an isolating op-amp circuit between the output and the controller's input, and also using one between the throttle's ouptut and the MCU's input, to prevent MCU damage if something goes wrong with wiring/etc somewhere).


This will reduce throttle lag and increase safety, because as of right now, it takes a long time to "spool up" and "spool down" the throttle signal, essentially meaning that there is a significant delay between punching the throttle and getting to full current, or releasing it and getting to zero. This delay is on the order of a second or two.
That's a really serious issue, and would make it unusable for someone like me that rides in traffic.

What creates the delay?

You should be able to have essentially instant response (which is desirable, generally), so the throttle output directly tracks the throttle input * actual battery current demand.
 
My bad, the "this one" was supposed to be a link. I'll update the original post to include it.

What you say about mapping the voltage to a current value is exactly what I've done with the code. The reason I use a PWM signal is simply because that is what the Arduino (a microcontroller) has to offer. A filter circuit is just a resistor and capacitor, and I used just some that I had laying around. I'll have a circuit diagram posted by the end of the day. The Arduino's maximum PWM frequency (without overclocking the processor or messing around with the time constants) is 32 kHz, and that seems to not be fast enough, with the controller just running through the soft start, going to zero power, then repeating, regardless of the duty cycle.

The throttle lag comes fundamentally from how I've implemented the feedback loop at this time. It can really be broken down into 3 steps:

1. Read the throttle value and map it to the target current value
2. Read the actual current value
3. If the actual current is lower than the target current, increase the throttle value by the set amount. If it is higher, decrease the throttle value by the set amount.
Repeat

The lag/delay comes from the amount of time it takes to run through the necessary number of iterations to reach the throttle setting that would yield the desired current at the present speed and load. As the code stands right now, it is possible to increase the value the throttle is increased or decreased by - this increases the speed of response, but also increases the "coarseness" of the control, and significantly increases the amount of oscillation or surging when trying to maintain a set current.

The first thing I am coding in tonight is a failsafe which basically says "If the throttle signal to the controller right now is above x% and the throttle signal from the throttle is below y%, cut the throttle completely." I'll test it tonight with 10 percent for x and 5 percent for y. This will make dropping the throttle instant, but will not affect the lag otherwise. Making the proportionality part of a PID loop will essentially change the "set value" from step three of the control loop to reflect how far the current is from its target, with stronger changes being made at higher discrepancies. Essentially, if the desired current is 15 amps and the present value is 1 amp, it will change the throttle much more quickly than if the present value were 13 amps. This will greatly reduce lag, but can only dampen oscillations so much - I just hope enough to make them unnoticeable.

I can't simply map the input to the output without measuring the result, because a cheap speed controller like mine will change the power to the motor based on the speed with the same throttle setting, hence the feedback loop. The Arduino can't tell what speed the bike is going, and so can't really tell what the controller will do with the given signal. It is essentially "fighting" the controller at all times that the throttle is not set to 100 or 0, by seeing what the controller will do with the signal it gives, then adjusting said signal until the controller is doing what it's supposed to.

I'm not familiar with the cycle analyist at all, so I'll look into it. It's possible that what I've done is the $25 version of that.
 
If you attached the non-contact current meter to one of the phase wires wouldn't you then be controlling phase amps rather than battery amps?
 
Grantmac said:
If you attached the non-contact current meter to one of the phase wires wouldn't you then be controlling phase amps rather than battery amps?

I as far as I can tell, yes. You would just need a function in the program to take the DC equivalent of the AC current there. I've updated my code with both the proportionality and the failsafe, so the lag is now less than half a second when throttling up or down, and less than a millisecond when releasing the throttle all the way. (Yes, I mean that. Dropping the throttle in programming now happens faster than the spring operates).

New code here. The changes are the 3 lines about the "delta" variable right before the feedback loop section, and the if statement right after "void loop() {", which is the part of the code that immediately cuts power if you let go of the throttle.
Code:
const int throttleOutPin = 9; // The pin on which the throttle output to the controller is located. If you change this, you may also need to change the address
                            // of the referenced clock in the second-last line of the setup section. See https://playground.arduino.cc/Main/TimerPWMCheatsheet for more info.
const int throttleInPin = A0; // The pin on which the arduino will receive the incoming throttle signal
const int currentInPin = A1;  // The pin on which the arduino will recieve the current reading

const int minVoltIn = 900;   // The minimum voltage the arduino should expect to receive from the throttle in mV. Measure your own throttle for a perfect value, but 1200 will do.
const int maxVoltIn = 4257;   // The maximum voltage expected from the throttle in mV. I set mine a little higher than actual so that the arduino never goes to 100% pwm duty cycle.
const int minVoltOut = 980;   // The minimum voltage the arduino will output in mV. It is higher than the throttle's because my smoothing circuit reduces the voltage slightly.
const int maxVoltOut = 4800;  // The maximum voltage the arduino will output in mV. It is higher than the throttle's because my smoothing circuit reduces the voltage slightly.
const int maxCurrent = 22000; // The maximum current the arduino will ever attempt to maintain flowing to the motor. Set this to the max of your motor or controller, whichever is lower.

int targetCurrent = 0;        // A placeholder for the current the arduino aims to maintain in mA
int throttleIn = 0;           // A placeholder for the present value of the throttle input
int throttleOut = 0;          // A placeholder for the present value of the throttle output
int current = 0;              // A placeholder for the present value of the measured current

int maxOut = 0;               // A placeholder for the maximum output pwm, with 255 being 100% duty cycle
int minOut = 0;               // A placeholder for the minimum output pwm, with 0 being 0% duty cycle
int maxIn = 0;                // A placeholder for the maximum throttle input voltage, with 1023 being 5 Volts
int minIn = 0;                // A placeholder for the minimum throttle input voltage, with 0 being 0 Volts

int delta = 0;                // A placeholder for the value the throttle should be changed by

void setup() {
  // Mapping the throttle voltages from voltages to numbers the arduino can use
  maxOut = map (maxVoltOut, 0, 5000, 0, 255);
  minOut = map (minVoltOut, 0, 5000, 0, 255);
  maxIn = map (maxVoltIn, 0, 5000, 0, 1023);
  minIn = map (minVoltIn, 0, 5000, 0, 1023);

  // Changing the clock speed of the clock which controls the ouput pin to the highest setting, to make the pwm output easier to smooth out
  TCCR1B = (TCCR1B & 0b11111000) | 0x01;

  // Start the serial communication with the computer, to be able to troubleshoot faulty operation. Comment this out to increase operation speed and reduce lag.
  Serial.begin(9600);
}

void loop() {
  throttleIn = analogRead(throttleInPin);                         // Read the throttle setting

  if (throttleIn < (minIn + 50) && throttleOut > (minOut + 25)) { // Before doing any other calculations, figure out if the throttle needs to be cut immediately
    throttleOut = minOut;
  }
  else {
    targetCurrent = map(throttleIn, minIn, maxIn, 0, maxCurrent);   // Generate a target current based on the throttle setting
    targetCurrent = targetCurrent - 0;                              // A line to reduce or increase the current manually, if you need to do that for whatever reason. I don't.
    current = map(analogRead(currentInPin), 0, 1023, 0, 5000);      // Read the analog voltage from the current sensor and map it to a range from 0 to 5000 mV
    current = current - 2500;                                       // Set the numeric value to the voltage at which your current sensor reads zero. If your sensor is installed facing
                                                                  // the other way, you may need to reverse "current" and the numeric value in the subtraction.
    current = current * 12;                                         // Set the numeric value to the ratio of mA to mV of your particular sensor.
    
    delta = targetCurrent-current;                                  // Perform a few operations to determine the delta value
    delta = abs(delta);
    delta = map (delta, 0, maxCurrent, 0, 10);

    // The feedback loop to keep current stable. Ideally, this would be a PID control, but I don't really know how to implent that, so the controller surges a little at low currents.
    if (current > targetCurrent) {
      if (throttleOut > minOut) {
        throttleOut = throttleOut - delta;
      }
    }
    else if (current < targetCurrent) {
      if (throttleOut < maxOut) {
        throttleOut = throttleOut + delta;
      }
    }
  }
  if (throttleOut > maxOut){
    throttleOut = maxOut;
  }
  else if ( throttleOut < minOut){
    throttleOut = minOut;
  }
  analogWrite(throttleOutPin, throttleOut);   // Send the output that's been calculated to the controller

  // Tell any computer attached by serial connection the status of key values. This requires the "Serial.begin" line to be enabled. Comment these out to increase operation speed and reduce lag.
  Serial.print(throttleIn);
  Serial.print( "\t" );
  Serial.print(targetCurrent);
  Serial.print( "\t" );
  Serial.print(current);
  Serial.print( "\t" );
  Serial.println(throttleOut);
}

In addition, here's a schematic I drew up:
https://imgur.com/a/VlsVwR3
arduino throttle control.PNG
Sorry it's messy, I wasn't really sure how to go about making it clear that the Red and Black lines from the controller are VCC and Ground.

Power delivery is very smooth now, with the "surging" being limited to about ±5 watts, which I can't feel while riding. I certainly got a workout carrying my bike up and down 2 flights of stairs each time I wanted to change a value in the new code!

It's possible a full PID solution wouldn't be required, since this seems much more usable than I had anticipated.
 
AviatorTrainman said:
What you say about mapping the voltage to a current value is exactly what I've done with the code. The reason I use a PWM signal is simply because that is what the Arduino (a microcontroller) has to offer.
AFAIK it also has analog outputs:
https://www.allaboutcircuits.com/projects/using-the-arduinos-analog-io/

I suppose there are different models and maybe what you have doesn't have any analog outs, just analog ins?

The catch with an RC filter is that it can affect the time it takes for the otuput voltage to settle, though if the PWM frequency is high, the RC constant can be so short that it doesn't matter on a human time scale.


The lag/delay comes from the amount of time it takes to run through the necessary number of iterations to reach the throttle setting that would yield the desired current at the present speed and load. As the code stands right now, it is possible to increase the value the throttle is increased or decreased by - this increases the speed of response, but also increases the "coarseness" of the control, and significantly increases the amount of oscillation or surging when trying to maintain a set current.
Is it possible the code could be better optimized, to take less clock cycles? (sorry I don't know how the arduino code itself works, just the basics of how programming in general works).

Or:

If you have to have it incrementally change the throttle, instead of just directly setting the throttle output to the value that should give the demanded current, and then verifying that demanded current is actually occurring and not being exceeded, then perhaps have the throttle response be kind of a logarithmic function: Make the change in 1/2 of total value increments.

So, if the throttle is demanding 100A, and actual current is 0A, then the controller sets throttle to demand 50A, and checks the actual current and the throttle demand.

Then if the demand hasn't changed, and the current is at 50A, it then increases throttle output to demand 75A, and so on.

If present current is 100A, and throttle demand is suddenly changed to 0A, then the opposite of the above occurs. (although, I would be inclined to always *drop* output throttle directly matched with actual throttle, since throttle down may be VERY important).

Thus it would quickly respond to throttle demands, but still roll onto the power rather than slamming it on.





I can't simply map the input to the output without measuring the result, because a cheap speed controller like mine will change the power to the motor based on the speed with the same throttle setting, hence the feedback loop. The Arduino can't tell what speed the bike is going, and so can't really tell what the controller will do with the given signal. It is essentially "fighting" the controller at all times that the throttle is not set to 100 or 0, by seeing what the controller will do with the signal it gives, then adjusting said signal until the controller is doing what it's supposed to.

I'm not familiar with the cycle analyist at all, so I'll look into it. It's possible that what I've done is the $25 version of that.
I think that you might find it does what you want already, and it does have the ability to monitor speed as well as battery current, throttle, presets, temperature, etc. https://www.ebikes.ca/product-info/cycle-analyst-3.html for the full featured one, or https://www.ebikes.ca/product-info/cycle-analyst.html for the basic one. The first link also has a link to Teklektik's UUG Unofficial User Guide, which explains a fair bit of stuf that mght be helpful to your project, as do a lot of posts in the thread it links to.

But I would like to see what you come up with for this project; there are a number of systems that could use this device that don't really need a CA (they already have a display, power monitoring, etc).
 
AviatorTrainman said:
Grantmac said:
If you attached the non-contact current meter to one of the phase wires wouldn't you then be controlling phase amps rather than battery amps?

I as far as I can tell, yes. You would just need a function in the program to take the DC equivalent of the AC current there.
AFAIK from the bits I've read in various controller development threads, you would want to read at least two of the three phases.



In addition, here's a schematic I drew up:
image
Sorry it's messy, I wasn't really sure how to go about making it clear that the Red and Black lines from the controller are VCC and Ground.
It doesn't display an actual image, just the word "image". If you attach it to your post directly, then anyone that can see the post can see the image (and it isn't lost when the external site goes away or changes their policies).

I certainly got a workout carrying my bike up and down 2 flights of stairs each time I wanted to change a value in the new code!
Sounds like you need a bluetooth app for that. ;)
 
So, if the throttle is demanding 100A, and actual current is 0A, then the controller sets throttle to demand 50A, and checks the actual current and the throttle demand.

Then if the demand hasn't changed, and the current is at 50A, it then increases throttle output to demand 75A, and so on.
While I think this would be the best way to implement this control, as of yet I haven't figured out how I could do that without a speed sensor hooked up, and a dynamometer for taking measurements to make a lookup table. This stems from the fact that the controller handles throttle inputs as target speed - half throttle at zero speed results in maximum current, and half throttle at top speed results in zero current. The response to a given throttle input is a function with speed as a variable, and I don't know the function or have any way of measuring the speed. I could have this in the code by setting the "target current" variable to half of what the user is demanding, ramping up to that, then halfway again, etc., but I can only see this as causing more delays, not fewer.

Is it possible the code could be better optimized, to take less clock cycles? (sorry I don't know how the arduino code itself works, just the basics of how programming in general works).
That's a perfectly valid question, and the answer is probably yes. I have an interesting result with that, though.
I have a few lines of code in there that tell the arduino to communicate via USB with a computer, for debugging purposes - it sends the present throttle input, target current, actual current, and throttle output to a display on my laptop. This code keeps on running even when I disconnect the computer, as the arduino keeps sending data over the cable, without ever verifying that the computer is hooked up or receiving it.
I decided that "commenting out" these lines of code (essentially, telling the program that uploads the code to the arduino to ignore them) would be a good move to shorten the time between iterations, essentially making the code run faster. When I did this, though, the surging came back with a vengeance. It wasn't the same surging as before, though. At a frequency of about 1 Hz, the current would gradually ramp up to about 1.5 times what I wanted, then suddenly drop to maybe half of the target. I can't think of how this could be entirely a fault of the arduino, since it increases and decreases the current at the same rate unless the throttle input is below 5%. I suspect this has something to do with the "soft start" function of my controller, but since I don't have a controller without this feature, I can't verify that speculation. It seems that the slowness in the code introduced by this vestigial function is what's keeping the oscillation in check. Without a derivative term in the code, I have no way of dampening these oscillations aside from reducing the response speed of the feedback loop - which introduces throttle lag.

Take a look at this animated graph from the Wikipedia article on PID control:
https://upload.wikimedia.org/wikipedia/commons/3/33/PID_Compensation_Animated.gif

Basically, the proportional part of the loop (Kp) is implemented by mapping the difference between target and actual to the "delta" value which dictates how quickly the signal should change. I have this.

The integral part of the loop (Ki) is implemented by how the code reacts to discrepancies close to the target - it keeps tweaking the output up or down until the target is reached.

The derivative part of the loop (Kd) is not implemented, and as such, there is no damping in the system.

I can't come up with a very good analogy, but the effect is the same as if you have a load on a spring, and you are trying to keep the load at a set height. You can raise or lower the platform the spring is on, and so you do so until the load reaches the height you want. The energy put into the spring by accelerating the platform upwards is now being released into the load, though - it keeps traveling upwards. You lower the platform to compensate, and the same thing happens in reverse. If you put some sort of damping device on the spring, like a shock absorber or friction brake, the oscillation will dissipate over time - more quickly if your damper is stronger. This is the derivative portion of a control loop. The arduino, however, does not do this, and so the load and platform oscillate, with the average height of the load being pretty close to the target. Sorry if that's too complicated/convoluted - I did my best.
 
AFAIK it also has analog outputs:
https://www.allaboutcircuits.com/projec ... analog-io/

I suppose there are different models and maybe what you have doesn't have any analog outs, just analog ins?
Yes, that’s right.
That article says farther down that the Arduino doesn’t actually have a true analog output, rather PWM only, but what I found in my research is that there is a certain model, the “due”, which has 2 built in Digital to Analog converters, but it is a $34 board, and its maximum system voltage is 3.3 volts. The board I have is the most basic in the lineup, the “UNO”, and so whatever code I write here should function with any of the more complicated ones, or with any of the cheap clones.

I've updated my post from yesterday to include a link to the image directly, instead of using (img)link(/img), since I don't know how to insert an image directly.
 
Bad news, I won’t be able to test for a while. I’ve been having battery issues since late February, like cutting out over speed bumps, and I figured it was a loose connection. I opened up my battery today, and found this:
https://imgur.com/gallery/wDPgJwY


I count myself extremely lucky for 2 reasons. One, it was a clear night last night, so I stored my bike outside instead of in; and two, this cell from the middle of the pack did not cause any visible damage to any others (i.e. no lithium fire), although the one it was in parallel with is probably dead too. I found a stray nickel strip melted to the bottom of the bottle when I opened it up, so I assume this was my loose connection, and then somehow after some time it touched both the cap and the shoulder of this cell. This morning was the first that it wouldn’t take a charge, which is why I opened it up today. I will completely dissassemble the pack, and maybe if at least 20 cells of the 26 are okay, I’ll reassemble it as a 36v (or maybe 44v?) pack until I can get new cells in.
 
FWIW, I can only see the tiny little thumbnails to the right of the actual image, on that website. I don't know if any of those are thumbnails of your images, but I doubt it, given that none of seems to be a schematic (too small to clearly see though). I expect their site is either using third-party scripts or something to display their images, which my browser won't let happen (I have deliberate blocks against this to prevent problems).

If you use the attachments tab below the text entry box when posting, your images will show up in hte post itself, for anyone that can see the post (as long as they are not actually blocking images). I usually resize my images to 600 pixels wide but much bigger images will upload fine.


I guess I misunderstood the Arduino capabilities. Sorry about that. :(


AviatorTrainman said:
While I think this would be the best way to implement this control, as of yet I haven't figured out how I could do that without a speed sensor hooked up, and a dynamometer for taking measurements to make a lookup table. This stems from the fact that the controller handles throttle inputs as target speed - half throttle at zero speed results in maximum current, and half throttle at top speed results in zero current. The response to a given throttle input is a function with speed as a variable, and I don't know the function or have any way of measuring the speed.
Maybe I'm misunderstanding, but I don't think you need to worry about what the controller sees as speed, because you're not trying to control speed, all you're doing is trying to control motor torque, which is approximately controlled by battery current (since you don't presently have access to teh actual phase currents).

So what you describe above as happening is actually what you want it to do, as long as the Arduino is fast enough to loop thru the current and throttle checks and outputs (and the controller responds fast enough to the changes), AFAIK.

For example: The Cycle Analyst doesn't have to monitor speed or have a lookup table for the translation, though it may be using the whole PID system, rather than just part of it; I don't remember which parts use what in there, though it's probably discussed in Teklektik's UUG. It's just monitoring throttle input voltage and current, for it's torque (current) throttle, processing those with any limits that have been set in it, and outputting the appropriate throttle voltage to the controller. (it can monitor speed, as a completley separate speed limiting system, but it still works even if you don't hook the sensor up). It also doesn't have any significant lag.

I'm sorry I don't know how all this works in detail inside the CA (or anything else that does this kind of thing)...I sometimes have an "intuitive" grasp of how stuff works, but sometimes I'm just plain wrong, or misunderstand something that makes my assumptions useless. :oops: But I like to figure things out, and I'm usually really good at it...eventually. :)




I decided that "commenting out" these lines of code (essentially, telling the program that uploads the code to the arduino to ignore them) would be a good move to shorten the time between iterations, essentially making the code run faster. When I did this, though, the surging came back with a vengeance. It wasn't the same surging as before, though. At a frequency of about 1 Hz, the current would gradually ramp up to about 1.5 times what I wanted, then suddenly drop to maybe half of the target. I can't think of how this could be entirely a fault of the arduino, since it increases and decreases the current at the same rate unless the throttle input is below 5%. I suspect this has something to do with the "soft start" function of my controller, but since I don't have a controller without this feature, I can't verify that speculation. It seems that the slowness in the code introduced by this vestigial function is what's keeping the oscillation in check. Without a derivative term in the code, I have no way of dampening these oscillations aside from reducing the response speed of the feedback loop - which introduces throttle lag.
That's a strange but interesting result. I am not certain what would cause it, but soft start (throttle ramp-up) in the controller could be that cause, it usually takes a half a second or so to ramp up in the ones I've had like that.



I can't come up with a very good analogy, but the effect is the same as if you have a load on a spring, and you are trying to keep the load at a set height. You can raise or lower the platform the spring is on, and so you do so until the load reaches the height you want. The energy put into the spring by accelerating the platform upwards is now being released into the load, though - it keeps traveling upwards. You lower the platform to compensate, and the same thing happens in reverse. If you put some sort of damping device on the spring, like a shock absorber or friction brake, the oscillation will dissipate over time - more quickly if your damper is stronger. This is the derivative portion of a control loop. The arduino, however, does not do this, and so the load and platform oscillate, with the average height of the load being pretty close to the target. Sorry if that's too complicated/convoluted - I did my best.

It makes perfect sense, and it's a fine analogy. I know this much although I don't follow maths and formulas well, so your explanation is better than the usual ones that pop up in PID discussions. :)
 
AviatorTrainman said:
I’ve been having battery issues since late February, like cutting out over speed bumps, and I figured it was a loose connection.
<snip>
I found a stray nickel strip melted to the bottom of the bottle when I opened it up, so I assume this was my loose connection, and then somehow after some time it touched both the cap and the shoulder of this cell.

That sounds like a probable sequence of events--it's been documented happening on other packs ehre on ES, and suspected in pack fires.

There are paper (or other materials) separators that are intended to prevent exactly that problem...but theyr'e not used in all packs; the cheaper the pack the more likely they don't use anything, so abrasion or pressure sufficient to cut thru the heatshrink on the top ring of the can then allows this kind of short to happen.

Nowadays there's a lot of cell holder options that also prevent this kind of problem, but they're still not used on the cheaper packs, simply because of cost.
 
I've updated my previous posts with the photos as attachments. I've ordered some of those cardboard rings on amazon, so they should be here by this time tomorrow. I'll rebuild the pack as 12s (since all but 2 cells are fine) and do some more extensive testing of the functionality as it stands, to see if this project suits my needs well enough.
 
Okay, so using the code given above, and tweaking a few of the throttle voltage values to more precisely match my throttle, I am happy with the project as it stands. I have been using this to go everywhere for some time now, and I can happily say I have found no glitches, and it works just fine. The shutoff is instant, and power up is as fast as the built-in soft start will allow. I would recommend this project to anybody looking to have some of the functionality of a CA, with a far lower cost. My all-in cost for this project was $5 for the Arduino (an Amazon clone of the real thing), $17 for the contactless current sensor, and some wires, resistors, and a capacitor I had just laying about, so a total of $22-25, depending on your part sources. I might yet make some more refinements, and if I do, I'll make sure to post them here, but I believe this can stand on its own as a fully complete project.
 
Back
Top