Closed wickeddoc87 closed 7 years ago
Does we know us?
Why your frind use the first version now?
@the author
why you use so many floats in your code. I changed all floats to byte, int and longs. It's not useful to do calculations with floats. So I try to keep all variables as big as possible and just before we write it to the output I calculate the true value. Like this I don't need one float at all.
Just in the Part for Human visualisation I use floats for Ki, Kd, kp...
Why you use micros for the RPM Trigger? Even if you're engine have 10000 RPMs and you use 6 teeth, the RPM resolution would be still 1ms, so Millis should be enough.
An older Projects shows me that micros and floats are slowing down the processor extremely.
Best regards Peter
.
Best regards Peter
Hello, it's me again....
You're calculating controls.lastTime with Millis. Your loop take about 0.56ms. So as I understand the code controls.lastTime will be almost ever 1 and sometimes 0 if you do the calculation with multiplication 0 integral is 0. I think at this position we should do the calculation with micros instead of Millis.
Best regards Peter.
millis is not updated when certain other things are happening, micros always is.
The control loop doesn't execute every run, only every 80ms.
very happy to hear about the update for 1.6.4 - I hadn't had a chance to look at that yet.
EMP = exhaust manifold pressure. I have a sensor on my board for it but I haven't done anything with it yet. It is only partly there in the code, it is basically unimplemented at the moment.
The AUX output can be used for controlling water/meth, I use it to help limit EGTs by hiding boost from the LDA. I have it set to start opening a second control solenoid as EGTs approach 800C.
thx for explaining.....
RPM Value is unstable the reason for it is a semi. fault.
if (teethNo > rpmResolution); <--------------- This Semi should not be there. {
The Arduino does not support an Software pull down on Inputs .. so this will not work
pinMode(PIN_TPS, INPUT); pinMode(PIN_MAP, INPUT);
digitalWrite(PIN_TPS, LOW); // safety unconnected TPS digitalWrite(PIN_MAP, HIGH); // safety unconnected MAP
you have to do the Pulldown external with a resistor 100K maybe.
so the setup can look like this.
pinMode(PIN_TPS, INPUT); pinMode(PIN_MAP, INPUT_PULLUP);
On 2015-06-19 01:23 PM, wickeddoc87 wrote:
thx for explaining.....
RPM Value is unstable the reason for it is a semi. fault.
if (teethNo > rpmResolution); <--------------- This Semi should not be there. {
— Reply to this email directly or view it on GitHub https://github.com/vanbcguy/vntlda/issues/2#issuecomment-113631553.
Good catch. I've updated, will test this afternoon.
hi guys
hope ye can help me out here. new to arduino programming etc but very keen to learn. ive been trying to verify the .ino file but a load of the "prog_uchar" errors were coming up so i replaced them with "const unsigned char" as mentioned above and they're all gone now :)
here is the list of errors i have now and im stumped. i cant figure this part out at all :/ any chance of some help?
Arduino: 1.6.5 (Mac OS X), Board: "Arduino Leonardo"
Build options changed, rebuilding all vnt_lda_myPID_1.ino: In function 'void setPwmFrequency(int, int)': vnt_lda_myPID_1:384: error: 'TCCR2B' was not declared in this scope 'TCCR2B' was not declared in this scope
cheers in advance :)
Shane
think i have it!
bit of info with leonardo having a library compatibility issue here in post 8 http://forum.arduino.cc/index.php?topic=175158.0
i swapped TCCR2B in line 384 to TCCR0B and it verified. ill report back (if ye dont mind :P) during the week when i get the chance to fit to the car :)
I've committed the prog_uchar change so it's there for everyone. :)
The 'TCCR2B' to 'TCCR0B' change alters the PWM timers. The 'setPwmFrequency' routine is specifically set up for the regular 'Uno' so it may need adjustment for other boards. The frequency that's set in my code is correct for the specific GM solenoids I'm using (which like a sllloowww low frequency signal); other solenoids don't necessarily want the same thing.
@wickeddoc87 - I'd be interested to see your version without using floats so heavily. I know it's kind of crappy right now.
The main slowdown though is actually updating the LCD - it takes nearly 50ms to update the entire thing. I recently changed it to update half the screen at a time which got it down to 28ms per update, but that's really what is limiting how fast I can run the loop right now. I need to spend some time and sort it out so it can just blast out an entire line at once rather than doing so many positioning steps, just haven't had a chance.
Good morning,
about Speed... i did same "Benchmarks" with old and new Arduino IDE and relatively simple Code. The Device programmed with the Arduino IDE 1.6.4 works a LOT LOT LOT faster than 1.0.5, maybe you should try an Update.
About the version without float.... i tried a complete other CALC Part Yesterday and "destroyed" the "old code" without doing a new Backup. i Just have a not finished old Backup...
void processValues() {
controls.vntMaxDc = mapLookUp(boostDCMax, controls.rpmCorrected, controls.tpsCorrected); controls.vntMinDc = mapLookUp(boostDCMin, controls.rpmCorrected, controls.tpsCorrected);
controls.rpmCorrected = mapValues(controls.rpmActual, 0, settings.rpmMax); controls.mapInput = getFilteredAvarage(&mapAvg); controls.mapCorrected = mapValues(controls.mapInput, settings.mapMin, settings.mapMax); controls.tpsInput = getFilteredAvarage(&tpsAvg); controls.tpsCorrected = mapValues(controls.tpsInput, settings.tpsMin, settings.tpsMax); controls.empInput = getFilteredAvarage(&empAvg); controls.empCorrected = mapValues(controls.empInput, settings.empMin, settings.empMax); controls.egtCorrected = mapValues(controls.temp1, settings.egtMin, settings.egtMax);
// EGT controls controls.auxOutput = mapLookUp(auxMap, controls.rpmCorrected, controls.egtCorrected);
// TODO add RPM hysterisis if ( controls.tpsCorrected > 0 ) { controls.idling = false; } else if ( controls.rpmActual < IDLE_MAX_RPM ) { controls.idling = true; } else { controls.idling = false; } unsigned long currentMillis = millis(); long timeChange = currentMillis - controls.lastTime;
long error; long integral; int calc_integral; long derivate;
int controlSpan; int scaledInput; int scaledTarget; int toControlVNT; boolean everyThingIsNormal;
if (!(controls.prevPidOutput >= 254 && error > 0) && !(controls.prevPidOutput <= 0 && error < 0)) everyThingIsNormal == true; else everyThingIsNormal == false;
/* This is the available span of our DC - we can only go between min and max */ controlSpan = controls.vntMaxDc - controls.vntMinDc;
scaledInput = controls.mapCorrected;
if (scaledInput > 255) scaledInput = 255; else if (scaledInput < 0) scaledInput = 0;
if ((controls.idling)) { // If we are at idle then we don't want any boost regardless of map
controls.vntTargetPressure = 0; // We don't want any pressure
controls.lastInput = scaledInput; // Keep the derivative loop primed
integral = 0; // Only you can prevent integral windup at idle
error = 0; // Not strictly necessary but it keeps my ADD in check on the datalogs
derivate = 0; // See above
controls.pidOutput = 0; // Final output is zero - we aren't trying to do anything
controls.mode = 0; // System status = idling
} else if ( controls.rpmActual <= settings.rpmMax ) { // Only calculate if RPM is less than rpmMax or we start doing bad things // Normal running mode int scaledError; /* Look up the requested boost */ controls.vntTargetPressure = mapLookUp(boostRequest, controls.rpmCorrected, controls.tpsCorrected); scaledTarget = controls.vntTargetPressure;
/* It should not be possible to have >255 or <0 targets but hey, let's be sure */
if (scaledTarget > 255.0) scaledTarget = 255.0;
else if (scaledTarget < 0) scaledTarget = 0;
/* Determine the slope of the signal - we need to know this to determine everything else we want to do */
derivate = ( settings.boostKd * 100 * ( scaledInput - controls.lastInput )) / ( timeChange * PIDControlRatio ) ;
controls.lastInput = scaledInput;
/* Since we do a bunch of comparisons with this value lets just calculate it once */
scaledError = scaledTarget - scaledInput;
error = ( settings.boostKp * scaledError ) / PIDControlRatio;
if ( toKpaMAP(controls.mapCorrected) < spoolMinBoost && integral < preSpoolInt ) {
// We haven't spooled up yet - use a static value for the integral
// May want to add a case here for 'spooled but still at low boost'
controls.mode = 1; // idling
integral = preSpoolInt;
}
else {
integral += (settings.boostKi * scaledError * timeChange) / (PIDControlRatio * 500) ;
// Turbo is producing pressure - now we can start actually controlling it
if ( derivate > rampThreshold ) {
// Boost is building extremely quickly, we need to take corrective action - multiply the derivative by rampFactor
derivate = derivate * rampFactor;
if (scaledError > 0) {
// We are below setpoint
if (scaledError < rampActive) {
// We haven't overshot yet but we are approaching setpoint. Reduce upwards momentum
controls.mode = 5; // Under but accelerating upwards rapidly
integral = integral * underGain ;
error = error * underGain ;
} else {
// We haven't overshot and we're still somewhat far from the target. We will continue as normal.
controls.mode = 8; // Normal PID
if (everyThingIsNormal == true) {
// If we are at the upper or lower limit then don't integrate, otherwise go ahead
integral = integral;
}
error = error;
}
} else {
// We've overshot and we're still building fast, pull back hard with proportional control, chop off the integral fast
controls.mode = 4; // Overshot and still accelerating upwards
if (everyThingIsNormal == true) {
integral = integral * overGain;
}
error = error * overGain;
}
} else {
if (-scaledError > maxPosErrorPct) {
//We're quite a bit over
controls.mode = 3; // Over but not steeply accelerating
if (everyThingIsNormal == true) {
// If we are at the upper or lower limit then don't integrate, otherwise go ahead
integral = integral * overGain;
}
error = error * overGain;
} else if (scaledError <= fineBand) {
// We're not on a steep upwards slope and we're close to the setpoint. Switch to fine control mode, disable derivative.
controls.mode = 7;
if (everyThingIsNormal == true) {
integral = integral * fineGain;
}
error = error * fineGain;
derivate = fineGain * derivate;
} else {
// We are spooled but everything is normal; we can use normal PID
controls.mode = 2; // Normal PID
if (everyThingIsNormal == true) {
// If we are at the upper or lower limit then don't integrate, otherwise go ahead
integral = integral;
}
error = error;
}
}
}
/* Can't have a value below zero... */
if ( integral < 0 ) integral = 0;
/* We can bias the signal when requesting boost - do we want boost to come on faster or slower */
if (error > 0) error = (error * settings.boostBias) / 10;
else if ((error < 0) && (scaledInput > PIDMaxBoost)) {
controls.mode = 6; // We're in emergency pullback mode
error = (error * 2); // If we are over PIDMaxBoost then double the proportional response to pulling off boost - turbo saver
}
/* PID Output */
controls.pidOutput = error + integral - derivate;
} else { // We must be over max RPM, open the vanes! controls.pidOutput = 0; }
// currentMillis = millis(); // This was set above, if we set it again here we aren't counting the time we spent processing? controls.lastTime = currentMillis;
/* If our loop goes over 100% or under 0% weird things happen!*/ if (controls.pidOutput > 255) { controls.pidOutput = 255; } else if (controls.pidOutput < 0) { controls.pidOutput = 0; }
controls.prevPidOutput = controls.pidOutput;
// Not sure why I used two variables here? toControlVNT = ((controls.pidOutput * controlSpan) / 255 ) + controls.vntMinDc;
controls.vntPositionDC = toControlVNT;
/* This loop should never ever be true - a 100% output should be diff between min and max + min which should equal max but I'm not quite ready to remove this */ if (controls.vntPositionDC > controls.vntMaxDc) controls.vntPositionDC = controls.vntMaxDc;
if ((settings.options & OPTIONS_VANESOPENIDLE)) { // Open the vanes fully if set that way controls.vntPositionDC = 0; }
/* Display these as real numbers - will make the logs more useful as we can try different values */ controls.boostCalculatedP = (float)(error) / 255.0; controls.boostCalculatedI = (float)(integral) / 255.0; controls.boostCalculatedD = (float)(derivate) / 255.0;
unsigned char finalPos; finalPos = controls.vntPositionDC;
if (settings.options & OPTIONS_VNTOUTPUTINVERTED) { controls.vntPositionRemapped = 255 - finalPos; } else { controls.vntPositionRemapped = finalPos; } }
I don't know your display, I use a Sparkfun Serial Display, it works with Baudrates up to 38400
If your Display Update takes 50ms... with Baud 9600 it will only take 13ms with Baud 38400...
I found the real Performance Killer! It is the max31855 library!
The Library works with Floats und is unbelievable slow! there are other Library's for the max31855!
With deactivated EGT my Code works 3Times Faster....
I Hope this will help you!
Best regards, Peter
Just try... To see the Difference..
void readValuesEgt() { // controls.temp1 = thermocouple.readCelsius(); // controls.temp2 = toTemperature(analogRead(PIN_TEMP2)/4); controls.temp2 = 0; // disabled for now as we aren't using it
if (controls.temp1<=0) { controls.temp1 = 0; } else if (controls.temp1 >= settings.egtMax) { controls.temp1 = settings.egtMax; }
}
Yes, it's terrible eh? Actually I'm running a patched version of that library that dramatically speeds it up. There are many delay_ms calls that are slowing things down more than necessary; this code block is the troublemaker - I've changed the delay_ms to delay_us. I found that I got bad temperature readings unless I increased the delay to 10 us rather than 1 us.
uint32_t Adafruit_MAX31855::spiread32(void) {
int i;
uint32_t d = 0;
if(hSPI) {
return hspiread32();
}
digitalWrite(sclk, LOW);
_delay_us(10);
digitalWrite(cs, LOW);
_delay_us(10);
for (i=31; i>=0; i--)
{
digitalWrite(sclk, LOW);
_delay_us(10);
d <<= 1;
if (digitalRead(miso)) {
d |= 1;
}
digitalWrite(sclk, HIGH);
_delay_us(1);
}
digitalWrite(cs, HIGH);
//Serial.println(d, HEX);
return d;
}
I did actually try a few other MAX31855 libraries but the timer settings I use to get the right PWM frequency seem to cause the EGT readings to get cut in half. This was the only library I could get to spit out the correct value.
As we've changed MAX31855 libraries, resolved the prog_uchar issues and switched to a totally different PID routine I'm marking this as closed...
Hello,
Nice to see this Project goes forward. With the new Arduino IDE 1.6.4 "prog_uchar" will not work any more. I replaced all "prog_uchar" with "const unsigned char". Like this it is possible to compile the code with the new Arduino IDE, i will see next week if it is working correct.
I have designed a new PCB with SMD technology, If you are interested tell me how i can send it to you.
I have to questions about your code. What exactly to you mean with EMP and AUX.
Thx alot,
best regards, Peter