Reading CAN-bus from energy storage, without losing your mind
Notes from the Voltfang internship: parsing CAN frames, decoding DBCs, automating conformity certificates.
Battery-test data lives in CAN-bus frames. Each frame is eight bytes of payload plus an arbitration ID, and the bytes mean nothing without a DBC file: a text-based description of which bits in which frame correspond to "Pack voltage", "Cell minimum voltage", "Temperature sensor 3", and so on. You cannot decode a battery without the DBC, and the DBC is usually proprietary, hand-edited, and slightly wrong.
The Voltfang internship started with a 90,000-row CSV of raw CAN frames and a 12-page DBC PDF the previous engineer had scanned. Step one: write a DBC parser. There are open-source ones (cantools is the canonical Python option), but the proprietary DBC was different enough that we wrote a small extension. Step two: cache the parse. DBC parsing is a hot path — every frame in the CSV needs to know what its bits mean, and re-parsing the DBC per frame puts you at three seconds per test. Cache it once, key by the signal name, and you are back at sub-second decoding for a full test run.
The deliverable was not the parser. The deliverable was an automated conformity-certificate generator that ate the decoded CSV and produced a PDF a battery technician could sign and ship with the product. The instinct of the previous engineer had been to render the certificate as LaTeX. I rewrote it in plain HTML/CSS with a print stylesheet, for one reason: the certificate template will be edited by somebody non-technical six months from now. LaTeX optimises for the engineer who writes it. HTML optimises for the office manager who will change the logo when the company rebrands. Pick the path of least resistance for the next person, not for yourself.
The second non-obvious lesson was about units. The DBC files use multiplicative scaling — a 16-bit unsigned value in a frame is "voltage × 0.01 + 0 V". One field had a scale factor of 0.0078125, a hex artefact from a 7-bit fractional representation. Round it to 0.008 in your code and you accumulate a 2.3% error over a 30-minute test. Use the exact value from the DBC. Always.
The project shipped, the certificates print clean, the office manager has edited the logo three times. The CAN parser still uses the original DBC parse cache. The lesson I took away was not about batteries. It was about respecting that the next engineer touching this code will not have the context I had. Cache wisely; document the unit conversions; choose the rendering technology your replacement can edit.