This is part 3 of series "Kona EV Conversion":
Oops, over six month since Part Two! I haven't abandoned either the blog or the EV project, although there have been no shortage of distractions. Slow but steady progress has been happening on two fronts: decoding Kona CAN messages, and building a "Bench Kona" in the shed.
This post is about decoding the CAN Messages.
First, get all the Logs
I've uploaded many log files, captured on various Kona EV CAN buses from two different vehicles (mostly PCAN - Powertrain CAN). For most of these logs I also have a video (not currently published online) showing the dash or other interactions as the log is being captured.
(This action shot is the dash animating a transition to Sport mode, not catching fire!)
The approach has been to capture logs in advance and analyse later, rather than doing interactive analysis on a running car. This is because all the Konas we are logging are wrecks that can't drive on public roads, and they are steadily being dismantled.
The goal is to figure out what the message contents represent - what signals are encoded in each CAN message payload. This is like identifying individual needles in a haystack packed full of needles...
The standard way to distribute information about the signals found in CAN messages is a file format called "DBC". The format originates from Vector Informatik, one of the key players in automative electronic communications.
Here's a tiny sample of a DBC file, showing a 4-bit field
REGEN_LEVEL inside the CAN message with ID 0x202. I've named this message
VCU_202 as it's sent by the Vehicle Control Unit:
BO_ 514 VCU_202: 8 XXX SG_ REGEN_LEVEL : 23|4@0+ (1,0) [0|1] "" XXX
... obvious, right?!? 🙃 A real DBC file will have hundreds if not thousands of these.
I don't know how old the DBC format is, but it has the hallmarks of late 1990s proprietary software: weird signifiers, human-unfriendly formatting choices (CAN IDs - represented in hexadecimal everywhere else on the planet - are encoded as decimal in DBC files), ALL CAPS DESIGNATORS, punctuation soup, two and three letter abbreviations to "save space".
There's such a thing as an over-engineered standard designed by committee, and there is also such a thing as an ad hoc in-house file format that accidentally became a standard. I know which category I'd put DBC into.
Perhaps one day there will be an open standard for CAN signal information that is less hostile to humans! In the meantime, the only productive way to work with DBC files is to use one of many software tools. We'll come back to this later in the post.
Step Two: Search!
It's always worth checking online to see what others have tried first. After many searches, I found quite a few folks who had analysed CAN messages from Hyundai/Kia EVs:
- Kona EV CAN Messages Google Spreadsheet, as linked to by Spfoamer on reddit /r/CarHacking. The same person also hacked their Kona VESS ("Vehicle Engine Sound System") to sound like a train, and published a VESS control script. Neat stuff!
- comma.ai maintains their opendbc project with reverse engineered CAN message data for dozens of cars. The hyundai_kia_generic.dbc file seems to cover a lot of messages used by the Kona EV.
- @uhi22 on openinverter has a repo with an Ioniq EV DBC file, centered around DC fast charging messages. It looks like the Ioniq shares a lot of CAN messages with the Kona.
- @powercontrol on openinverter has been using my logs to do some decoding into a Google spreadsheet. 🦾
- While writing this I saw @powercontrol linked to a very comprehensive decoding of Kia Soul EV messages. Haven't looked at this yet, unclear where it's from or who made it (maybe 2016?), or how much of it translates over to the Kona.
There are also a lot of projects posting diagnostic "PIDs" for use with CAN-based OBD2 diagnostic interfaces, and related diagnostic CAN IDs for the UDS protocol (i.e. here, and these). Very useful, but they're a different set of diagnostic CAN messages and IDs to the ones the car uses for normal operation (albeit they share the same transport bus).
Step Three: Analyse
That was a great start, but at some point I'd need to get my hands dirty. How to analyse the CAN logs?
I have the logs in what I've been calling the "GVRET CSV format". Maybe the correct name is "SavvyCAN Native CSV file format"? In any case, the format looks something like this:
Time Stamp,ID,Extended,Bus,LEN,D1,D2,D3,D4,D5,D6,D7,D8 1300856300,00000394,false,0,8,00,E0,00,00,FF,DB,B1,8E 1300856600,0000010C,false,0,8,04,00,55,54,15,40,01,02 1300860500,00000371,false,1,8,42,1E,00,00,00,00,00,10 1300860800,00000372,false,1,8,00,00,10,00,00,00,00,00 1300861000,00000436,false,1,4,00,00,00,08 1300862300,00000291,false,0,8,00,00,00,00,FF,FC,FC,24 1300862500,00000523,false,0,8,0C,38,4B,4C,49,4A,A5,00 1300862800,00000524,false,0,8,62,01,00,00,00,00,00,00 1300863400,00000354,false,0,8,AA,0A,55,05,00,01,00,20
(Time Stamp column is in microseconds. In my logs it's relative to the interface hardware's clock not any real timestamp.)
grep & cut
Being inclined towards the Linux command line, it's hard not to start with some command line tools. For example:
cut -d',' -f2 221228-4-2019-ac-charging.csv | sort | uniq -c | sort -n
You can get quite far with these kind of tools: look for patterns in particular messages, find out which message payloads repeat in different log files, etc. I'm sure if I learned awk then I could go even further with it!
However at some point you really want to visualise what's happening, and it's time to leave the terminal behind...
SavvyCAN is probably the best known open source CAN bus reverse engineering tool, and for good reason. The maintainer Collin Kidder is a prolific contributor to open source EV reverse engineering projects.
If you open a CAN log in SavvyCAN, you see a list of messages like this:
SavvyCAN is a real swiss army knife, it has a ton of features and built-in tools. For playback of pre-recorded CAN logs with unknown contents the most useful feature I've found is the Flow View:
The flow view lets you step through particular messages and watch the values that change.
Once you've identified some signals, SavvyCAN also has features to graph the signals and to display them inline in the log window.
As SavvyCAN is also designed for live CAN interaction, some features like the Sniffer window require you to open a Playback function and play back the log as a simulated real-time capture in SavvyCAN. Once you do this, you can see the message fields changing in the Sniffer as if it was happening live:
This works OK, although there are rough edges. For example, if you pause playback all the Sniffer values eventually fade out (as if a real CAN interface had stopped receiving those messages).
Overall, SavvyCAN is a very flexible CAN analysis tool. However, I couldn't find a comfortable workflow for replaying log files, figuring out new CAN signals, and adding them to a DBC file. It's all technically possible in SavvyCAN, but I didn't find it ergonomic. This might come down to my personal working style, or it might be because SavvyCAN is such a flexible tool: it caters to many different use cases and workflows.
I've already mentioned comma.ai, the open source driver assistance company. I don't know a lot about the company, and I'm not a fan of its founder, but I am very grateful to the team for maintaining an open source DBC repository (opendbc) and an open source CAN analysis tool called Cabana. These were both created to make it easier for folks to integrate new vehicles to the comma.ai driver assistance platform Openpilot, but as they're open source they can be used for other purposes too.
The original Cabana was a web application designed to download recorded "routes" from comma.ai's cloud service. A "route" consists of a detailed binary log containing CAN files and other driving metadata, along with a video stream.
Web Cabana has been deprecated, but before noticing this I applied some dirty hacks so it would load files from the local filesystem instead of the cloud. Together with a Python based "route converter" tool that takes pairs of CSV log files and video files as input, it was possible to access your own log files in "Cabana@Home":
Almost as soon as I had something half-working I realised "Web Cabana" was deprecated, and a New Cabana desktop application had been developed to replace it. The Cabana@Home hacks are online here in case they're useful to anyone, but "New Cabana" seems a lot better!
Like Web Cabana, the workflow of the new Cabana tool is centered around downloading "routes" from comma.ai directly. Unlike Web Cabana, there is already built-in support for locally stored routes. Woo!
Therefore, the only task was to update the existing Python "route converter" to produce "routes" that worked with the new Cabana. Easy, right?
Well, kind of easy. The old route converter was pretty clunky and slow, and implemented only the bare minimum of comma.ai's "route" file format. The new Cabana has more features, and therefore needed a more complicated converter tool.
For an extra detour, at some point I decided to "rewrite it in Rust"! This took longer than expected for various reasons, but I think it turned out pretty well. Moving from Python to Rust allowed me to process the video frames directly using rust-ffmpeg while also having the whole tool run significantly faster. I'm also pretty new to learning Rust, and it was a good opportunity to build something of moderate complexity.
The tool is make_cabana_route. It's able to process pairs of CSV log files and videos in order to produce output that loads into Cabana for easy analysis and DBC file creation:
One of the Cabana features I really like is that it's very quick to identify a region of bytes as a potential signal, create a line graph of that signal over time, and "zoom" in on the timeline to loop through a short period where the signal did something interesting.
Here's some graphs of signals shown in the previous screenshot:
In the next screenshot I've clicked and dragged a region on the graph where the
uwe524_EPCU_Voltage1 signal changes. Cabana has zoomed in and is looping playback over that one second period when the car is powering on and we see from the graph that the inverter is pre-charging:
While it's looping, it's easy to click around the other signals and look for interesting values that are also changing during this period.
The only real feature I'm missing is audio playback. Because the comma.ai hardware doesn't record audio there isn't any audio playback functionality in the New Cabana video widget. It might be possible to work around this, but for now it seems OK without it. Hearing yourself say something inane on a two second loop has its downsides, as well!
I find this to be a pretty smooth workflow. It took a lot of work to get it up and running, but I think it's going to be worth it.
If you have your own CAN logs (with or without videos) then please head over to make_cabana_route and check it out. If you're keen to access the videos that go with my Kona CAN logs then feel free to drop me a line, maybe I can find a cost-efficient way to put them on the internet.
During development of
make_cabana_route I noticed some weird behaviour: my logs kept stuttering on and off - the Cabana message window would freeze and unfreeze, seemingly at random. I originally thought this was an issue in Cabana, or perhaps my converted "routes" were somehow invalid and overloading the UI. Eventually I realised the pauses were deterministic and seemed to correlate with periods in the logs.
Graphing some CAN log "messages per second" rates over time with pandas showed a troubling pattern:
Most (but not all) of my CAN logs are full of dropped messages! Somehow, a few minutes into many of the log captures there are constant intermittent 1-2 second pauses where no messages were logged!
I don't know exactly how this happened. I've been capturing with a cheap and cheerful "Canalyst-II" USB to CAN adapter (not recommended), python-can, and the canalystii driver that I developed to replace the binary library it shipped with. It could be a bug in the driver, it could be a bug in the Canalyst-II firmware, or it could have been a limitation of my old laptop failing to keep up (I was tee-ing the log into a terminal window that probably had unlimited scrollback, so it's possible the whole thing got overloaded and I didn't notice - oops!)
I haven't managed to reproduce the message loss with bench tests, but a modern car is a much more intense CAN environment than anything I can assemble on the bench. I think I'll need to plug the Canalyst-II back into a real Kona to try and reproduce.
With some luck, CANtact Pro will come back into stock. It no doubt also has downsides, but I'd much rather be working with a CAN interface where I can read the firmware source!
It's only in the last few weeks that I've stopped working on
make_cabana_route and started using Cabana to process Kona logs. It's coming along pretty well so far, although the vast majority of signals came from the work of others. You can see the progress thus far on GitHub in the dbc directory.
The next goal is to use this information to convince my "bench Kona" components that they are still in a real car, enough that the motor can spin. More on that soon, I hope...
Thanks @uhi22 for already identifying that particular signal! ↩