Background and Purpose

Some weeks ago a friend broke her forearm: she was on a bus whose driver violently pulled the brakes, and she fell down. This reminded me of the few times in which I had to (politely) remind the bus driver that he was not suppossed to transport cattle.

So, I decided to investigate a bit on the quality of public transport driving and, finally, went to make my own accelerometer data logger, and to put it into use.

There are plenty of webpages on DIY data loggers and accelerometers; also lots of information on data analysis; and also even some pages on bus driving quality. This Instructable, though, is not just another "howto do your own accelerologger", at least because I have not seen any one which covers the design, make, use and analysis, all in one. So this is it: A to Z for making and using an accelerologger.

There are also apps for smart-phones and tablets which read the device's sensors and which too can save the records - but how would one learn in this way? And what's the fun compared to doing it by yourself? But no offence if you prefer the app! :-)


The level of this Instructable is intermediate: at one end, for instance, I will almost not comment the Arduino code as I assume that you are already reasonably familiar with it; and at the other end I will not enter, say, into the mathematical details of data filtering or time frequency analysis.

Step 1: BOM

What is Required?

The list of materials for this accelerologger is as follows:

  • 1 Arduino Pro (5V, 16Hz)
  • 1 module GY521 (with accelerometer and gyroscope MPU6050)
  • 1 SD breakout board (and, yes, the memory card)
  • 1 4-DIP switch
  • 1 2-pin screw terminal
  • 1 LED + 330 ohm resistor (I later added a second LED).
  • 2 capacitor (100 nf)
  • 1 perf board (5*7 mm, 2.5 mm pin spacing)
  • 1 battery holder (4 LR6/AA, included please)
  • Pin headers and flexible wires (plain, pinned female)
  • Welding gear, plywood, glue, tools.

Of course there are miriads of possible variations. In general, I have used what I already had in hand, and here I include few lines on my choices:

  • I really, really, like the Arduino Pro: small, cheap, reliable, easy to use, tough and powerful. Still, it is a too big horse for this project, but it is the smallest that I have!
  • SD board/card: I'd rather use a microSD board/card, but the large one is what was available in my box, so... There are references of bad experiences with powering the board at 5 V (not the +5 V VCC pin, but the data transfer pins). I can only say that mine works OK at 5 V, so far.
  • The accelero/gyro GY521/MPU6050 seems to be a usual choice, so no regret on this regard. I am surprised by the amount of noise and requirements for calibration (see below), but I cannot compare to other accelero/gyros. I wonder if the analog units are better on this aspect.
  • LR6/AA batteries. The package required to reach the 6 V for the Arduino Pro is "large", and the first alternative is the 9V 6LR61/6AM6 "rectangular" battery. However, sometime ago I read that the energy density or delivered power of the 6LR61 is very low compared to the LR6, so I am not using them anymore. Also, it is very easy to find rechargeable R6/AA batteries. Finally I thought of LiPo batteries, but did not further develop (for no real particular reason).
  • I like welding (though I'm not that good), so, for me, welded PCBs are a good enough solution for relatively simple circuits. I also considered etching a printed circuit, but, apparently, some parts were missing in Fritzing and I preferered not to create them with their real dimensions etc. Finally, I definitely use headers for the main parts, so that after I'm tired of my circuit (or, ehem, it does not work) I can easily recover the main parts. (I know that this is probably a cause of faulty connections, but I take the risk).

How Much does it Cost?
Total cost, roughly (from where I normally buy, www.dhgate.com):

  • Arduino Pro: 3.5 USD
  • GY521: 4.5 USD
  • SD board and card: 9 USD
  • Total: approx. 25-30 USD

Step 2: Build It - Hardware

The Fritzing schematics are in a picture; the original file is uploaded here:

Kindly note that some parts in the scheme are not exactly what I have actually used (namely the accelero/gyro board and the SD board): I have added some remark notes in order to provide further clarity on the wiring.

Attached are also some pictures of the making process, from the protoboard to the final result.

Two final notes regarding possible "mistakes":

  • There are two capacitors, aimed at stabilizing the supply, although probably there should only be one, if any. Still, one is on the "upstream Arduino" side, and the other on the "downstream" part.
  • The Arduino Pro Mini board description mentions that "If you're supplying unregulated power to the board, be sure to connect to the "RAW" pin on not VCC." The supply to the Pro is done on the VCC connection, either from the PC, through the USB adaptor, or through a battery - hope both are regulated enough! :-)

Step 3: Build It - Software

Sketch Used

The accelerologger runs with Arduino, and the code/sketch can be found here.

Few comments on the general parts of the code:

  • The 3 DIP switches which are coded (#2-4) are pulled-up with the pins' internal resistors. The action of the switches are:
    • DIP02: continuous reading. If the switch is off (pin high) the duration of the reading is defined by TimeR (time of reading), whose value is defined within the code. If the switch is on (pin low) the data reading and writing goes uninterrupted (actually there is a code line where this can be limited, by default I have set 2 hours).
    • DIP03: interrupts the reading. If the switch is off (pin high) the reading goes as specified by DIP02. If the switch is on (pin low) the reading & writing step is bypassed, but the timers are not stopped. This allows for a clean halt of the reading in case of need.
    • DIP04: calibration. If the switch is off (pin high) there is a calibration phase at setup. If the switch is on (pin low) the calibration step is bypassed.
  • The DIP switch which is not coded (#1) powers the Arduino Pro from the batteries. Here the off position means switch disconnected (no-power).
  • The calibration function simply reads data and writes it to the SD card during a time defined within the code (TimeC). There is no use within the code of the calibration results, the purpose is just to gather information at a controlled stage. What use should be provided to this information is a matter of postprocessing (see next Step).
  • The data reading and writing frequency can be specified in the code (name of variable: frequency, in Hz). In order to adjust the timing an input is required: the average time of reading and writing (TimeDRW), which in my experience is 20-25 ms. The resulting frequency is not exact, just good enough for my purposes.
  • The yellow LED is on when things go OK (reading and writing), blinks slowly during preparation (setup) and completion of the data reading&writing. If there is a problem with the data (the x component of acceleration is -1 or 0), the red LED blinks for a short time; if the problem is related to the SD card, the red LED stays on. When there is a SD-related difficulty or the task has been completed the sketch enters a repose mode (infinite void loop) after informing with the corresponding blinking.

MPU6050 and Software

Regarding the MPU6050:

  • The communication with the board is done through the I2C protocol.
  • I have used the code prepared byJohn Chi at http://playground.arduino.cc/Main/MPU-6050.
  • Jeff Rowberg has extensively worked on libraries and code for this device (see https://github.com/jrowberg/i2cdevlib and http://www.i2cdevlib.com), but for my purposes I found that Chi's approach was good enough through the Wire library.
  • The raw data read by the MPU6050 is in local coordinates. If global coordinates are required, the MPU6050 has an additional processor (DMP, Digital Motion Processor) which can provide the required calculations. This DMP also has error minimization capabilities. Access to the DMP results can be achieved through the libraries written by Jeff Rowberg.

Step 4: Use It - Calibration

Why Do We Need to Calibrate?

Isn't the sensor already calibrated from the factory?
These are ten consecutive readings (accelerations followed by angular velocities; x, y,z in both cases) with the GY521 in standstill, vertical position (axis +X upwards):

  • 17088 208 -1048 5 -1 -216
  • 17028 308 -1320 4 3 -250
  • 16988 360 -1212 7 3 -236
  • 16876 376 -1032 -13 -36 -218
  • 16972 244 -1348 -13 -25 -226
  • 17060 316 -1156 -2 -11 -224
  • 16948 328 -1300 -31 0 -224
  • 17016 332 -1124 1 -1 -209
  • 17088 348 -1088 -6 -27 -238
  • 17072 284 -1104 -13 -24 -228

If the device was really vertical, the readings for the accelerations should be (see below the reason): (16384, 0, 0); and if the device was really still, the readings for the gyroscope should be: (0,0,0). So: the readings should all have been: [16384, 0, 0, 0, 0, 0]: what's wrong? Or, is actually anything wrong?

Three things are probably happening:

  • the device is still, at least with no noticeable movement, but it is likely not perfectly vertical,
  • there is signal noise, and this is probably the cause of the fluctuation in the instant readings,
  • the readings are raw, not calibrated, which is why they are "deviated", on average.

So, let's go step by step.

ADC of the MPU6050

The MPU6050 has an integrated ADC (Analog-to-Digital Converter) which outputs each channel (acceleration and angular velocities, each in x, y, z) in 16 bits. Therefore 2^16 different results are possible: 0 to 65535, or -32768 to +32767. This range of readings is mapped in the standard configuration to +-2g in accelerations, and +-250 deg/s in angular velocities. Then 1 g corresponds to 16384 LSB (Less Signifficant Bit, or digital raw units of reading), and 1 deg/s corresponds to 131 LSB.

Both ranges can be changed in the configuration settings via software through Jeff Rowberg's code (see previous Step). The possibilities are:

  • Acceleration ranges: +- 2g, 4g, 8g, 16g
  • Gyroscopes ranges: +- 250, 500, 1000, 2000 deg/s.

Note that because of the ADC's 16 bit constraint, extending the ranges of measurements decreases the sensitivities: the +-4g range mapped into a reading range of (-32768,+32767) gives 8192 LSB/g.

So, the raw readings can be converted into "physical" units with the known sensitivities are:

  • 1,042969 0,012695 -0,063965 0,038168 -0,007634 -1,648855
  • 1,039307 0,018799 -0,080566 0,030534 0,022901 -1,908397
  • 1,036865 0,021973 -0,073975 0,053435 0,022901 -1,801527
  • 1,030029 0,022949 -0,062988 -0,099237 -0,274809 -1,664122
  • 1,035889 0,014893 -0,082275 -0,099237 -0,190840 -1,725191
  • 1,041260 0,019287 -0,070557 -0,015267 -0,083969 -1,709924
  • 1,034424 0,020020 -0,079346 -0,236641 0,000000 -1,709924
  • 1,038574 0,020264 -0,068604 0,007634 -0,007634 -1,595420
  • 1,042969 0,021240 -0,066406 -0,045802 -0,206107 -1,816794
  • 1,041992 0,017334 -0,067383 -0,099237 -0,183206 -1,740458
  • Units: g and deg/s

Good, but ... what's the real result? How many decimals can be properly used? I have selected 6 decimals, but why not 10?

Manipulation of Numbers

What we can say is that with a 95% confidence level (based on all the records of the calibration, not just the 10 shown here) the averages can be calculated with statistical tools and consideration of the rules of significant figures. See here the spreadsheet, whose results are:

  • Ax = 17002 +- 5 LBS <-> 1.038 +- 0.000 g
  • Ay = 328 +- 4 LBS <-> 0.020 +- 0.000 g
  • Az = -1170 +- 6 LBS <-> -0.071 +- 0.000 g
  • Gx = -1.9 +- 0.7 LBS <-> -0.014 +- 0.005 º/s
  • Gy = 0.6 +- 1.1 LBS <-> 0.004 +- 0.008 º/s
  • Gz = -227 +- 1 LBS <-> -1.730 +- 0.007 º/s

Clearly, just by looking at the results: the acceleration readings seem to be "reliable", and Gy is not. But even these "statistically corrected" averages are still not what one would expect! Acceleration should be 1.000; and, in addition, one wonders why the average of Gz is so high if the device was not moving.

So, enter calibration - at last!

Calibration (of the Accelerometer)

First remark: calibration is not intended to correct the results of a faulty sensor. If from the previous results we feel that sensor Gz is likely broken or miss-connected, then there is probably no calibration which can fix it.

Second remark: a calibration compares readings, or readings with assumptions. Extrapolation beyond those readings requires care.

The MPU6050 displays a theoretical linear relationship between the measured accelerations or angular velocities and the output. (The product specification datasheet mentions a "nonlinearity" of 0.5% and 0.2%, respectively; "cross-axis sensitivity", the amount of change introduced in one axis by the application of acceleration or angular speed on another axis, is 2%).

Then,it might be possible to apply corrections to the converting equations. In the previous case, for the accelerations the correction of the gain error leads to:

  • Ax(g) = (Ax(LBS) )/(16384 + 618)

Offset deviations might be also corrected:

  • Ay(g) = (Ay(LBS) - 328)/(16384- 328)
  • Az(g) = (Az(LBS) +1170)/(16384+1170)

This offsetting procedure could be correct IF we are sure that the accelerometer was really vertical (+X up) when the calibrating measures were taken - otherwise it is not correct. It may be that the error thus introduced is small, but it is nonetheless not correct. And, unfortunately, it is difficult to be sure of the accuracy of the verticality with which the MPU6050 is placed during the calibration.

One alternative calibration procedure (the "six positions test") would be to read six times the acceleration results, with the device still. On each of these instances the sensor would be turned so that every time a different axis is on the "vertical" (+-x/y/z). The readings on each position for all axis provides enough information for a detailed calibration.

A simple description of this procedure can be found here; more precise info here; more serious here.

Regardless of the position of the sensor, if it is not moving, then the norm or modulus of the vector acceleration should be 1 g (or whichever is the gravity acceleration in your location). This can also be used for calibration purposes in any position of the sensor.

Calibration (of the Accelerometer) other than with G

Two simple additional calibration tests seem possible, although I have not developed them:

  • Free fall: An accelerometer in free fall should read (0,0,0), regardless of its spatial orientation. It will probably be difficult to collect enough data before applying an arrestor (from my 7th floor it will take the tester barely more than 2 seconds to reach the street).
  • Pendulum: A pendulum on whose bob is the GY521 would measure accelerations and angular velocities which are relatively easy to calculate.

Calibration (of the Gyroscope)

The standard procedure used for the calibration of the accelerometer can be used for the offset control of the gyroscope, but it provides no clue about the gain error. If the gain error needs to be checked, I assume that a calibrated pendulum might be required.

How Much Time for Warm-Up? And for Calibration?
A chart is attached showing the readings logged as quickly as possible after powering up the Arduino. No warm-up period is apparent - or, if there is any, it seems that is very short and of no practical effect for my purposes.

The question of how much time is required for calibration data reading can be converted into a statistical issue: how many samples are required from a general population to accurately estimate the average? The answer is: as many as required in order to provide stable results. There are explicit expressions for the number of samples, but, in general and when feasible, it is preferable to make as many assumptions on the population as possible. An attached chart shows the evolution of the estimation of Ax with the sampling size. After 10-15 seconds of readings the results are quite stable, and my recommendation would be to read for 20-25 s at a frequency rate of at least 25 Hz.

Step 5: Use It - Get on the Bus!


So, get on board the bus and fix the accelerologger!

Precautionary remarks, though:

  • A bus is a complex dynamic element: not all its parts are moving equally or simultaneously. Of course, the bus as a unit is moving, and with it all its constituents (including passengers). But in addition to this solidary movement there are different behaviors which are reflected in the kinematics of the components. Front and rear, left and right, low and high; frame, seats, windows, doors, handrails: all have different movements.
  • Therefore, what the accelerologger will record is the acceleration and angular velocities of the ... MPU6050 (or so we hope!). How much does this differ from the conditions of another element of the bus to which the accelerologger may be attached is dependent on the dynamics of the element as well as on the attachment conditions and the dimentions/weight/etc of the accelerologger. A rigid connection is likely to introduce little distortion, while a floffy link can be expected to create quite different performances.
  • The bus is not yours. It may be a good approach to request permission from the transportation Company, or at least inform the driver of your purpose.
  • If some of the travellers do not like the appearance and lights of the logger ... try politely to calm them!

But before you come up the bus with your nice device...

Step 6: What Sampling Frequency?

The data reading frequency, or sampling rate, can be set at the sketch (see a previous Step), but which sampling rate is best?

The answer is easy: as low as you really need, or just a bit more to be safe. If you read too often, you will likely get noise and tons of data which you may not know how to use.

OK then: what is the lowest samping data that you need?

Well, It depends on your requirements! Sorry for the vagueness, but it may be easy to understand with an example. If you drive at 100 km/h and want to spot a bumper or a pothole which are 0.5 m long, a sampling rate of less than 56 Hz is likely not to detect it, while a sampling at 150 Hz will get 3 readings on the obstacle.

Now: will these 3 readings be enough to be clearly separated from the background noise? Here I can also not provide other answer that: "Test it!".

(The theory says that if the sampling is done at a rate at least twice the maximum frequency included within the signal, then it is possible to recover the initial signal. Still an obstacle, though: it is not obvious which is the frequency of the signal in the example of the pothole, so tests seem to be necessary in any case. A numerical guidance to the pothole case: if there is a main frequency event once the car's wheel is, say, 5 cm off the pothole edge, then a sampling frequency of 1.1 kHz would be required).

Nevertheless, some information that I have gathered on actual sampling rates:

  • Normal personal activities: 2-10 Hz (for measurements on the body trunk).
  • Bus accelerations for driving quality measurements: 20-50 Hz (in some cases 1 kHz are mentioned...)

Finally: remember that the maximum sampling rate in my sketch is limited by the time required for reading and writing, which in my case is about 20-25 ms per cycle. Therefore the maximum sampling rate of my accelerologger is approx. 40-50 Hz.

As a reference: the sample rate of the MPU6050 is 1 kHz for the accelerometer and 8 kHz for the gyroscope. On the interface: with a frequency of 400 kHz for the I2C, the maximum nominal transfer data rate is 2.6 kHz (17 bytes (accelerometer + temperature + gyroscope) at 9 (8+1) clock tics per byte). And at the other end, the transfer rate on the SD is (???).

Although I have not digged on the subject, I assume that the relatively low sampling rate of this accelerologer is related to two of its features:

  • (I think) I'm not using the asyncronous data transfer that the MPU6050 allows. Access to a FIFO buffer on the MPU can be managed through Jeff Rowberg's code.
  • The data storage is done opening and closing the storage file every time data is received from the MPU, which is likely a very slow process. This should be a quite easy task if a larger sampling rate is needed.

Step 7: Public Transport Driving Quality

A Standard: EN 13816

The standard EN 13816-2003 Transportation. Logistics and services is the basis in the EU for defining and measuring the quality capability of transport providers in public passenger traffic services.The quality of the service is evaluated in different domains, and the standard includes the following ones (informative, not mandatory):

  1. Offered Service
  2. Accesibility
  3. Information
  4. Regularity and Punctuality
  5. Customer Service
  6. Comfort
  7. Security
  8. Environmental Impact

Within level 6, item 6.3 Passenger Comfort the standard includes:

  • 6.3.1 Driving
  • 6.3.2 Start/stop
  • 6.3.3 External factors

The public transport company of my town is EN13816 certified. Interestingly, the policy (see here) does not mention anything related to the driving style or behavior, the smoothness/recklessness driving as an element of the perceived quality. Or, as mentioned in other traffic quality management cases: "driver operation of the bus in a safe and competent manner", or "operation of the bus in a manner so as to provide a smooth ride".

As a side comment: I think that my town's bus company is doing reasonably well - nevertheless, I also believe that driving quality can be signifficantly improved, and that this will increasingly become a must with a quickly ageing customer base. (See this for some information on people's accidents on buses).

Reccommended Accelerations

There does not seem to be a general agreement on appropriate accelerations on public ground transport systems. However, what I have been able to gather can be summarized as follows:

  • Steady non-emergency longitudinal accelerations in the range 0.10 g to 0.15 g are acceptable in most cases.
  • If the passengers are properly seated, the tolerable for-and-aft acceleration levels can be higher, up to 0.20 g, as in a commercial jet take off with usual average acceleration in the range of 0.25 g for a take-off velocity of approx. 250 km/h (peaks can reach 0.5 g). As a reference: a VW Golf GTI can reach 100 km/h in 7 seconds, or an average acceleration of 0.4 g.

  • For for-and-aft decelerations in normal conditions, accepted values seem to be in a similar range of 0.10-0.15 g, with emergency brake levels of up to 0.3 g. Again, the standard car can brake at 0.6 g. (100 km/h require an actual braking distance of approx. 90 m - add to it, please, 60 m for perception and reaction).

  • The previous figures are in line with the usual standards used in the design of roads: acceleration levels of 0.10-0.15 g in a longitudinal direction are considered manageable, and decelerations of 0.15 g as comfortable, as felt by standing bus passengers.
  • Upsetting acceleration values are related to jerk (acceleration rate change). Standing passengers have difficulties in maintaining their balance when the jerk is higher than 0.06 g/s. Values of longitudinal jerk larger than 0.30 g/s would seldom be acceptable for most public transportation.

  • For transversal accelerations, values as low as 0.05 g are mentioned as threshold which cause losing balance in unsupported passengers.

Step 8: The Bus Line That I Have Evaluated

Attached are images of the bus line that I have selected. Main features:

  • Length: 8.6 km.
  • Difference in elevation: approx. 10 m (there is one tunnel under the railtracks, otherwise it's rather flat).
  • Circular, driven clockwise.
  • Main bends: the track has 10 main bends (see map for identification), most of which are clockwise, and sharp.
  • Number of stops: 28 (see map for identification).
  • (It has a stop in front of home...).
  • Average speed: approx. 12-14 km/h.

A chart is also included showing the bearing of the track, with labels to main geographical landmarks.

Linked files for consultation:

Step 9: Results!!!

Raw Data

Attached are some charts with the raw data (figs. 1, 2 & 3; Ax, Gz and Ay) - the spreadsheet is here.

Interpretation clues:

  • Units, in all cases:
    • X: time, in seconds.
    • Y: acceleration or angular velocity, in LSB.
  • The GY521 was placed with the axis +Z upwards, and the axis +X forward - because of this and the bus movement I have focused only on Ax and Gz (and checked Ay).
  • Ax>0 means acceleration, Gz>0 means turn to the left.
  • The time in the raw data records is in milliseconds. It can be converted into standard CET by adding 12:21:48 h:mm:ss (of the day 14.may.2015).
  • A log of the trip is attached here.

The raw data seem quite noisy and confusing: after all, are they really worthy? Is there any valuable, clear reading?

Mapping of the Raw Data to the Bus Track

Fig. 4 shows the position of the main curves of the route followed by the bus on the Gz raw data chart.The results match not only because they are visually appealing, but because the times recorded on the manual log of the trip closely correspond to those recorded by the accelerologger.

From time 180-480 seconds the bus was stopped, with the engine on, waiting to adjust the turn-around time (the same happened from 1430 to 1560 s). Fig. 5 shows the corresponding Gz records, whose average for that period is -230 LBS. Refer to the offset error for Gz in the Calibration step. Fig. 6 is the result after applying to the previous data a moving average of approx 0.2 seconds (6 consecutive records).

Figures 7 & 8 are zooms on bends A-B: the first one with the raw data and a cut-off level of +- 400 LBS, and the second after applying the moving average described above and the offset corrected. The rough integration of Gz along the period corresponding to the curve A yields a result of -10870 LBS, or 82.9º for the standard sensitivity of the gyroscope. The difference in geographical bearing for curve A is 83.2º, as per the quick calculations performed on the klm file (see also a chart in previus Step). This seems a quite reasonable comparison for a rather unsophisticated calculation.

The analysis of the Ax data also provides worthy data, although somehow tougher to analize. From 480 to 700 seconds the manual log reports:

  • 481: depart from stop P348
  • 539: arrival to stop P349
  • 548: depart from stop P349
  • 563: traffic light stop
  • 599: depart traffic stop
  • 632: traffic light stop
  • 645: depart traffic stop
  • 662: arrival to stop P351

Figures 9 & 10 show the corresponding records, the first one unfiltered, and the second as a moving average with the same parameters as for Gz above. Finally, figure 11 shows the detail from 520 to 570 seconds, where the effects of the automatic gear changes can be appreciated both in acceleration and deceleration.

The results are not as clear as for the Gz case, but still the elements of the trip can be identified.

Regarding Ay, fig. 12 shows the moving average for time 830-870 seconds, corresponding to curve A. The average velocity in this curve is estimated from the records as 2.4 m/s (8.6 km/h). The average angular velocity from the gyroscope readings is approx. 8.9 deg/s. The average radius of the curve is therefore 15.5 m (r=v/w). This is a reasonable figure for a relatively closed bend and a bus. The centrifugal acceleration is therefore 0.4 m/s2 (a = v²/r = w²*r), or 6127 LSB. This, however, is not precisely matching the readings of Ay, with peaks of 4000 LSB.

Finally, the records show accelerations (fore-and-aft as well as transversal) which are far exceeding the recommended values for a confortable trip: at curves, brakes for stops/traffic lights and also at shifting gears. This confirms my experience on a bus.

Next Stops?

  • Put a bit more of data filtering (especially on accelerations).
  • Cross check values of accelerations.
<p>I have been looking for a project like this for a while now. I might just give this a try.</p>

About This Instructable




Add instructable to: