CAN通信で用いられるDBCフォーマットについて
はじめに
こんにちは!KGモーターズ株式会社でエンジニアをしている中村です。
KGモーターズは、広島を拠点に1人乗り小型 EV mibot を開発しているスタートアップです。
いよいよ量産が迫ってきております。量産の内装、完成度高いです!👇
今回は私自身のドメインとは少し異なり、CAN通信関連のお話しです。
車載開発や計測器との通信で使われる CAN通信ですが、
その中で「信号がどのビットに詰められているのか」「どんな意味を持つのか」を定義するのが DBCファイル(CAN Database File) です。
このファイルがあることで、バイナリのCANフレームを「人間が読める変数・物理値」に変換できるようになります。
この記事では、DBCの基本構造と利点、フォーマット仕様の概要を整理します。
DBCファイルとは
DBCファイル は、CANメッセージとその中に含まれる各信号(Signal)の定義を記述したテキスト形式のデータベースファイルです。
(テキストファイルなのかよ、と突っ込んでしまいそうになりました)
簡単に言えば、CAN通信の辞書みたいなもので
「CAN ID 0x123 の 5bit目から16bit分が車速で、スケールは0.01 km/h単位」などのルールを決められたルールで記述していきます。
たとえば、あるメッセージが次のように定義されていたとします。
BO_ 123 VehicleStatus: 8 ECU_Main
SG_ Speed : 0|16@1+ (0.01,0) [0|250] "km/h" Display
SG_ BatteryVoltage : 16|16@1+ (0.1,0) [0|600] "V" Display
この例からわかることは...
- CAN ID 123 のメッセージ(VehicleStatus)には 2 つのシグナルがある
- Speed は 0bit から 16bit(リトルエンディアン)
- BatteryVoltage は 16bit から始まる
- etc...
ツールやコードジェネレータは、この定義を元に「CAN生データ ⇄ 意味のある値」の変換を行っていきます。
DBCファイルを使うと何がいいのか?
1. CANデータの意味を共有できる
これは前述の話で、DBCファイルのルールを使って共有の理解をすることができます
2. コード生成・自動解析が容易
BO_ や SG_ の定義を元に、自動的にシグナル変換コードを生成したり、Python でデコードしたりできます。
以下はAIに作ってもらったので、バイナリがあってるかわかりませんが...
import cantools
db = cantools.database.load_file('vehicle.dbc')
msg = db.decode_message('VehicleStatus', b'\x10\x27\xA0\x0F\x00\x00\x00\x00')
print(msg)
# {'Speed': 100.0, 'BatteryVoltage': 40.0}
このように、バイナリだけだと全くわからないものが、DBCファイルを通すと人が読める形で扱えるというのが利点です。
3. CAN通信仕様のバージョン管理ができる
DBCはテキストファイルなので、Gitでの差分管理も容易です。
「どのビットがどんな意味に変わったか」が履歴で追えるのもエンジニアにとっては嬉しい話です。
DBCフォーマット
では本題です。
DBCファイルはテキスト構造で、主に次のような構成を持っています。
VERSION ""
NS_ :
BS_:
BU_: ECU_Main Display
BO_ 123 VehicleStatus: 8 ECU_Main
SG_ Speed : 0|16@1+ (0.01,0) [0|250] "km/h" Display
SG_ BatteryVoltage : 16|16@1+ (0.1,0) [0|600] "V" Display
VAL_ 123 Speed 0 "STOP" 1 "RUN";
CM_ BO_ 123 "Vehicle status message";
主な構成要素のサマリー
| 要素 | 意味 | 備考 |
|---|---|---|
| VERSION | DBCファイルのバージョン情報 | 省略可 |
| NS_ | シンボルの宣言 | 内部シンボルリスト |
| BS_ | ビットタイミング(形式上必須) | 内容は多くの場合空 |
| BU_ | ノード定義(送信元・受信先) | ECUやDisplayなど |
| BO_ | メッセージ定義(CAN IDごと) | メッセージサイズや送信ノード |
| SG_ | シグナル定義(1つの値の構造) | 開始ビット、サイズ、符号、スケールなど |
| VAL_ | 値と文字列の対応表 | 例: 0="Off", 1="On" |
| CM_ | コメント(説明文) | 開発ドキュメント用途にも便利 |
VERSION
- バージョン情報
- CIで自動埋め込みにしておくと、リリース紐付けが楽。
例
VERSION "Vehicle DB v1.3.2 (2025-11-01)"
NS_ (new symbols)
- DBC内で使用するシンボル群の宣言
- 多くの場合、定型の羅列で問題なく、中身を編集することはあまりない
例
NS_ :
CM_
BA_DEF_
BA_
VAL_
SIG_VALTYPE_
BO_TX_BU_
VAL_TABLE_
SIG_GROUP_
;
BS_ (bit timing)
- ビットタイミング
- 何も書かないのが一般的らしく、消すとエラーになることがある(らしい)
例
BS_:
BU_(nodes)
- ネットワーク上のノード(ECUやツール)を列挙する
- 送信者/受信者として参照されるため、先にここへ全ノードを登録
BU_: NODE1 NODE2 NODE3
BO_(message)
- CANメッセージの定義。続けて
SG_で中のシグナルを定義 -
message_idはDBC内で一意である必要がある - また
message_sizeはバイト単位(最大8:Classical CAN、CAN FDはツール依存)
例
BO_ 288 VehicleStatus: 8 ECU_Main
SG_(signal)
- 値(信号)の位置・型・スケーリングを定義
- 開始ビット定義はエンディアンで解釈が異なる
-
byte_orderが0ならBig Endian, 1ならLittle Endian
-
- 浮動小数そのものを送りたいときは後述の
SIG_VALTYPE_を併用。 - 受信者(receiver)はノード名を指定
-
@byte_orderは0: Big (Motorola),1: Little (Intel) - 物理値は
raw * factor + offset
例
BO_ 288 VehicleStatus: 8 ECU_Main
SG_ Speed : 0|16@1+ (0.01,0) [0|300] "km/h" Display
SG_ BattVoltage : 16|16@1+ (0.1,0) [0|600] "V" Display
ここはテンプレート化すると以下のようになります。
{}に値が入ります。
SG_ {signal_name} : {start_bit}|{size}@{byte_order}{value_type} ({factor}, {offset}) [{min}|{max}] {unit} {receiver}
VAL_(値→文字列の変換テーブル)
- Signalや環境変数の状態名を定義
- GUIやログで人間が読みやすくなる
例
VAL_ 288 GearPos 0 "P" 1 "R" 2 "N" 3 "D" ;
VAL_ Move_Stop 1 "On" 0 "Off" ;
CM_(コメント)
- DBC内オブジェクトに説明文を付与
- 仕様の背景/注意点をここに残すと設計レビューが楽になる(かも)
例
CM_ "Vehicle project DB for 2026 SOP";
CM_ BO_ 288 "Vehicle status message (main loop @10ms)";
CM_ SG_ 288 Speed "Wheel-based speed (filtered)";
BA_(属性の付与)
- 個々のオブジェクトに属性値を割当(初期値など)
例
BA_ "CycleMs" BO_ 288 10 ;
BA_ "SafetyLevel" SG_ 288 Speed "ASIL-B" ;
BA_ "Owner" BO_ 288 "Taro.Yamada" ;
最後に
と自分の記録に近い内容となりましたが、KGモーターズでは現在も一緒に働くエンジニアを募集しています!
特に車の制御や組み込みに興味のある方を強く募集しています!
興味がありましたらお気軽にご連絡ください!
Discussion
とても勉強になりました。いい記事をありがとうございます。
私の経験としては、DBCファイルはVector Infomatik社のツール「CANdb++」で見るのがメインでした。差分確認したいときにテキストエディタやWinMergeで見ることはあれど、各要素の数値の意味を正確には理解していませんでした。なのでこのまとめで「こう読めばいいのか!」「分解能はここで決めてたんだ!」と新しい気付きが得られました。Vector社のライセンスがなくてもDBCファイルの構造さえわかれば、その意味を視覚的に理解できるような内製ツールが作れそうですね。
コメントありがとうございます!
ソフトウェア開発チームではこの辺りは完全に内製になっていて(改めてDevOps環境を記事にしたいと思ってはいるのですが...)、
CAN定義をJsonやYamlで書きつつGitで管理し、CIでDBCファイルを生成、結合テストを回すなどの仕組みを入れて人手をなるべく排除しています。
そのためvectorライセンスは特になしでDBCを使ったり変えたりする必要があるためフォーマットの理解が重要になっております...笑
また疎通の確認も製品は使わず自分たちでテストコードの中にCAN送受信のプログラムを書いてなるべく自動化できるように開発してきます!