tz89 Posted September 8, 2012 #1 Posted September 8, 2012 (edited) Built a digital sync and you can, too! After reading this forum about installing an aftermarket TCI and in other places about easy to use microprocessing platforms, it occurred to me that one might be able to use multiple MAP sensors to set the carb sync on a bike. I'm no expert on either motorcycles or electronics, so it had to be easy if I was going to do it. And it was easy. The hardest thing for me was figuring out what certain connectors are called and then finding a reasonable source. Point your search engine at “arduino” or go directly to this link: www.arduino.cc to get an idea for the microprocessing end of this. I used the Arduino Uno R3. You can use any, but you'll have to modify my program or write your own. In particular, if you use the kind of LCD display connection I did (IIC) it interferes with two of the ports on the board. On the Uno it's analog 4 and 5, leaving a nice grouping of 0-3 for my 4 sensors to connect. My end goal is to remove the LCD and use a wireless smartphone as the display. When I get that working then this thing could do a 6 carb bike. Goldwing heaven! (On the Leonardo board it's digital 2 and 3.) Here's the parts list. I'll edit this post to improve accuracy as I can. The hard parts (for me): MAP sensors. I found 6 old GM 1 bar MAP sensors for $40 on Ebay and was quite happy. 6 3-tower GM weather-pack housings with male connectors. Spendy with rip-off shipping. You don't really need the plastic housing. You can just solder wires to loose male connectors, and maybe use some heat shrink to tidy up. Save big $$. The rest: Arduino Uno R3. $23. Arduino IDE software (free download). Sensor shield (optional - makes connections easier). $10. LCD IIC display 4x20. $7. 4 count 3-wire board connectors with one end removed and soldered to the weather-packs. $5. 1 count 4-wire board connector to attach the LCD with the +/- polarity rewired. $2. 2 feet 1/4” hose. Cut into 6” lengths and attached to the MAPs. 10 feet 3/16” hose. 4 count ¼ to 3/16 connectors. $5. 4 count caps for the 3/16 hose. $3. The Arduino IDE includes sample programs. I modified one that keeps a running average for input smoothing to load arrays of readings for each cylinder and calculate the peak and average readings. I'm an old software guy but never something like this and never in C. But those old skills came in handy and I wasn't shy about this part. The Arduino doesn't report overflow errors at compile or run time, so I had to do a little digging to debug odd results. For example, if I set the readings array to more than 180, the LCD stopped working. What I figured out was that the sensitivity scale of the readings multiplied by the number of readings had to be less than the max integer value (32k) or it would overflow. If the array got too big the RAM would overflow. I could change to long integers or floating point math I suppose. I could change to a chip or board with more memory because there is a memory size limitation. My rainy weather project will be to go back through and clean up the code. Basically, I just hacked my way forward and didn't worry about the elegance of the code like I did when I was working in software. I didn't know how the compiler or board really worked so why worry about style. The key thing I did was code a self-calibration step. The first time through loading the reading array (with the bike not running), it takes an average of the average of all the MAPS and uses that to establish a calibration adjustment to be applied to all subsequent readings. This way all the MAP sensor circuits are normed to a constant value. It could be normed to zero, but then negative numbers would be more common. To test this live, I hooked up all 4 MAP sensors in turn to the same cylinder on a running bike to see if it would return a consistent value. It did. The nice thing is that build precision is less of a factor which is great for me. It just works with what you have for MAP sensors, wire harness and soldering skills. Assembly is just plugging the shield into the top of the Uno, then plugging in the LCD and the 4 MAP sensors. For power I plugged in a cigarette adapter into my battery maintainer plug, plugged a USB converter into that, and ran a USB cable to the Uno. There are other ways but I had all this handy. The software was already loaded; you just plug the USB into the computer running the IDE and upload. At power up it does the calibration and when you hit the reset button. Nothing to lose by trying. I hooked up 4 hoses to the bike and capped them. Then I tested #1 against all 4 sensors. It read the same, about 159 peak. Then I hooked all 4 up. The bike was in good sync, which I knew because it runs good. But I tweaked all 3 sync adjustments to get them the same. Everything ended up peaking at 158-159. Then I capped the hoses and tested #3 against all 4 sensors. All the same. After that I took it for a ride. Seemed smoother but it was running great already. The numbers don't really mean anything. They depend on how 'sensitive' the software is set. The MAP sensors run at 5v and drop the signal voltage from that as vacuum increases. The UNO board reads an analog voltage and returns a range of integer values. The rest is software. One nice thing - you can crack the throttle without worries. In fact, since you can compare manifold pressure at higher RPMs you may get some diagnostic value if you've got pin holes in a diaphragm or a sticky slide. Hopefully, some engine experts will weigh in on that notion or with better ideas. Things to consider. If you can't find cheap MAP sensors, don't bother. They should all be the same or similar, but the calibration step allows for variances. Try to get the weather-pack connectors included because you'll go broke if you have to buy a small quantity at full retail. If anyone has a better source please let me know. Late 80's GM cars in a junkyard may be a good place to start. There are also less expensive vacuum sensors available for non-automotive applications that are not as rugged. Everything you need can be bought online if you know what to call it. The board connector names still elude me. I just bought stuff until I had something that worked. I'll post the code in a subsequent post. I will be glad for suggestions. I will be especially interested in a) how to build a cool enclosure and b) thoughts about better analysis techniques. I would never post it anywhere else, because the purists would flame you. But this forum is different. Best $12 ever! Lots of pix. If there's a better way to post them I don't know it. Tom Edited November 24, 2014 by tz89 grammar spelling and new facts
tz89 Posted September 8, 2012 Author #2 Posted September 8, 2012 (edited) /* Here's the code. Just copy everything and paste into the Arduino IDE. */ /* Modified Smoothing (below) by Tom Hogue 2012 for CarbSync Tool Accepts 0-5v from GM 1 bar MAP sensors Creates arrays of values for all cylinders v01r01 is the basic development version v01r02 adds LCD display v01r03 adds input calibration at startup Future mods smartphone display bluetooth connectivity tach live smooth and sensitivity adjustments Smoothing Reads repeatedly from an analog input, calculating a running average and printing it to the computer. Keeps ten readings in an array and continually averages them. The circuit: * Analog sensor (potentiometer will do) attached to analog input 0 Created 22 April 2007 By David A. Mellis modified 9 Apr 2012 by Tom Igoe http://www.arduino.cc/en/Tutorial/Smoothing This example code is in the public domain. */ #include #include LiquidCrystal_I2C lcd(0x27,20,4); //set the LCD address to 0x27 for a 20 chars and 4 line display /* Define the number of samples to keep track of. The higher the number, the more the readings will be smoothed, but the slower the output will respond to the input. Using a constant rather than a normal variable lets use this value to determine the size of the readings array. Uno board drives the LCD with A4 and A5, leaving only A0-3 for 4 MAP sensors */ const int numReadingsMax = 100; // this should be maybe 5-150. 190+ overflows lcd const int numCylinders = 4; // max is 4 . Reducing to actual will improve processing only slightly int readings[numCylinders][numReadingsMax]; // the readings from the analog input int numReadings = numReadingsMax; // allow this to change to vary smooth vs speed int index = 0; // the index of the current reading int sensitivity = 200; // how fine input is parsed usually 20-100. 1023 max. int thisCylinder = 0; // the index of the cylinder loops int total[numCylinders]; // the running total int average[numCylinders]; // the running average int runPeak [numCylinders]; // running peak value int inputPin[numCylinders]; // the input pin array int pinOffset = 0; // setting to 0 maps cylinders 1-4 to pins 0-3 int calibrate [numCylinders]; // an adjustment for input voltage variance int calibrateCylinder = 0; // int calibrationMean = 0; // the input adjustment added to each reading int calibrationFlag = 1; // use the first readings to calibrate String outString = " "; // int dispCylinder = 0; // void setup() { // initialize serial communication with computer: // Serial.begin(9600); // initialize LCD lcd.init(); lcd.backlight(); // initialize all the readings to 0: for (thisCylinder = 0; thisCylinder { inputPin[thisCylinder] = thisCylinder + pinOffset; // set cylinder pin plus an offset total[thisCylinder] = 0; average[thisCylinder] = 0; runPeak[thisCylinder] = 0; calibrate[thisCylinder] = 0; for (int thisReading = 0; thisReading { readings [thisCylinder][thisReading] = 0; } } } void loop() { // while the serial stream is not open, do nothing: need for leonardo board // while (!Serial) ; using UNO board and LCD not serial output /* for each reading read all cylinders then increment */ for (thisCylinder = 0; thisCylinder { // subtract the last reading: total[thisCylinder] = total[thisCylinder] - readings[thisCylinder][index]; /* read from the sensor. As vacuum increases MAP sensor output signal voltage drops so use map command to reverse output so that more vacuum == lower voltage == higher data points */ readings[thisCylinder][index] = map(analogRead(inputPin[thisCylinder]), 0, 1023, sensitivity, 0) + calibrate[thisCylinder]; // add the reading to the total: total[thisCylinder] = total[thisCylinder] + readings[thisCylinder] [index]; // calculate the average: average[thisCylinder] = total[thisCylinder] / (index + 1); // calculate the peak - look for more efficient method depending on output method runPeak[thisCylinder] = 0; for (int thisPeak = 0; thisPeak { runPeak[thisCylinder] = max(runPeak[thisCylinder], readings[thisCylinder][thisPeak]); } } // advance to the next reading position in the array: index = index + 1; // if we're at the end of the array... if (index >= numReadings) { index = 0; // ...wrap around to the beginning display(); } /* set a short delay between readings to add stability set to approx 1 ?? when running live */ delay (1); } void display(){ if (calibrationFlag == 1) { calibrationFlag = 0; calibrationMean = 0; for (calibrateCylinder = 0; calibrateCylinder {calibrationMean = calibrationMean + average[calibrateCylinder]; } calibrationMean = calibrationMean / numCylinders; for (calibrateCylinder = 0; calibrateCylinder {calibrate [calibrateCylinder] = calibrationMean - average [calibrateCylinder]; } // display the results and pause lcd.clear(); delay(5); for (calibrateCylinder = 0; calibrateCylinder { outString = "Calibrate C"; outString += calibrateCylinder + 1; outString += " Val "; outString += calibrate[calibrateCylinder]; lcd.setCursor(0, calibrateCylinder); lcd.print (outString); delay(5); } delay(3000); } else { /* send results to the lcd */ lcd.clear(); delay(5); for (dispCylinder = 0; dispCylinder { outString = "C"; outString += dispCylinder + 1; outString += ": PEAK "; outString += runPeak[dispCylinder]; lcd.setCursor(0, dispCylinder); lcd.print (outString); delay(5); outString = " AVG "; int chop = average[dispCylinder]; outString += chop; lcd.setCursor(12, dispCylinder); lcd.print (outString); delay(5); } } /* commented out this code for a test // reset all the readings to 0: for (dispCylinder = 0; dispCylinder { total[dispCylinder] = 0; average[dispCylinder] = 0; runPeak[dispCylinder] = 0; for (int dispReading = 0; dispReading { readings [dispCylinder][dispReading] = 0; } } commented out */ } Edited September 8, 2012 by tz89
Kirby Posted September 8, 2012 #4 Posted September 8, 2012 :confused07::starz: Uhhhhh, Carbtune??????
Pegasus1300 Posted September 8, 2012 #5 Posted September 8, 2012 that is just too much. I am very impressed.:lightbulb:Have you actually tried to use it and is it easier to use then a carbtune?
tz89 Posted September 8, 2012 Author #6 Posted September 8, 2012 (edited) Yes I used it today and it worked quite well. I've never used a carb tune just the oil in the tube method. Very easy. Each cylinder shows a value. You just adjust the sync until you are satisfied. And since all 4 cylinders show at once and there is no oil lag I was done in a few minutes. I'm hoping for good improvement suggestions and I'll revise as I go. It's probably cheaper just to buy a carb tune, but what's the fun in that?!?! Edited September 8, 2012 by tz89
Kirby Posted September 8, 2012 #7 Posted September 8, 2012 Don't take it the wrong way. I wasn't knocking it, it was just w-a-y over my head. It was impressive.
StarFan Posted September 8, 2012 #8 Posted September 8, 2012 Wow,,, That is way beyond impressing. Do you actually realise Tom that if/when you finalize this product with user friendly controls/installations/readings and you pack this up in a cool looking casing and market it you could be into serious business ? I have actually quite often wondered when using my carbtune why in the world these things were not made digital. Always thought there was some kind of a technical threshold that prevented it to be possible. But you did it !!! Make sure that if you ever want to sell one of these for the second Gen then put me on the top of your list - I´ll come running ! Thanks for a great article and for sharing this with us. I´ll be watching closely. Maybe you should form a company around this - Digi-CarbTune All the best from Iceland, Jonas aka StarFan
etcswjoe Posted September 8, 2012 #9 Posted September 8, 2012 I like it, seems like a logical thing to do Did you try Mouser or Digi key for connecters? How about adding a digital tach in with it?
XV1100SE Posted September 8, 2012 #10 Posted September 8, 2012 Better start the copyright process ! :mo money::mo money::mo money::mo money::mo money:
XV1100SE Posted September 8, 2012 #11 Posted September 8, 2012 Similar idea... $119 - http://www.aerostich.com/tools/maintenance-repairs/carburetor/twinmax-synchronizer.html http://www.ibmwr.org/prodreview/twinmax.html $255 - http://www.mactools.com/product/tabid/120/p-319466-mn08-0194.aspx Looks like all that is out there are +/- type readings. What you've done is a great start !
DragonRider Posted September 8, 2012 #12 Posted September 8, 2012 Portability............doesnt look to portable, great idea, now if shrunk down to fit in maybe a small leather pouch thats not to bulky it would be a great item to have, I think you would be very wise to make sure someone else hasnt done this and maybe put a patent or copyright on it..............It is indeed very cool. I know your just in the beginning stages of this so size didnt matter, you gotta make sure it works before you try to shrink it down............GOOD JOB, way over my head!!!!
wrenchrob Posted September 8, 2012 #13 Posted September 8, 2012 Awesome!!! If you need a bike to try it on than come on over.
Flyinfool Posted September 8, 2012 #14 Posted September 8, 2012 Shrinking it down and stuffing it all in a nice small box is the easy part, You already did the hard part. I wonder if you could count the vacuum pulses from one of the sensors to get a tach reading??? that way you do not have to tap into the bike electrics anywhere or need an additional input. Like if you are doing a 2nd gen where there ain't no tach. (hey they had to make a tough choice tach or cassette......) Nice job, it looks very interesting. Similar idea... $119 - http://www.aerostich.com/tools/maintenance-repairs/carburetor/twinmax-synchronizer.html http://www.ibmwr.org/prodreview/twinmax.html $255 - http://www.mactools.com/product/tabid/120/p-319466-mn08-0194.aspx Looks like all that is out there are +/- type readings. What you've done is a great start ! And made for 2 cylinders.
tz89 Posted September 8, 2012 Author #15 Posted September 8, 2012 (edited) Yes this will work on a 4 cylinder bike (even 6 once I get beyond the conflicting LCD display). A tach should be doable without too much trouble. All you need is an induction coil and some software to translate that into RPM. You could just wrap some wire around a clothespin and clip it to the plug wire on #1. I'll add this to my list of future mods. To do a tach with just the vacuum pulse data coming in is a non-trivial math problem of trying to detect the period of the pulse with very noisy data. Sounds challenging at least. If only my algebra teacher had said it would be useful for motorcycles I might have paid attention. Any Fast Fourier Transformation experts out there? I wonder if there is a simple way given that we know it's a 4 cycle engine with RPM between ~ 500 and 5000. Edited September 13, 2012 by tz89
BlueVenture87 Posted September 9, 2012 #19 Posted September 9, 2012 The Arduino platform is sooo cool! I am consistently amazed by what talented folks do with these boards! Thanks for sharing the code! -JK
tz89 Posted September 9, 2012 Author #20 Posted September 9, 2012 I'm hoping it becomes a community project. There are lots of ideas and skills on this forum. Best $12 ever!
tz89 Posted September 9, 2012 Author #22 Posted September 9, 2012 (edited) /* Modified Smoothing (below) by Tom Hogue 2012 for CarbSync Tool This code is in the public domain. Accepts 0-5v from GM 1 bar MAP sensors Creates arrays of values for all cylinders v01r01 is the basic development version v01r02 adds LCD display v01r03 adds input calibration at startup published on venturerider.org 9-7-12 v01r04 cleans up the code a bit v01r05 more clean up v01r06 localize some variables published on venturerider.org 9-9-12 Future mods smartphone display bluetooth connectivity tach live smooth and sensitivity adjustments Smoothing Reads repeatedly from an analog input, calculating a running average and printing it to the computer. Keeps ten readings in an array and continually averages them. The circuit: * Analog sensor (potentiometer will do) attached to analog input 0 Created 22 April 2007 By David A. Mellis modified 9 Apr 2012 by Tom Igoe http://www.arduino.cc/en/Tutorial/Smoothing This example code is in the public domain. */ #include #include LiquidCrystal_I2C lcd(0x27,20,4); //set the LCD address to 0x27 for a 20 chars and 4 line display /* Define the number of samples to keep track of. The higher the number, the more the readings will be smoothed, but the slower the output will respond to the input. Using a constant rather than a normal variable lets use this value to determine the size of the readings array. Uno board drives the LCD IIC with A4 and A5, leaving A0-3 for 4 MAP sensors Leonardo board drives LCD IIC with D2 and D3, leaving A0-5 for sensors */ const int numReadingsMax = 100; // this should be maybe 5-150. Too large overflows RAM. const int numCylinders = 4; // max is 4 . Reducing to actual will improve processing only slightly int readings[numCylinders][numReadingsMax]; // the readings from the analog input int numReadings = numReadingsMax; // allow this to change to vary smooth vs speed int index = 0; // the index of the current reading int sensitivity = 200; // how fine input is parsed usually 20-100. 1023 max. int thisCylinder = 0; // the index of the cylinder loops long total[numCylinders]; // the running total int average[numCylinders]; // the running average int runPeak [numCylinders]; // running peak value int inputPin[numCylinders] = {0,1,2,3}; // set the input pin array per board info above int calibrate [numCylinders]; // an adjustment for input voltage variance int calibrationFlag = 1; // use the first readings pass to calibrate void setup() { // initialize serial communication with computer: NOT USED // Serial.begin(9600); // initialize LCD lcd.init(); lcd.backlight(); // initialize all the readings to 0: for (thisCylinder = 0; thisCylinder { total[thisCylinder] = 0; average[thisCylinder] = 0; runPeak[thisCylinder] = 0; calibrate[thisCylinder] = 0; for (int thisReading = 0; thisReading { readings [thisCylinder][thisReading] = 0; } } } void loop() { // while the serial stream is not open, do nothing: need for leonardo board // while (!Serial) ; using UNO board and LCD not serial output /* for each reading read all cylinders then increment */ for (thisCylinder = 0; thisCylinder { // subtract the last reading: total[thisCylinder] = total[thisCylinder] - readings[thisCylinder][index]; /* read from the sensor. As vacuum increases MAP sensor output signal voltage drops so use map command to reverse output so that more vacuum == lower voltage == higher data points */ readings[thisCylinder][index] = map(analogRead(inputPin[thisCylinder]), 0, 1023, sensitivity, 0) + calibrate[thisCylinder]; // add the reading to the total: total[thisCylinder] = total[thisCylinder] + readings[thisCylinder] [index]; // calculate the average: average[thisCylinder] = total[thisCylinder] / (index + 1); // calculate the peak - look for more efficient method depending on output method // this should not be needed runPeak[thisCylinder] = 0; for (int thisPeak = 0; thisPeak { runPeak[thisCylinder] = max(runPeak[thisCylinder], readings[thisCylinder][thisPeak]); } } // advance to the next reading position in the array: index = index + 1; // if we're at the end of the array... if (index >= numReadings) { index = 0; // ...wrap around to the beginning display(); } /* set a short delay between readings to add stability set to approx 1ms when running live */ delay (1); } void display(){ int calibrateCylinder = 0; // int calibrationMean = 0; // the input adjustment added to each reading String outString; // int dispCylinder = 0; // if (calibrationFlag == 1) { calibrationFlag = 0; // only do calibration once calibrationMean = 0; for (calibrateCylinder = 0; calibrateCylinder {calibrationMean = calibrationMean + average[calibrateCylinder]; } calibrationMean = calibrationMean / numCylinders; for (calibrateCylinder = 0; calibrateCylinder {calibrate [calibrateCylinder] = calibrationMean - average [calibrateCylinder]; } // display the results and pause lcd.clear(); for (calibrateCylinder = 0; calibrateCylinder { outString = "Calibrate C"; outString += calibrateCylinder + 1; outString += " Val "; outString += calibrate[calibrateCylinder]; lcd.setCursor(0, calibrateCylinder); lcd.print (outString); } delay(3000); lcd.clear(); } else { /* send results to the lcd */ for (dispCylinder = 0; dispCylinder { outString = "C"; outString += dispCylinder + 1; outString += ": PEAK "; outString += runPeak[dispCylinder]; lcd.setCursor(9, dispCylinder); lcd.print ("___"); lcd.setCursor(0, dispCylinder); lcd.print (outString); outString = " AVG "; outString += average[dispCylinder]; lcd.setCursor(17, dispCylinder); lcd.print ("___"); lcd.setCursor(12, dispCylinder); lcd.print (outString); } } // reset all the readings to 0: for (dispCylinder = 0; dispCylinder { runPeak[dispCylinder] = 0; // must reset this. others are kept running for now /* total[dispCylinder] = 0; average[dispCylinder] = 0; for (int dispReading = 0; dispReading { readings [dispCylinder][dispReading] = 0; } */ } } Edited November 8, 2012 by tz89
darthandy Posted September 11, 2012 #23 Posted September 11, 2012 "so it had to be easy if I was going to do it. And it was easy. " I'm just dying to see your description of something that's not easy to do. But I am quite impressed with your work. Bravo!! Andy
tz89 Posted September 13, 2012 Author #24 Posted September 13, 2012 Here's the ebay item # for the LCD I used. 271024721907 Attached is the add-in Arduino library I used to make the LCD work. Be sure to virus scan the zip file. Always be safe. If you attempt to build one let me know!
darthandy Posted September 14, 2012 #25 Posted September 14, 2012 Or, you could buy one of these: http://www.twinmax.co.uk/acatalog/twinmax.html Looks quite interesting and is about 52 Pounds or 84 Canadian dollars. (The price they show includes a British tax of 20% that is not charged on international orders.) Andy
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now