10-03-2010, 07:51 AM
|
#1 (permalink)
|
EcoModding Lurker
Join Date: Sep 2010
Location: Fresno, CA
Posts: 78
Thanks: 4
Thanked 9 Times in 7 Posts
|
FalconFour's MPGuino mods
I think they deserve their own thread, although I think the bigger ones (like the ALDL one I plan once I get comfortable with Arduino coding) probably deserve their own thread...
Here's what I've been up to tonight, after getting my Arduino back from a friend
Current list of "gee, wouldn't that be nice to have?" features on my todo list:
- Tank remaining gallons calculated by (tank size - tank gallons) * tank MPG (completed)
- Editor for tank values in memory, for restoring from a power outage from values recorded prior to unplugging (e.g. to recover from the setup menu CPU% timing bug) (still planning that one, LCD manipulation is tough)
- Smartass message/indicator for ultra low instant MPG, high instant MPH delta (flooring it)
- Real-time clock based on cycles, computed from memory value of "current time", set using "tank" method above (implemented, but unable to set the time at the moment due to lack of editor, so it always starts at 12am)
And more posts to follow for each mod, and the associated code.
|
|
|
Today
|
|
|
Other popular topics in this forum...
|
|
|
10-03-2010, 08:02 AM
|
#2 (permalink)
|
EcoModding Lurker
Join Date: Sep 2010
Location: Fresno, CA
Posts: 78
Thanks: 4
Thanked 9 Times in 7 Posts
|
Tank MPG is the easiest. Right now, for testing, it starts with a fixed value of 17.9999999 MPG to test rounding functions (I wasn't quite sure how the code worked yet, but I'm getting the hang of it now), but that value is discarded as soon as tank MPG moves away from 0.00. It calculates against the configured (but currently unused) tank capacity setting.
It uses its own "screen" which I currently call "F4 edit" due to all the comments I made in the code indicating where I patched it ("// ** F4 edit: blah blah"). The screen has both RemMiles and Time (clock).
Here's the code:
Put this somewhere around the screen routines. I put mine after doDisplaySystemInfo.
Code:
void doDisplayRem(void) {
LCD::gotoXY(0,0);
unsigned long remMPG = tank.mpg(); // may need to change this below
unsigned long remMiles = parms[tankSizeIdx]; // final value
if (remMPG < 50) remMPG = 17999; // if unreasonably low, make more reasonable
LCD::print("Rem miles:");
remMiles -= tank.gallons(); // subtract used gallons from total tank gallons
remMiles *= remMPG; // multiply available gallons by tank mpg
remMiles /= 1000; // since we multiplied two *1000 vals, knock down a notch
LCD::print(format(remMiles));
LCD::gotoXY(0,1);
LCD::print(" ");
}
Add a new displayFuncName:
Code:
displayFuncNames[x++] = PSTR("Rem tank miles ");
And add a new displayFuncs to the position where you added the displayFuncName (if at the top of the stack, add it to beginning of list; if at bottom, add to end):
And that should pretty much be that. You can also use the computation above to add it to any other screen you want (custom is nice), but real estate there is limited. So if you want to replace Current MPG on the Custom screen, you could do this:
Code:
void doDisplayCustom() {
unsigned long remMPG = tank.mpg(); // may need to change this below
unsigned long remMiles = parms[tankSizeIdx]; // final value
if (remMPG < 50) remMPG = 17999; // if unreasonably low, make more reasonable
remMiles -= tank.gallons(); // subtract used gallons from total tank gallons
remMiles *= remMPG; // multiply available gallons by tank mpg
remMiles /= 1000; // since we multiplied two *1000 vals, knock down a notch
displayTripCombo("MG","LK", instantmpg(), " S"," S", instantmph(), "GH","LH",
instantgph(), "RM", remMiles);
}
(I think. I haven't tried that... and I removed the metric functionality from mine, so I had to add that back above too.)
As they say... enjoy!
Last edited by FalconFour; 10-04-2010 at 10:09 AM..
Reason: fixed maths bugs
|
|
|
10-03-2010, 08:12 AM
|
#3 (permalink)
|
EcoModding Lurker
Join Date: Sep 2010
Location: Fresno, CA
Posts: 78
Thanks: 4
Thanked 9 Times in 7 Posts
|
And a fun one, if at least to see how far the MPGuino's interrupt-generated clock differs from reality (if "1.024 milliseconds, we will call that a millisecond for our purposes" is any indicator )... a clock.
It's not complete. The "values editor" has to first be created here in order to set the time on the clock. But it does count time, and it seems to be working, so I'll provide that here as a starting point, and to get some feedback (particularly on if there's anything I can do to clean up all the mBuff parameters)...
First, a new function, char * clock():
Code:
char * clock() {
unsigned int clockDelta = tank.loopCount / loopsPerSecond;
// if over 24 hours, remove 1 day. will occur after running for more than 24 hours.
while (clockDelta > 86400) clockDelta -= 86400;
unsigned int clock = (clockBase + clockDelta);
// if we then add the clock base and it's over 11:59pm, wrap around to midnight.
// will occur once a day and will reset when the clockDelta check above catches it.
if (clock > 86400) clock -= 86400;
unsigned int clockSeconds = (clock % 60);
// will still be seconds so divide later
unsigned int clockMinutes = (clock - clockSeconds) % 3600;
unsigned int clockHours = (clock - clockMinutes - clockSeconds) / 3600;
// divide to get minutes from mod seconds
clockMinutes /= 60;
boolean clockAmPm = false;
if (clockHours > 12) {
clockHours -= 12;
clockAmPm = true;
}
if (clockHours == 0) clockHours = 12;
mBuff[0]='0'+clockHours/10;
mBuff[1]='0'+clockHours%10;
mBuff[2]=':';
mBuff[3]='0'+clockMinutes/10;
mBuff[4]='0'+clockMinutes%10;
mBuff[5]=':';
mBuff[6]='0'+clockSeconds/10;
mBuff[7]='0'+clockSeconds%10;
mBuff[8]=clockAmPm?'p':'a';
mBuff[9]='m';
return mBuff;
}
So, add that code above somewhere, I added it below instantgph() and above the Trip functions.
Then, a way to display it. Basically just call LCD: rint(clock()) anywhere. I added a new menu for it. Take the construct above and replace the blank line print with:
Code:
LCD::print("Time: ");
LCD::print(clock());
Then bam, you get a clock starting at 12am. Happiness!
Attached is a photo of my work thus far
Last edited by FalconFour; 10-04-2010 at 10:11 AM..
Reason: Corrected bugs that would result in after-13pm oddities after 24 hours
|
|
|
10-03-2010, 08:28 AM
|
#4 (permalink)
|
EcoModding Lurker
Join Date: Sep 2010
Location: Fresno, CA
Posts: 78
Thanks: 4
Thanked 9 Times in 7 Posts
|
Bleh, just found out that tank miles isn't working right either. For some reason it flips out once tank MPG != 0.00. I can't figure out how the math is done in this thing. For example, tank capacity is stored as an integer like "10500" by default, but when I throw "format()" at it, it comes out as 10.5, as it should. But values like VSS pulses/mile also come out from format() as "4.00". I can't figure out where the decimal is coming from... or going to. I created a small test function to cycle through every stored parameter during every update, and it gave me some fast-paced but useful insight, such as that I should remove the "/1000" on the tank capacity parameter. But now it explodes in my face after I try to use it.
Needless to say I'm a little confused as to how to handle variables in the MPGuino code. Any tips? :/
|
|
|
10-04-2010, 10:20 AM
|
#5 (permalink)
|
EcoModding Lurker
Join Date: Sep 2010
Location: Fresno, CA
Posts: 78
Thanks: 4
Thanked 9 Times in 7 Posts
|
Updated both mods... tank remaining MPG now actually works (yay! d'oh), learned a little too late about the 64-bit, integer-based *1000 math that was used in MPGuino... so all the calculations were screwed up. All fixed now with sane math and a better understanding of how to follow MPGuino as it runs around the room...
Also updated clock to fix the bug I noticed as I was posting it. Still not functional; tomorrow I'll work on a menu that allows you to set the time. Already added a menu as in the photo. Will work on adding clock- and tank-setting menus tomorrow!
BTW, here's as small as I could get the menu code: (sorry, haven't gotten around to commenting it - but check out that pos-pointer statement! Hint: press L/R to go to the 4 corners.)
Code:
void setupGuino() { // setup menu
LCD::gotoXY(0,0);
//LCD::print(" ");
LCD::print("Params | Clock");
LCD::gotoXY(0,1);
LCD::print("Tank | Exit");
LCD::LcdCommandWrite(0b00001110);
byte p=3;
byte keyLock=1;
while (true) {
if (p < 4)
LCD::gotoXY((bitRead(p,0)*15), bitRead(p,1));
if (keyLock == 0) {
if (!(buttonState & lbuttonBit)) {// left
p--;
if (p == 255) p = 3;
}
else if (!(buttonState & rbuttonBit)) {// right
p++;
if (p == 4) p = 0;
}
else if (!(buttonState & mbuttonBit)) {// middle
LCD::LcdCommandWrite(0b00001100);
if (p == 0) { // params
initGuino();
return;
}
else if (p == 1) { // clock
// tbd
return;
}
else if (p == 2) { // tank
// tbd
return;
}
else if (p == 3) { // exit
return;
}
}
if (buttonState != buttonsUp) keyLock = 1;
} else {
keyLock = 0;
}
buttonState = buttonsUp;
delay2(125);
}
}
|
|
|
10-05-2010, 03:24 AM
|
#6 (permalink)
|
EcoModding Lurker
Join Date: Sep 2010
Location: Fresno, CA
Posts: 78
Thanks: 4
Thanked 9 Times in 7 Posts
|
Next up... Duck.
Yes, all it is, is a duck. Just a duck.
Add to LCD prototype (begins at "// LCD prototype" near the top):
Code:
void initDuck();
void printDuck(byte pos);
Add "doDisplayDuck" to the list of "displayFuncs[]" containing all the other doDisplay's.
Add the line "displayFuncNames[x++] = PSTR("Duck.");" to the menu selections (big block of displayFuncNames[x++]).
Add the following function, I put it around all the other display functions (below doDisplaySystemInfo):
Code:
void doDisplayDuck(void) {
while (tmp1[0] > 6) {
tmp1[0]--;
tmp1[1] = 1;
}
LCD::printDuck(tmp1[0]);
if (tmp1[1]) tmp1[0]--;
else tmp1[0]++;
if (tmp1[0] == 0) {
tmp1[1] = 0;
}
}
Now, look for "displayFuncs[screen](); //call the appropriate display routine". Look for the comment "//left is rotate through screeens to the left", and the misnomer "//right is rotate through screeens to the left", and just below each of those, add the line " if (screen == displayFuncSize - 1) LCD::init();". At the bottom of each, under the "LCD: rint" statement, add the line " if (screen == displayFuncSize - 1) LCD::initDuck();". This ensures that the LCD is in the right state when both coming-from and going-to the Duck mode.
Finally, two LCD functions need to be added - initDuck and printDuck.
In the LCD section near the middle, add:
Code:
void LCD::initDuck() {
//creating the duck:
LcdCommandWrite(0b00001100); // display control:
LcdCommandWrite(0b00000110); // entry mode set: increment automatically, no display shift
LcdCommandWrite(0b01001000); // set cgram
static byte chars[] PROGMEM = {
B00001,B10000,B00000,B00000, B00000,B11111,B11111,B00110,
B00011,B11000,B00000,B00000, B00001,B11111,B11111,B11110,
B00010,B11100,B00000,B00000, B00011,B11111,B11111,B11100,
B01111,B11100,B00000,B00000, B00011,B11111,B11111,B11111,
B11111,B11100,B00000,B00000, B00011,B11111,B11111,B11110,
B00001,B11100,B00000,B00000, B00011,B11111,B11111,B11100,
B00000,B11000,B00000,B00000, B00001,B11111,B11111,B11000,
B00000,B11100,B01100,B00000, B00000,B11111,B11111,B10000};
for(byte x=0;x<LcdNewChars;x++)
for(byte y=0;y<LcdCharHeightPix;y++)
LcdDataWrite(pgm_read_byte(&chars[y*LcdNewChars+x]));
LcdCommandWrite(0b00000001); // clear display, set cursor position to zero
LcdCommandWrite(0b10000000); // set dram to zero
}
void LCD::printDuck(byte pos) {
char duckchars[]={ 1,2,3,4,4,0,5,6,7,8,4,0 };
LCD::gotoXY(0,0);
byte x=0;
for (x=0;x<pos;x++) {
LCD::print(" ");
}
LCD::print(duckchars);
LCD::gotoXY(0,1);
for (x=0;x<pos;x++) {
LCD::print(" ");
}
LCD::print(duckchars+6);
LCD::gotoXY(11,1);
LCD::print("Duck.");
}
Then, upload, rechip, and voila... you have a duck screen.
|
|
|
The Following User Says Thank You to FalconFour For This Useful Post:
|
|
10-05-2010, 04:50 AM
|
#7 (permalink)
|
needs more cowbell
Join Date: Feb 2008
Location: ÿ
Posts: 5,038
Thanks: 158
Thanked 269 Times in 212 Posts
|
LOL! I did some playing around too, here is conways game of life:
http://ecomodder.com/forum/showthrea...html#post39458
__________________
WINDMILLS DO NOT WORK THAT WAY!!!
|
|
|
11-10-2010, 04:42 AM
|
#8 (permalink)
|
EcoModding Lurker
Join Date: Nov 2010
Location: Monterey, CA
Posts: 21
Thanks: 0
Thanked 0 Times in 0 Posts
|
Feature suggestions:
How about "tank miles remaining" before tank is empty
VSS pass through, (so I can change the VSS signal to the speedometer to read correct speed when changing tire sizes) So modify the input VSS, and output a "corrected" value to take into account changes
Allowance for a bigger/better screen to see more information at once
|
|
|
11-10-2010, 04:59 AM
|
#9 (permalink)
|
EcoModding Lurker
Join Date: Sep 2010
Location: Fresno, CA
Posts: 78
Thanks: 4
Thanked 9 Times in 7 Posts
|
Miles remaining? I've got that now, and it's pretty much dead accurate, based on tank MPG, tank gallons used, and the configured tank size. Also got a working clock that's 100% completely and totally spot-on accurate 24 hours a day, 7 days a week... haven't reset the MPGuino in some 3... almost 4 weeks now, and it's still got the perfect time. Also made a huge number of modifications to the screens, to provide more intuitive flow of screens:
BIG MPG (instant)
BIG MPH (instant)
Instant
Current
Tank
EOC/Idle
CPU usage (current/peak; free mem)
Remaining miles / clock
Duck
And the Instant/Current/Tank screens have been rearranged to provide more intuitive figures:
MPG | MPH
Gallons | Distance (on Instant screen, distance is replaced with current MPG for reference)
Also added a menu that allows me to edit different parameters instead of just jumping in and locking me into editing all system parameters with no way out... when I press L+R buttons, I'm presented with a menu of "Params, Clock, Tank, Exit" (image above). Params launches the usual all-parameter edit screen, but selecting "XX" backs out of all editing back to the main screen. Clock allows me to enter the clock time in 24-hour format. Tank lets me edit the tank gallons and tank miles, in case of an accidental reset or power cycle, using figures I recorded previously (say I need to take the MPGuino inside to reprogram or something). It takes those figures in value*1000, then converts them into VSS pulses and injector S/MS that the MPGuino works with internally, based on the configured values.
I think I've made waaaaay too many edits to this code now... lol.
But... what do you mean by VSS pass through? You mean, reproduce a VSS signal on a signal pin to drive the speedometer? Hm... I don't really have a use for that, so I dunno if I could really develop and test that... :/
And a bigger screen? Not sure about that one either... if I get my hands on a bigger LCD I might play around with it, but the 16x2 LCD format comes in a wide variety of physical dimensions... doesn't help to put more info on the screen at once, but I think the instant/current/trip screen setup is already an information overload as it is while driving!
|
|
|
11-10-2010, 05:04 AM
|
#10 (permalink)
|
EcoModding Lurker
Join Date: Nov 2010
Location: Monterey, CA
Posts: 21
Thanks: 0
Thanked 0 Times in 0 Posts
|
FalconFour, Wow! Thanks for that crazy quick response.
|
|
|
|