No announcement yet.

1996 Mazda / Eunos / Miata MX-5 data logger...

  • Filter
  • Time
  • Show
Clear All
new posts

  • 1996 Mazda / Eunos / Miata MX-5 data logger...

    Hi, I have been lurking around these forums for about a year. I have come a fair way from the initial idea to shove a pc in my car, so decided I would start a blog on wordpress and also put some bits up here.

    I have rather an obsession with data. Combine this with my deep love of cars, and you may begin to understand why I installed a computer in my car. It is a way for me to collect data whilst I drive!

    The opportunities are endless, for example, I want to log acceleration, record videos using an on board camera, monitor gps position, develop a power curve plotter similar to this, as well as monitor fuel consumption data.

    Unfortunately my car is not a CAN vehicle, infact it doesn’t even have an OBD II port. With all OBD II cars it is possible to calculate fuel consumption. Obviously some of the other requirements are already quite bespoke. So I am quite prepared to integrate my own sensors, write software etc.

    This first post is really an opportunity to discuss what I did to build and install a car PC in my ’94 model year MX-5.

    The spec is as follows:


    * Motherboard : Intel Desktop Board D945GCLF2 (onboard graphics and soundcard)
    * Memory : 2GB Kingston DDR2 800Mhz
    * Power supply : M2-ATX 160W
    * Hard disk drive : 30GB Kingston SSDNow V-Series SATA 2.5″
    * Wifi : Edimax EW-7711UAn
    * GPS antenna : Sanav TK-158
    * Case : Automotive spec case
    * Volume control : Hacked PS/2 mouse with volumouse
    * Touchscreen : Linitx 7″ widescreen touch
    * External HDD : Good ol’ USB stick (TBA)
    * Sound : Sony CDX headunit with aux plugging into on board sound
    * Accelerometer : Freescale MMA8450Q (Denoted to me from work, perhaps not recommended if you are going to buy one)
    * Accelerometer interface : Seeeduino, Arduino clone


    * O/S : Windows XPwith enhanced write filter (to protect the solid state HDD from lots of writes!)
    * Front end : Riderunner
    * Skin : Elite lite
    * GPS : PC Navigator 10
    * Visual Basic 10 to write logging software.

    To install a PC in my small little MX-5 was actually not too bad. I started by removing the spare wheel from the boot. I then looked at installing the screen in my double DIN dash. Here are some lovely pictures of the process which was quite fun.

    I had to cut into the plastic to allow me to route the sound and monitor cables to the boot, notice the silver tape on the left used to ensure there were no burrs. Check out my handbrake, my girlfriend gave it a good varnish, the gear nob has now been done but not in this photo.

    The headunit acts as my amp, setup on AUX plugging to the computer. It is secured in place by velcro. This means I can pull the kit out easily for 'bench' maintenance. I have been able to keep RDS traffic updates as it is still plugged to my FM aerial, I also plan to run a fibre optic cable to the IR receiver. This is a cheeky way of manipulating the headunit using my remote control

    I went to B&Q and managed to get a large strip of MDF board back for the false floor in my boot. I cut it exactly, using old wallpaper as a template for my jigsawing. Now I can use the boot, without worrying about squashing the computer!

    Ordering all the bits was done over the weekend, so imagine my excitement when it all arrived at work, I built it there and then!

    And for now, a picture of it running on the bench.

    I will post more when I take more and when I have more to say. The exciting work lately has been getting my arduino working. This has been a long time coming but I am so pleased with it. I will post that work up soon.

  • #2
    Last night, I pulled the computer out of the car with the intention of installing my visual basic application for accelerometer logging. I wrote it using VB express 2010. To install, it turns out XP needs to have .NET 4 installed. What a pain that is, I have already partioned my HDD into a write protected 2 gig C: drive and the rest is D: I don't have enough C drive to install .NET so now I am facing the likelihood of reinstalling the whole machine

    ---------- Post added at 07:48 AM ---------- Previous post was at 07:40 AM ----------

    I will investigate as to whether I can easily re partition, as that is preferable at this stage!


    • #3
      I like the idea of collecting data from the car without using OBD. I'm going the same route with my car although i do have OBD. I'm building a car network using Arduino Nano's using RS485 and a RS485 to RS232 converter to my CARPC. I'm writing a Riderunner plugin to get information from the Arduino controllers in the car but also send commands to the controllers. For example I am going to replace my fog lights by RGB leds and control the color of the lights using the Arduino. The advantage of using RS485 is that I only have to have one cable with 4 wires throughout the car and have the controllers in the area they are needed. Next to the carpc I will also have old PocketPC (HP hx4700) with an application to control the arduinos. Is an idea for you as well?
      My car: 2009 MAZDA CX-9 3.7L V6 runnin on LPG (Liquid Petrol Gas)
      Hardware: None at the moment
      Software: None at the moment
      See: Velleman K8055 Plugin for Road Runner

      Progress: [XXXXXXXXXX] 0 % DONE


      • #4
        Excuse my ignorance, but what is involved with writing riderunner plugins? Is it a case of creating an executable and then simply embedding into the Ridefunner front end?

        I am planning the cheaper option of just one arduino controller. Yes it means running individual wires to individual components. If I run out of I/O I can use an I2C interface like this one

        This may be a ridiculous idea but have you considered perhaps running a CAN bus, you could then (I think) plug CAN enabled devices into your network run via your arduino using USB serial...

        So it might go something like this (feel free to poke holes in this suggestion): Arduino goes on bus as a master using something like this You then start making your CAN bus network, solder a twisted pair to the appropriate pins on the D-sub coming out of that CAN transceiver board. Then you can use off the shelf CAN enabled components to sit on the bus and be controlled from your arduino. As I say, I have no experience with this and is just a suggestion.


        • #5
          For the plugin there are examples in the RRExtension Plugin Examples directory. There is one for VB6 , VB.NET and C#. Basically you can add you own command, labels, sliders, etc in the plugin to extend to functionality of Road Runner.

          I did consider CAN. The advange of CAN over RS485 is that there is bus arbitrition. So multiple device can send and there is message priority. However, the protocol is more difficult to implement. The physical layer is the same a RS485 anyway. I'm going to use time slicing to allow all the devices to send the data to the master. The is no data that I need faster than a second so I should alright. I'm also on a tight budget. To attach another Arduino Nano to the bus I only need a single LTC485 and some resistors. To attach the PC to the bus I'm using which works very well. Seems to me that CAN bus device are a bit more expensive.
          My car: 2009 MAZDA CX-9 3.7L V6 runnin on LPG (Liquid Petrol Gas)
          Hardware: None at the moment
          Software: None at the moment
          See: Velleman K8055 Plugin for Road Runner

          Progress: [XXXXXXXXXX] 0 % DONE


          • #6
            I still have not re-partioned my HDD, however, I have just published to my blog, the first steps towards integrating an accelerometer with my car PC...

            I wanted to get an idea of cornering forces, and although completely pointless, I thought it would be fun to add an accelerometer to my carputer. I quickly realised that this was not going to be a case of simply plug and play. Most accelerometers are designed for embedded systems, this means that they don’t work with USB. A common theme was I2C, pronounced I squared C. This is a protocol proposed by Phillips a while ago. It is a two wire interface, a clock line going low and high, and a data line carrying data bits in sync with the clock.

            So of course I set about finding an I2C to USB convertor, these don’t really exist and are generally quite expensive. I continued researching and stumbled across ‘Arduino’, it can do Input/Output (I am also hoping to be able to switch things on/off like my headlights etc. using my computer). The Arduino could also talk I2C, so I bought one. I then bought a soldering iron, solder and multimeter!

            I was really quite fortunate and acquired an accelerometer from work, but something like a butchered wii remote is adequate, I suppose it depends on your required accuracy of data.


            The first hurdle was powering the damn thing, my Arduino runs at slightly less than 3.3V or an equally ‘not quite’ 5v. I needed a nice stable 1.8V. I am new to electronics and had just learnt about potential dividers. Incidentally I put that knowledge to good use, creating a VERY simple circuit + code to drive pin 13′s LED high when ambient light in the room drops low.

            Anyway, I initially planned to create a potential divider to step down my Arduino’s voltage. This is not the way to go, I tried and it just does not provide a suitable solution. A loaded circuit behaves differently to one with no current draw.

            I then learnt about zener diodes, they allow current to flow once a certain voltage is achieved, ‘knee point’ or something similar. This could work but at such low voltage it is best to use a linear regulator. I got hold of a 1.8v LDO from Farnell. A three pin affair; input voltage, ground and regualted output. Get a nice chunky one, then when you wire it up wrong it will shut down before it dies!

            An LDO needs a capacitor for stability. The data sheet often specifies what you need as a minimum capacitance, this is for high volume low cost circuit designers. However, I am lead to believe that if you have a bigger one lying around, there is no harm in using that. I have a big cap (100 microfarad) on the input side aswell as a little one (10 micro farad) and then I have another big (100 micro farad) cap on the output. The big caps are there to keep a constant flow of current as and when the LDO requires it. The smaller cap is not strictly neccessary, but it should ensure that supply remains ripple free, (its small size facilitates good transient response).

            Now I have my 1.8v I am ready to wire up the accelerometer. I am using a freescale MMA8450Q. The data sheet found on freescale’s site shows you where each of it’s 16 pins need to go, following this sheet can be tiresome but I bought some stripboard and a few 8 row dual inline (DIL) plugs and set to work.

            Wiring it up

            Something I have failed to mention so far, the I2C bus supports multiple slaves. That means you can hook loads of devices up and read from each one seperately using only two wires connected to the slave (the Arduino of course!). So I bought a temperature sensor , now I can pretend I drive one of those cars that has a sensor for the outside temperature.

            The final piece of hardware clearly visible in my completed circuit pictured below, is a logic level convertor. It consists of a mosfet and enables me to run logic at two different voltages. Basically my Arduino will be running at 5v supply and hence it sees a logic level of ’1/on’ as anything in excess of 3v for example. My 1.8v digital devices on the other hand, need only 1.5v for example, to denote a logical 1. The logic level convertor is the elegant solution to this nasty issue!

            Before producing the circuit you see before you, I sketched a rough layout to ensure I could fit everything I wanted in the available space - I needed it to fit neatly inside a disguarded Ferrero Rocher case of course! I didn’t keep to the plan it kind of evolved as I was making it.

            A tip that may or may not be common knowledge. I found that a good way to mount a flat, off the shelf integrated circuit (IC ) breakout board like the one I am using (pictured).

            Chop the legs off a resistor and then run it through the breakout board’s hole, then solder the leg to that and then onto the strip board. Look closely and you will see what I mean, I have left the odd leg poking out!

            My stripboard circuit was designed in such a way that the I2C lines were available as an expandable bus. By this I mean that the two wires (clock and serial) ran the full width of the board. You can make out two resistors in the finished picture, these are the pullups for each line and the wires are colour coded as white= SCL and red = SDA. Now in theory I can add further sensors to the bus as and when. The pullup resistors are present because the I2C lines are designed to remain in a logic high state, these ensure that the line is pulled high. The sensors in my circuit are only able to pull things to ground, they cannot pull the lines high.

            Following the data sheet I cut and soldered each of the 16 pins to their appropriate destinations and tried it out.

            Firing it up

            First off it didn’t work, this was a result of sloppy workmanship. Using a multimeter it was apparent that something wasn’t quite right. Further digging revealed the first error- I had failed to snip the excess wire off one of my components after soldering, this meant that the data line was shorted out to ground. Having solved that issue I tried again. Voltages were now as expected. I read a few tutorials online and used the wire library to perform some read/writes to my accelerometer. This failed. After many frustrated hours I READ THE DATASHEET very carefully. Basically the wire library was unable to support my hardware. The accelerometer uses ‘repeated start’ this is something unsupported by the wire library so after some searching I discovered another I2C library which quite frankly is far far better than wire. It is provided free by Peter Fleury available on his website here. Using the data sheet and this excellent library I was able to interface with the accelerometer and the temperature sensor.

            The code

            And finally, the last piece in the puzzle- the exciting bit. We write some code, compile and upload onto the Arduino’s Atmega 328 chip. So first off I downloaded my new I2C library and added it to the libraries folder in my Arduino directory. I think I might have changed the c file extension to a .cpp in order to be compatible with the arduino’s compiler.

            Be sure to include the relevant c++ library. Read your datasheet to establish the address of the device you wish to talk to. The accel chip is addressed as 0x0D and temp chip addressed as 0×48. This is #defined at the top of my sketch, a method of letting the compiler know to assign a constant value to an identifier. Here is a code snippet with most of the variables I #defined…

            #include <i2cmaster.h>

            #define ACCEL_ADDRS (0x1D << 1) //This is the MMA8450Q device address when pin 7 is high.
            #define ACCEL_CTRL_REG1 (0×38) //This is the system control register
            #define standby (0×00) //stops measuring, used to configure device.
            #define RESOLUTION (0×01) //Sets to 2g mode 0 1
            #define ODR (0×03 << 2) //Set the output data rate 3 = 50Hz
            #define WHO_AM_I (0x0F)
            #define XYZ_DATA_CFG (0×16) //Configure the ‘data ready’ register
            #define REG_STATUS (0×04) //This gets set when data is available and reset when data is read

            //temperature sensor
            #define TEMP_ADDRS (0×48 << 1) //This is the temp device address
            #define TEMP_REG (0×00) //This is the temperature register

            Now avoid blindly copying my code, you will be better reading how to use the library and applying that to your application. Check your data sheet and try to understand what is going on. That being said I will proceed with what I got up to in this project…

            The Standby and Active modes are controlled by the last two bits of the System
            Control 1 Register (at 0×38), FS1 and FS0.
            [0 0 = Standby], [0,1 = Active 2g mode], [1,0 = Active 4g], [1,1 = 8g]
            #define OUT_X_LSB (0×05) //X Register
            #define OUT_X_MSB (0×06) //Y Register
            #define OUT_Y_LSB (0×07) //Z Register
            #define OUT_Y_MSB (0×08)
            #define OUT_Z_LSB (0×09)
            #define OUT_Z_MSB (0x0A)

            int MSB_x = 0;
            int MSB_y = 0;
            int MSB_z = 0;
            int LSB_x = 0;
            int LSB_y = 0;
            int LSB_z = 0;
            int X_data = 0;
            int Y_data = 0;
            int Z_data = 0;
            int xx_dat = 0;
            int yy_dat = 0;
            int zz_dat = 0;
            int wire_debug = 1;
            int running2g = 0;
            int data_ready = 0;
            int looopcount = 0;
            int xyz_event = 80;
            bool temp_sensor_read = 0;
            double ambient_temp = 0;
            unsigned long tot_accel = 0;
            unsigned long avg_accel = 0;
            int array_pos = 0;
            const int avg_size = 10;
            unsigned int accel_now[avg_size]; //set size of array for storing readings
            bool movement_detected = 0; //false means vehicle is stationary
            unsigned int roll_reset = 0;
            unsigned short time_stamp;

            void setup()

            // Serial.println(“Serial running”);
            i2c_init(); //Sets up HW pins for I2C

            /*Initialise the sensor, put all configs here before we activate */

            i2c_start_wait(ACCEL_ADDRS + I2C_WRITE); //Accelerometer device address

            //Setup for polling mode
            i2c_start_wait(ACCEL_ADDRS + I2C_WRITE);

            /* All configs should be above, as we are going online now. */
            i2c_start_wait(ACCEL_ADDRS + I2C_WRITE); //Accelerometer device address
            wire_debug = i2c_write(ACCEL_CTRL_REG1); //This addresses the appropriate register
            if (wire_debug == 0) //Success
            i2c_write(ODR + RESOLUTION);
            if (RESOLUTION == 1)
            running2g = 1;
            Serial.println(“failed to wake the ol’ girl up”); //Error trap

            for (int thisReading = 0; thisReading < avg_size; thisReading++)
            accel_now[thisReading] = 0; //ensures the array is full of 0s when we start
            } // end setup()

            I chose to go for a fairly quick serial baud rate, anything quicker and my frontend gui was overwhelmed. The HW pins 4&5 on the Arduino are lost as an I2C interface when we send i2c_init(); Next I address the sensor and tell it to expect a write. Then I send the register address. Then I send the value intended to be written to the defined register on the defined slave address. Various configurations are then set – the data rate for example. Now onto the main programme which runs indefinately.

            So we head into the loop. I am still developing bits and pieces, this code has a timestamp which is to be passed across the serial for my GUI, in future I expect that will go and I will keep time on the pc side. My data ready flag is initialised as 0 and is set high by the accelerometer everytime the accel reports it has data on the XYZ registers. A while loop is perfect for polling. It will continually keep checking if data is ready until this flag is not 0. The commented section was used during debugging for establishing how many times I could run the while loop before data was ready. A significant number of iterations of the while loop was possible, so I decided to go and read from my temperature sensor. To avoid doing this too often I set a boolean high once temperature has been obtained, this flag gets set once outside of the main while loop.

            void loop()
            time_stamp = millis();
            while (data_ready == 0)
            i2c_start_wait(ACCEL_ADDRS + I2C_WRITE); //Accelerometer device address
            i2c_write(REG_STATUS); //Register with data ready flag
            i2c_rep_start(ACCEL_ADDRS + I2C_READ);
            data_ready = i2c_readNak();
            //looopcount = looopcount + 1;
            // Expect a min of 1422 iterations in 2g mode at 1.5 Hz
            // N.B. 1422 even after reading from temp sensor!
            // This gives us a great window of opportunity for temp readings!!
            if (temp_sensor_read == 0)
            ambient_temp = get_temperature();
            temp_sensor_read = 1;
            // Serial.println(looopcount); //for debug
            //looopcount = 0;
            data_ready = 0; //Resets flag for next loop iteration.
            temp_sensor_read = 0; //Set this to 0 to tell function to read temp sensor

            i2c_start_wait(ACCEL_ADDRS + I2C_WRITE);
            i2c_rep_start(ACCEL_ADDRS + I2C_READ);

            Binary hex and dec

            Onto some bit shifting. Computers can’t strictly count, they can recognise if voltage levels are high or not, (on or off). This is why for a computer all numbers must be made up of only ones and zeroes, for example, 5 = 101 in binary. Basically we are working with a number system to base 2.

            An unsigned 8 bit number has the possibility of representing 255 integers (as well as 0), that is, 2^8. So for 5 we have 1.(2^2) + 0.(2^1) + 1.( 2^0), giving 101. Unsigned means the number can’t go negative. If you want negative you have to use a signed integer. An 8 bit signed number ranges between 127 to -127, we have 7 bits available for the value with the final left most (most significant bit) available for the sign. Check out two’s complement for a more comprehensive description.

            Bit shifting is very handy. Hopefully you understand that numbers are represented as binary at the very basic level on the Arduino chip. Programmers often use hexadecimal, hex for short, this is purely for simplicity when writing code. It has ended up, for whatever reason that bits are often packaged as bytes, 8 bits are in a byte. One byte occupies only 2 characters in hex. Theoretically we could write 1111 1111 (this is what it will look like on the chip) or we could say 255 in decimal (base 10 is generally used in the real world), but FF in hex is the least cumbersome of the three, despite all three having the same value.

            In my code I receive 12 bits or 1.5 bytes for each direction (1 byte & 1 nibble). In order to arrange it meaningfully into one number of the correct magnitude I must do some bit shifting. It’s like if you shift the decimal number 10 left, we add a zero to the end and it becomes 100. The same happens in binary. So if we shift b101 left: 101<<1 it becomes 1010, so we now have decimal 10.

            That being said, the data is read using a multibyte read, this reduces the number of physical writes required as the accelerometer chip will auto increment through its registers, (rather than wasting time and resource using the Arduino to request data sequentially for each register).

            //Let’s start a multi byte read… (use the datasheet for the order!)
            LSB_x = i2c_readAck() << 4;
            MSB_x = i2c_readAck() << 8;
            LSB_y = i2c_readAck() << 4;
            MSB_y = i2c_readAck() << 8;
            LSB_z = i2c_readAck() << 4;
            MSB_z = i2c_readNak() << 8;

            X_data = get_accel_data(MSB_x,LSB_x);
            xx_dat = X_data / 10;
            Y_data = get_accel_data(MSB_y,LSB_y);
            yy_dat = Y_data / 10;
            Z_data = get_accel_data(MSB_z,LSB_z);
            zz_dat = Z_data / 10;

            /*I want to keep a rolling average of sum of squares for say 10 ticks at 200 Hz */

            tot_accel = tot_accel – accel_now[array_pos]; //allows us to keep rolling!
            accel_now[array_pos] = (xx_dat*xx_dat + yy_dat*yy_dat + zz_dat*zz_dat);
            tot_accel = tot_accel + accel_now[array_pos];
            if (array_pos >= avg_size)
            array_pos = 0;
            avg_accel = tot_accel/avg_size;

            /*Now we have an average, lets check if we think we are stationary! */

            if( ((accel_now[array_pos] + avg_accel) / 2) > (avg_accel)* 1.05 || ((accel_now[array_pos] + avg_accel) / 2) < (avg_accel)* 0.95 )
            movement_detected = 1;
            movement_detected = 0;


            This pretty much completes it. I am developing a quick and easy movement detected algorithm using the sum of squares to identify if acceleration is abnormal compared with the stationary average.

            I push each value out on the serial port. It is seperated using a ‘|’ this makes it easy to ID where each piece of data resides when using it in the GUI. The raw data is gathered and arranged using a function, you can see it being called in the code above, ‘get_accel_data’ for example. This and the temperature data is obtained using the functions written after the void loop() as follows:

            double get_temperature()
            double TEMP_DATA = 0; // Contains the temperature intended to be displayed as a decimal
            int TEMP_DATA_L = 0; //Low byte of the form xxxx 0000 where 0s are not populated
            int TEMP_DATA_H = 0; //High byte containing complete data set MSB contains sign info 0 = +ve

            i2c_start(TEMP_ADDRS + I2C_WRITE); //Accelerometer device address
            i2c_write(TEMP_REG); //Setup for a read from device’s appropriate register
            i2c_start(TEMP_ADDRS + I2C_READ);
            TEMP_DATA_H = i2c_readAck() << 4;
            TEMP_DATA_L = i2c_readNak() >> 4;
            TEMP_DATA = (TEMP_DATA_H) | (TEMP_DATA_L);
            TEMP_DATA = TEMP_DATA * 0.0625;
            return TEMP_DATA;

            int get_accel_data(int MSB, int LSB)
            int raw_data = MSB | LSB; //This is a 16 bit number with last 4 bits redundant

            // The arduino is already performing 2′s complement maths on a 2 byte word.
            // So once the data is arranged as a word, we can shift if back to 12 bits.

            //Get rid of the first 4 bits which are always zero.
            raw_data = raw_data / (B1000);
            return raw_data; //2024 counts for 1 g.

            There we have it. Hopefully I will post up how I get on with the GUI and how I get on with it in my car very soon.


            • #7
              This seems like a really cool project, how is it coming along?

              Have you started datalogging yet?


              • #8
                Originally posted by superart View Post
                This seems like a really cool project, how is it coming along?

                Have you started datalogging yet?
                Thanks for showing an interest. I have made some limited progress since posting! The software combines GPS and accelerometer data to estimate vehicle speed. I have written some basic coastdown software designed to capture the drag characteristics this is due to be trialled in the car in the next few days.

                I am also able to log all of my variables at about 50Hz to a text file, including gps location vehicle speed, lateral acceleration (both filtered and raw), as well as predicted power at the wheels, based upon vehicle speed and coastdown characteristics.

                Next job now is to decide the best way to obtain engine speed and integrate it into the system...