Friday 10 May 2019

On-board Data Logging

Since last year, I have wanted to implement an on-board data logging system for the bike for a number of reasons.

  1. On-board logging would mean all trips could be data logged automatically without needing to consciously connect to the ECU and start logging.
  2. Logging the engine data as broadcast via CAN-Bus would enable logging at a higher frequency than is available through the RS232 connection. 50Hz vs c.15Hz
  3. The CAN-Bus data broadcast from the ECU also gives access to far more data channels than are available to log via RS232 which includes many very useful diagnostics channels and calculated channels which I feel really should be included in the RS232 data stream such as injector deadtime.
  4. Having data log capabilities external to the ECU opens up the flexibility to add more data inputs either via CAN-Bus or analogue inputs. These could be additional engine sensors that are not currently required by the ECU to run the engine (oil pressure, oil temperature, EGT) or else they could also include chassis data such as brake pressure, GPS & IMU data, wheel speed, etc.

I found that most units on the market that would log CAN-Bus data were just too expensive for my needs so decided to use the opportunity to build on my existing skills and build my own.
I decided to use the Teensy 3.2 development board as the heart of the logger mainly due to the on-chip CAN-Bus interface but also because of its small package size and ease of programming via Arduino IDE.

The circuit layout and PCB design for the Teensy including the peripherals needed was relatively straight-forward. I was familiar with the CAN-Bus interface on the Teensy from other projects and, as a MicroSD socket and coin cell holder were the only other major components required, the physical aspect of the logger did not take long to complete.

Modelled Assembly

PCB Layout

PCB Board

Assembled Board

While the physical aspect was completed quite quickly, the software side of things took a bit of time to get to a state that worked well enough. While I was familiar with the CAN-Bus reading aspect, I had not had any experience with logging data to an SD Card so I went through a few iterations of code before settling on an approach that worked.
As I do not come from a software/coding background, any of my microcontroller projects always start with existing code that does something similar to or a particular aspect of what I want and then modify it to my needs.

The software workflow is relatively simple. On power-up, the microcontroller would read the date & time from the RTC and create a new data file on the SD card using the RTC timestamp in it's filename. This ensures unique filenames are used and makes the data easier to manage later.
Once the file is created, the controller reads any data contained in the CAN-Bus recieve buffer and adds it to the appropriate position in a data struct. At defined intervals corresponding to the desired logging frequency, the data contained in the struct is written to the SD card. In between writing the data to the SD card, the controller cycles through reading the CAN-Bus buffer and passing the recieved data to the struct as quickly as possible.
The cycle of data read & write is continued until power is removed from the module (i.e. ignition off). This does mean that there is the potential to lose some data not written to the card on power down but the period spanned by the lost data is unlikely to be more than 2-3 log intervals and is deemed acceptable for the purposes of the project.

Software Main Loop Basic Workflow

Writing data to the SD card was very straightforward as long as the number of parameters and logging frequency was kept low but problems started cropping up when more parameters were added to the datastream and the rate was pushed higher than c.10Hz.

I began by wanting to log data to a human readable .csv file on the SD card purely for convenience. However, with the number of data channels I wanted to log I ran into issues with SD card write latency at write speeds above c.10Hz which was causing me to lose a number of data points every now and then while the program waited for the SD card to finish writing. I could help the issue by adding data to a single long data string and then writing that to the SD in one go. However, the data string took up too much memory with the number of channels I was trying to log so it was not really a viable option. This also didn't completely eliminate the issue.

In the end, after experimenting with minor changes to the same basic method, I opted to write the data to the SD card in binary format and then post process the data after it had been downloaded from the SD card to create human readable .csv files with headers.
By writing the data in binary format, I was able to use a C struct to contain the data variables which was much easier to update within the software and also very easy to simply write the entire struct to the log file whenever it was needed. It also seems to have made the SD write latency issues disappear. I have not yet verified data frequency consistency over a long period of time and at higher logging rates at the time of writing but I have verified writing over 60 data channels to the card at 20Hz for several minutes without any loss of data. While logging directly to .csv file, I was getting data inconsistencies even with only 10off data channels and 10Hz logging rate.

The post processing script was written in GNU Octave which is an open source alternative to Matlab. The script is written in a way that it reads information about the C struct (variable names, units and precision) from a text configuration file so that it knows how to interpret the binary data. The script then reads the raw binary file, arranges the data into a matrix which matches the configuration file input and writes the processed data matrix to a .csv file along with header lines that define the channel names & units. The necessity to have a configuration file which matches the logger C struct means that I need to be particularly meticulous when it comes to documenting changes to the logger software and I need to have good version control.

Version 1.0 of the logger software & post processing script leaves some room for improvement but I am happy that I have an easy to use and reliable datalogger that I can fit to the bike and use while I work on further improvements.

Some improvements which I have in mind are:
  1. Remove the CAN message processing from the Teensy software and log raw message values. The post processing script will be capable of doing the data conversion as well as the binary to decimal conversion. Removing the processing from the logger just means that I can free up some processing power & main loop time to help increase reliability at higher data rates. Logging single bytes also will have the advantage of reducing the size of the struct as it currently pads variables out to the largest precision value (32-bit float). If all variables to be logged are full CAN message data sizes (64-bit) there will be no need for any additional padding.
  2. Add one or more data buffers to the logger software. This should help logging reliability and increase the potential logging rate by not requiring the SD card to be ready for writing on each data write loop. 

I 3D printed an enclosure for the board in ABS plastic. The case is not fully sealed as I have left a slot in the side to allow me to remove & insert the SD card without opening the case.

To complete the logger connection to the bike, I made up a short adapter harness which is sleeved & booted at the connector end. The adapter harness is then cable tied to the PCB board via 2off small slots which I had cut in the board for this very purpose. This just serves to provide some strain relief for the header pins & socket. I also printed a wire seal from TPU as an experiment to help seal the area where the harness exits the case. I also added a label to the harness to identify the module. Because.... well... it looks nice.

Bike interface connector

Adapter harness in position

Case with cable seal

Monday 6 May 2019

Making an Exhaust Silencer

It has been quite a while since I updated this! Apologies. I need to be more diligent in posting updates.

During my last track day of 2017, the exhaust silencer on the TSR system suffered a mild failure where the perforated tube broke off from the main body and dropped down into the link pipe.

I treated this failure as a perfect opportunity to get a new silencer for the bike. I had thought that the silencer that came with the TSR system looked tired and was also too long to suit the look of the bike.

Naturally, option #1 was to purchase a ready made exhaust silencer from an aftermarket supplier and do a straight swap. Unfortunately, I found that the entry diameter for the TSR silencer is not very common (45mm) and while it was possible to purchase a direct fit silencer from one or two aftermarket manufacturers, all the exhaust designs were either far too short or had far too large an exit diameter to suit my taste. I did not want the silencer to look like a race style or a stubby.

Option #2 was to request one of the UK-based exhaust manufacturers to make a silencer with a bespoke entry design to suit the TSR link pipe. This seemed like a good route to begin with but as the design progressed, it became clear that the entry pipe design would be compromised by an external diameter change to allow the manufacturer's standard tooling to fit. The silencer would have had a swaged neck in the entry pipe which I felt would have looked unsightly on the finished product.

Option #3 was to attempt to repair the original silencer myself. I found a local supplier from whom I could purchase carbon tube in the correct diameter (also not standard) as well as the perforated tube and packing material for reasonable cost so the decision was made to have a go at doing it myself.

The optimum aesthetic length of the silencer was chosen by applying some basic photoshop "skills" to a photo of the bike and I decided to reduce the silencer length from 450mm to 350mm. This made the silencer look much more in proportion to the rest of the bike in my opinion but without making it look like a short stubby silencer.


When the old TSR silencer was dismantled, a few items stuck out as needing to be changed.

  1. The rivet holes in the old end caps had been damaged so most were oversize. To provide a better surface for the rivets to hold on to, a new strip of stainless steel would be added inside the end caps
  2. The old perforated tube was smaller than the silencer entry diameter and was only tack welded to the end cap in 2 places. It was also not supported at the exit end of the silencer which allowed it to vibrate and eventually break the tack welds and fall down into the link pipe. I sized the replacement perforated tube to be nicely supported on the exit end. As this still left the diameter of the perforated tube smaller than the entry diameter, I flared the end of the perforated tube to match and welded it fully around its circumference.
  3. The sleeve of the TSR silencer had been riveted directly to the end caps. I wanted to add rivet straps at each end both to provide a barrier between the rivets and the carbon sleeve and to provide a decorative finish to the silencer.

First the silencer assembly was modelled in 3D to ensure all parts fit as intended.

Modelling the exhaust assembly allowed me to get the rivet straps just right. The profile was laser cut from stainless steel sheet and bent into shape.

The perforated tube was flared and welded to the entry cap.

 The silencer was first dry assembled using clecos and test fitted to the bike.

Then the parts were riveted together.

And the packing material added.

Overall, the repaired silencer looks much better in my opinion and makes for a cleaner look than the old TSR silencer. The sound from the exhaust is not significantly different from before so that is a plus. There are a few things I would improve on or do differently if I was to do the job again but I am happy with the end result.