Measuring engine RPM with Arduino

You can measure engine RPM using the negative terminal of the coil, however you need to isolate the 12v circuit of the coil, from the 5v levels used in the Arduino. This can be done using an optical isolator circuit as detailed below.

The following schematic shows how to connect the circuit:

RPM Module Schematic

Assembly List

The following components, or their equivalent are required to build the RPM module.

Label Part Type Properties
4n25 DIP – 6 pins package DIP (Dual Inline) [THT]; hole size 1.0mm,0.508mm; true; chip label IC; pins 6; pin spacing 300mil
Arduino Arduino Uno (Rev3) type Arduino UNO (Rev3)
C1 Ceramic Capacitor package 100 mil [THT, multilayer]; capacitance 100nF; voltage 6.3V
C2 Ceramic Capacitor package 100 mil [THT, multilayer]; capacitance 100nF; voltage 6.3V
D1 Rectifier Diode package 300 mil [THT]; type Rectifier; part # 1N4001
D2 Zener Diode package Melf DO-213 AB [SMD]; breakdown voltage 5.1V; type Zener; power dissipation 0.5W; part # 1N4732A
R1 390 Ω Resistor package THT; tolerance ±5%; bands 4; resistance 390Ω; pin spacing 400 mil
R2 4.7k Ω Resistor package THT; tolerance ±5%; bands 4; resistance 4.7kΩ; pin spacing 400 mil

Example Code

volatile unsigned long timePointsOpen, timePointsClosed, lastChange;
volatile unsigned int numBangs;

void pointsOpening(){
    unsigned long t;
    t = millis();
    if (lastChange > 0){
        timePointsClosed += (t - lastChange);
    }
    lastChange = t;
    ++numBangs;
}

void setup(){
  pinMode(3, INPUT);
  digitalWrite(3, HIGH);
}

void loop(){
  // Number of coil pulses
  numBangs = 0;
  attachInterrupt(0, pointsOpening, RISING);
  delay(50);
  detachInterrupt(0);
  numBangs = ((60000/50)*numBangs)/2;
  Serial.print("RPM: ");
  Serial.println(numBangs);
}

Arduino Megasquirt Library

This driver provides access to the MegaSquirt ECU with a level of abstraction above the MegaSquirt serial interface, enabling users with no knowledge of the MegaSquirt commands to access the register data easily without caring about the underlying communication required.

The MegaSquirt is a low cost engine control unit with support for fueling, ignition and idle control.

Wiring

The MegaSquirt is connected to the Arduino using the RS232 output on the MegaSquirt, a MAX232 chip, and the Serial interface on the arduino board.

Synopsis

 
#include >MegaSquirt.h<
void setup(){
 MegaSquirt::begin();
 
 byte status;
 String signature;
 status=MegaSquirt::signature(&signature);
 switch (status){
  case MS_COMM_SUCCESS:
   Serial.print("MegaSquirt Signature: ");
   Serial.println(signature);
   break;
  case MS_ERR_COMM_TIMEOUT:
   Serial.println(" FAILURE: Communication Timeout");
   break;
  case MS_ERR_COMM_OVERFLOW:
   Serial.println(" FAILURE: Communication Overflow");
   break;
  default:
   Serial.println(" FAILURE: Unknown Error"); 
 }

String revision;
 status=MegaSquirt::revision(&revision);

 uint16_t uptime;
 status=MegaSquirt::seconds(&uptime);

 MegaSquirtData registers;
 byte regTable[MS_TABLE_LENGTH];
 status=MegaSquirt::getData(regTable);

 registers.loadDAta(regTable);

 Serial.println(registers.lambda1()/10,DEC )
}

Download

You can download the ZIP file to import into the IDE here, or you can fork your own.

Mesh refinement with SnappyHexMesh

Mesh refinement is probably one of the hardest components of OpenFOAM, for me this mainly revolves around snappyhexmesh and blockmesh, with one or more STL files exported from SolidWorks as the input.

The first thing to get right is the position in the the blockmesh, you can do this using a transform, or by changing the coordinates in the blockmeshdict.  Then check the refinement box is suitably sized, this one was too small so I made it larger using the refinementbox settings:

refinementBox
      {
          type searchableBox;
          min (-1.0 -1.4 0.0);
          max ( 8.0  1.4 2.5);
      }

Next up is to look at the basic refinement and improve that, currently, the basic mesh looks like this:

Using feature edge detection should align the cells better with the edges of the features.  First we run surfaceFeatureExtract on the STL file, then update snappyhexmesh to use edge detection.

   features
   (
       {
           file "seven.eMesh";
           level 10;
       }
   );

I also turn on feature snapping

nFeatureSnapIter 5;

This makes the edges much cleaner, but the mesh is still too course.

Adding more layers of refinement around the car should improve the mesh some more, to do this we use the addLayersControls settings below:

nSurfaceLayers 3;
expansionRatio 1.3;
finalLayerThickness 0.7;
minThickness 0.25;

Next I make the bounding box slightly finer using blockmesh

blocks
(
     hex (0 1 2 3 4 5 6 7) (80 32 32) simpleGrading (1 1 1)
);

At this point I also need to turn up the max cells a little, and add another refinement level

maxGlobalCells 12000000;
refinementSurfaces
{
     seven
     {
     // Surface-wise min and max refinement level
     level (5 6);
     }
}

 As you would expect, mesh size increases dramatically, as does the time to create the mesh.  The result is improved, however the quality of the mesh is still poor in places, this will need further effort.

OpenFOAM rotating boundary conditions using rotatingWallVelocity

So far my model has used only a single STL file with no patches, and did not take into account the rotation of the wheels and tyres.  I figured out the OpenFOAM part from this thread on CFD-Online, and used paraview and solidworks to modify the model.

I’m working with a large assembly, with each component as its own part which makes getting things in the right format fairly easy.  The first thing to do is save the whole assembly as individual STL files.

As this created a few hundred files, all with spaces in the name, I opened them in paraview and used the Append Geometry filter to create a single object for the front axle, rear axle, and everything else.  For each of the new geometries, i added an Extract Surface filter.

As I managed to get my solid model in a strange location in Cartesian space, I performed a translation to rotate and move them to the middle of the bounding box.  I could have also moved the bounding box in blockmeshdict.  I then saved the three surfaces as chassis.stl, faxle.stl, and raxle.stl. Use the ascii file format.

Paraview calls the solids ascii (I’m assuming binary if you use the binary file format) since these dictate the name of the patch that snappy will create, it makes sense to rename these based on their file names.  These then need to be concatenated into a single file.  I used some sed foo to do this.

This then gives me three patches, seven_chassis, seven_faxle and seven raxle.  These need to be defined in the initial condition for U.

Originally there was just a single definition:

"seven_*"
    {
         type            fixedValue;    
         value           uniform (0 0 0);
    }

However, we now need to define the three patches explicitly.  The first is easy, as its the everything else part.

"seven_chassis"
    {
         type            fixedValue;    
         value           uniform (0 0 0);
    }

However, for the rotating boundary, we need to know a few more things.  The first is the origin of the rotation, I created a point in the center of the axle and manually applied the appropriate transformation to get the center of rotation.  As I’m assuming that there is zero toe and zero camber, this is trivial.  In the future I may wish to improve on the model in which case I will have four patches, and I’ll add some sketches to the model to work out the correct axis.

The axis of rotation in my model is the y axis, which again is trivial in this case.

Lastly I needed to work out the speed the wheels are rotating at.  I am modelling the car at a speed 40ms−1, and Omega, the boundary condition is measured in rads/second.

First we calculate the distance travelled in one revolution of the wheel.  I have 13 rims with 205×60 profile tyres. This gives a circumference of 1.8146Meters giving 22.04 revolutions per second.  1 Revolution is 2pi radians, giving 138.5rads/sec.

"seven_faxle"
      {
          type            rotatingWallVelocity;
          origin          ( 0.839 0 0.2775 );
          axis            ( 0 1 0 );
          omega           138.5;
      }
      "seven_raxle"
      {
          type            rotatingWallVelocity;
          origin          ( 2.753 0 0.2775 );
          axis            ( 0 1 0 );
          omega           138.5;
      }

Automotive Arduino Power Regulator

Jonathon Oxer and Hugh Blemings describe an excellent power regulator for Arduino in automotive applications in their book “Practical Arduino Projects”. Loguino doesnt need to be notified about a power failure, but it did seem sensible to be able to provide a buffer which may help when the car is being started.

Parts List

  • IC1: LM294OCT-5 – An automotive grade 5v regulator
  • D1: 1N4001 Diode
  • F1: 3A Fuse
  • C1: 100uf Capacitor
  • C2: 47uf electrolytic capacitor ideally rated to 16v max
  • C3: 47000uf capactor, rated to at least 60v

 

Scanning the car with an Xbox Kinect and Paraview

I have a pretty accurate drawing of the Seven, from the drawings i’ve created models in OpenFoam.  I want to do the same for the Fury, however I don’t have drawings of the bodywork.  Drawing freehand in Solidworks would take me forever, so I decided to try scanning the car using an Xbox Kinect and the openkinect libraries.

The first thing that you need to do is get a point cloud from the xbox kinect, this is not quite straightforward as it seems. First the sync_get_dept() returns a disparity image, not cartesian points, so some conversion is required.  The openKinect wiki has most of the background information required.  The calibkinect library can do most of the calibration work, this can be formatted into whatever format suits you best.  I chose wavefront’s format as it stores the point normals and can be read by both MeshLab and Paraview.

Getting a single disparity image is quite easy, however stitching many together is more challenging.  Fundamentally in order to scan an object you need to know the following:

  • Where the camera is relative to a fixed point in space
  • Which direction the camera is pointing.

Assuming you know these two things, you can do a fairly simple matrix transformation on the points to move them into the appropriate location. Initially I tried to find a clever way to triangulate the position and direction of the kinect, it would be great to be able use it like a wand, however this requires significant levels of accuracy, and the only sensor on board is a tilt sensor.  GPS wont cut it, I had some ideas about using a bunch of cameras, or ultrasonic sensors, but in the end I shelved that idea for now.

Instead I decided the easiest way to get a usable scan was to do things the old fashioned way.  I only need to scan half the car, as its symetrical.  As such I created a box around the car.  This allowed me to position the camera at a known location.  I used a tripod to hold the kinect, and took images at one meter intervals from about one and a half meters away from the car.

I then cleaned each mesh in MeshLab so that I just have the car, and no background.  Then loaded each one into paraview and applied transformations to each file until they were lined up based on the measurements I’d taken earlier.  This worked pretty well but required some manual adjustments for the first image in each direction.

The end result is good enough for a first attempt.  I’ll load the file into Solidworks and start drawing.

Loguino Data Aquisition for Arduino

I’ve been interested in capturing data from the seven since the moment I could drive it. I’ve looked at commercial data loggers, and there are plenty of good options, I use the ETB Digidash on the Fury, and it’s very competent, not least in the analysis software.

For the seven though, I didn’t feel there was a good fit for a number of reasons:

  • not many data logging tools support reading data from the megasquirt ECU, which is critical to get any information about the engine at runtime.
  • Many data loggers are geared towards providing an in car display system, but I already have a working dashboard that I like.
  • Usually they are limited to a number of channels, each channel having a predefined function or purpose.
So I decided one day to make my own, my first step was the bifferboard, this is a 486pc on a chip, it was easy to program since it runs linux, but it wasn’t the right tool for the job.  I’d hear lots of good things about Arduino, an embedded platform, and once I got my head around the API, it was clear this was the perfect solution, and shortly thereafter loguino was born.
Loguino itself is a generic logging platform, it functions a little bit like log4perl/java/etc in that you have a logging class that accepts log messages, and logger outputs that take those messages and do something meaningful with them.  Most of the time this is simply write the message to a disk, or output it over the serial line, but it could be used to control shift lights or any other task too.
Data is generated by pollers, pollers are polled periodically and generate messages which are picked up by the loggers.  The first task was to write one for the megasquirt, this allows me to pull engine data directly into the logging tool. The next step was gps speed and positioning, and then support for accelerometers and gyroscopes.
I chose a very simple logging format, rather than use columns, I decided to use key value pairs, this means the tool can be completely agnostic about formatting, time, and everything else.  My view is that once data is downloaded of the loguino, it will go into a database and be queried.  Having seen google chart, and flot, I decided there was no real need to use excel or write complex software, instead it should be a case of adding and removing series, and scaling them.  This spawned metriflot, a data visualization package, and was a great way for me to learn some Ajax and django.
Having tested loguino over the summer, I’ll be doing a permanent install over the winter with wheel speed sensors, brake temperature, pressure, and all sorts of other sensors, and generally tidying up the packaging.  Next year I’ll be able to concentrate on the analysis where I want to have more intelligent data trending, for example:
  • Is the engine temperature hot because of the outside temperature, speed, or a fault?
  • Is the oil pump failing or was i just not driving hard enough?
There is a lot of potential here, as well as a good chance for me to learn more about electronics and data analysis, and hopefully it will benefit others too.
Loguino was released under the GPL license, and is hosted on google code.

CFD for the Seven

I’ve long had an interest in CFD, and now that OpenFOAM is getting pretty mature, I decided to have a go at modeling the seven.  I drew the car using Solidworks, I focussed more on the shape of the car, rather than accuracy of the chassis etc and the result is a fairly simple parametric model.

Lotus seven replica modeled using open foam, visualized using paraview
SimpleFOAM was used to create the data, then ParaView to visualize the result.

As I only have a couple of macs at home, I used RDP to connect to an amazon EC2 instance to do the actual drawing.  This works surprisingly well, and has the added advantage of not having another windows system to deal with.

To perform the actual CFD, I use openFOAM running on my mac mini to do the preprocessing, then ship this off to a linux instance on ec2 to do the actual calculation.

Looking at this thread, it would appear that its worth spending some time tweaking the solver to converge sooner, since my main issue right now is the time for a run, and the memory requirement for meshing, it would make sense to optimize this, so i’ve written a workflow and some optimization logic.  The end result should be a model that can tune itself within certain parameters, not only for the solver, but also for the model itself, with Solidworks reading in parameters at run time and generating a new STL file for each combination.

Post finals, I’ll tidy it up and publish the optimizer.

Self Inflicted Misery

Camping next to the broch

After a very enjoyable week hiking and driving around northern scotland without a hitch, disaster finally struck on my way home.  Not long after leaving the house the car just cut out with no warning, the first time I managed to grind to a halt and stop in a lay by.

It was likely something electrical, so I opened the front of the car and started wiggling.  Eventually after pulling at random wires for a while it started up, and I drove off only for it to cut out again about 10 minutes later.  This time I came to rest just after a blind bend, I felt the only thing to do was get the car off the road, so I used the starter to pull the car forward 15, this ultimately was what ruined my day out.

After more wiggling, and as the battery started to go flat, I called out green flag who sent out a local recovery company.  We hooked up a spare battery and started wiggling again, eventually the engine started, and we continued wiggling until it cut out again, this time I noticed that the battery lead to the solenoid was loose, this is also where the main electrical feed for the ECU branches off, so it was tightened up and off I went.

I stopped for fuel 200 miles later, and as i started the engine up, i noticed that the starter was turning very slow, and initially put this down to the battery being flat and the generator being weak, and drove off.  About 20 miles later it cut out again, this time I noticed the battery lead was loose, I reconnected it but the car wouldn’t turn over.  I called out the green flag again.

As it turns out the issue was not a flat battery, in fact far from it, I’d managed to kill the starter motor which when I removed it was just a pile of black soot and burned electrical connections, this was the price I paid for using the starter motor to get the car off the road, although I’d rather a broken starter than a smashed car.

I wasn’t convinced i’d solved the electrical problem for good though, loose battery seemed too good to be true, and one would  expect that if its loose it would stop running completely, or make no difference, as the generator isn’t affected.  Green flag only restart your car once, after that its recovery or your on your own, so rather than get suck and have to call out the ANWB, I decided to have the car recover to Andy Bates for a new starter, and to get the engine mount beefed up as it had cracked.

I found the electrical issue, or should I say issues once I got the car home a few weeks later, there was some corrosion on the fuses, when the bulkhead flexed the car cut out as a result.  I was finally able to reproduce this when examining something with the lid open, replacing the fuses has solved that issue, and its easy to check.  I expect the loose connections didn’t help things either so I glued and lock wired them accordingly.

 

First Nurburgring trip in the Fury

Did 8 laps of the ring in the fury, all I can say is that it sticks to the tarmac like glue, goes like stink, and is probably the most fun I’ve had outside the bedroom.  It took me a while to really get it up to speed, and my camera only lasted a lap sadly.

It’s also the first time I’ve ever been on the larger VLN circuit, its quite nice as it gives you some space to really push the car a little before going back onto the north loop which is less forgiving.

Fury at the Nurburgring

Fury at the Nurburgring

Fury at the Nurburgring

Fury at the Nurburgring