|TNKS1407 解説
← 解説一覧へ

CAN と CANopen ── 衝突しない、優先度つきのバス

2026.06.29

RS-485 は親分が1台ずつ聞いて回った。CAN はそこを飛び越える ── 誰でも喋れる多マスタなのに、複数が同時に話し出しても衝突せず、優先度の高いメッセージが自動で勝つ。鍵は『0 が 1 に勝つ』という一つのルール(非破壊アービトレーション)。車の中で鍛えられたこの仕組みと、その上の辞書 CANopen(EtherCAT の CoE の元)を開けてみる。

▶ CAN アービトレーションのラボを全画面で開く

RS-485 と Modbus では、親分(master)が子を1台ずつ順番に聞いて回った(ポーリング)。堅実だけど、台数が増えると遅いし、親分が一人居ないと回らない。今日の CAN は、そこを飛び越える ── 誰でも好きに喋れる(多マスタ)。なのに、複数が同時に話し出しても衝突しない。 しかも、優先度の高いメッセージが自動的に勝つ。

これ、よく考えると魔法みたいだ。共有バスで二人が同時に喋れば、普通は混信して両方ダメになる(だから RS-485 は親分が交通整理した)。CAN は、その「同時に喋る」を、壊さずに勝者を決める仕組みでまるごと解いてしまう。車の中 ── エンジンもブレーキもエアコンも、一本のバスで待ったなしに通信する世界 ── で鍛えられた知恵だ。

1. 衝突しないバス ── アービトレーション

種明かしは、たった一つのルールから始まる。CAN のバスは、「0 が 1 に勝つ」

CAN のビットには強弱がある。dominant(0)は強くて押し通す。recessive(1)は弱くて引っ込む。 バスは、誰か一人でも 0 を出せば 0 になる(残り全員が 1 でも)── 論理積(AND)みたいな線だ。この非対称が、すべての鍵になる。

各ノードは、自分のメッセージの先頭に ID を付けて送る。そして送りながら、同時にバスを読んでいる。ここで、こう振る舞う:

自分は recessive(1)を出したのに、バスが dominant(0)になっていたら ── 「より強い(ID の小さい)相手が居る」と悟って、その場で身を引く(送信をやめ、受信に回る)。

すると何が起きるか。複数のノードが同時に ID を送り始めても、ビットを上位から1つずつ比べていくうちに、ID の小さい(=0 が多い=優先度の高い)ノードだけが残り、最後の1台が勝つ。負けたノードのメッセージは壊れない ── ただ送るのをやめて、勝者の番が終わるのを待つだけ。だからこれを 非破壊アービトレーション(衝突を壊さずに捌く調停)と呼ぶ。下の widget で、3台が同時に喋り出して、ID の小さい1台が勝ち残るまでを、1ビットずつ追ってみてほしい。

can-arbitration全画面で開く ↗

物理は RS-485 と同じ 差動2本(CAN High / CAN Low)。前回の「差で送るとノイズが消える」が、ここでもそのまま効いている。CAN が足したのは、その2本のバスに「0 が 1 に勝つ」という強弱を持たせて、ぶつからない交通ルールにしたことだ。

もう少しだけ、その「0 が 1 に勝つ」を電気で覗いておこう。recessive(1)は、全員が手を離した状態だ ── 誰もバスを駆動せず、CAN_H と CAN_L は同じくらいの電圧(約 2.5V)に落ち着く=差がない=1。いっぽう dominant(0)は、誰かが能動的に駆動した状態 ── トランシーバが CAN_H を上へ、CAN_L を下へ引き離す(差が約 2V)=0。ここがミソで、「駆動する(0)」は「手を離す(1)」を必ず上書きできる。一人でも駆動すれば、ほかが手を離していてもバスは 0 になる ── これが電気的な「0 が 1 に勝つ」の正体で、まさに論理積(AND)だ。だから優先権争いも、信号どうしがぶつかって壊れるんじゃなく、強い方(駆動した方)が、弱い方を静かに上書きするだけ。混信ではなく、重ね書き。下の widget の「触ってみる」のステップで、その「誰か一人でも 0 を出すとバスが引き倒される」を、自分でノードをクリックして確かめられる。

もう一つ、細かいけれど効いている工夫 ── ビットスタッフィング。同じビットが5つ続いたら、送信側は逆のビットを1個ねじ込む(受信側は抜いて元に戻す)。なぜ? ── ねらいは、この後の Ethernet で出てくる 4B5B と同じだ。CAN も受信側が信号のエッジで時計を合わせ続けているので、同じ値が延々と続いて変化が無くなると、時計が少しずつずれていく。だから人工的にエッジを混ぜて、同期を保つ。違う通信でも、「受信の時計を、変化で合わせ続ける」という悩みと、その工夫は、何度でも顔を出す。

2. 宛先でなく、ID ── メッセージ指向

もう一つ、CAN は相手の選び方が独特だ。Modbus は「アドレス○番に聞く」だったけれど、CAN は 宛先を書かない。メッセージに ID を付けてバスに流すと、全員に届く(ブロードキャスト)。各ノードは、自分の欲しい ID だけを フィルタで拾う。

そして ── さっきのアービトレーションで分かったとおり、その ID が、そのまま優先度になっている。ID は「これは何のメッセージか(内容)」と「どれだけ急ぐか(優先度)」を、一つで兼ねているわけだ。下の widget(python-can)で、送り方・拾い方を1行ずつ。

この「宛先を指定しない」が、多マスタと相性がいい。送り手は誰が聞いているか知らなくていいし、受け手は何台居ても勝手に取捨選択できる。新しいセンサを1個バスに足しても、配線は2本に割り込ませるだけ、既存のノードのコードは何も変えなくていい ── 車のように、後から機能が増え続ける世界に、よく合っている。

# 速い周期データは ID を小さく(優先度高)、ログ等は大きく
brake = can.Message(arbitration_id=0x080, data=[...])  # 急ぐ=強い
temp  = can.Message(arbitration_id=0x300, data=[...])  # 急がない=弱い
# 同時に出ても、brake(0x080) が temp(0x300) に必ず勝つ ── 設計でID順に意味を込める
ID の付け方が、そのまま優先度設計になる。「急ぐものほど小さいID」を割り当てるのが定石。

3. CANopen ── ID に、意味の辞書を与える

CAN そのものは「ID 付きのメッセージが、ぶつからずに流れる」までしか決めていない。じゃあ「ID 0x180 は何を意味するの?」「モータの目標速度は、どのメッセージのどのバイト?」── そういう 意味の取り決めは、上に一枚、層を重ねて決める。その代表が CANopen だ。

CANopen の背骨は オブジェクト辞書(object dictionary)。機器の中のあらゆるパラメータ(目標位置、制御ワード、温度…)に、インデックス:サブインデックス(例 0x6040:0 =制御ワード)という住所を振る。そして、

この「速い実データ(PDO)」と「設定(SDO)」を分ける発想 ── どこかで見たと思わないだろうか。そう、EtherCAT でやった「毎周期のプロセスデータ」と「別腹のメールボックス設定」、あれの素性がこれだ。EtherCAT の CoE(CANopen over EtherCAT) は、文字どおり CANopen の辞書の仕組みを、EtherCAT の上でそのまま使うもの。制御ワード 0x6040 が EtherCAT のサーボでも出てきたのは、偶然じゃなかった ── 産業界が CAN で育てた「辞書」を、新しい速い線の上に持ち込んだんだ。

4. どこに居るのか ── 賢いバスの、ひとつの頂点

CAN は、共有バスの系譜(RS-485 と同じ「2本を皆で使う」)の中で、いちばん賢くまとまった一つだと思う。差動で頑丈、多マスタで柔軟、非破壊アービトレーションで衝突しらず、メッセージ指向で増設に強い。車載で広く使われ、産業でも CANopen として根を張った。

ただし、共有バスである以上、根っこの速度(古典 CAN で 1Mbps 程度、CAN FD でも数 Mbps)と、一度に1メッセージ、という枠からは出られない。「もっと速く・もっと太く」を求めると、バスを共有するのをやめて、Ethernet の物理に載せ替えるという、次の大きな段が来る。

そこで次回からは、いよいよ Ethernet に入る。まず Ethernet そのもの(線・MAC・スイッチ・あの MLT-3 の波形)を開けて、その上に TCP/IP を積み、最後に EtherCAT のような産業 Ethernet へ ── 通信の梯子を、ここから一気に上りはじめよう。共有バスで握った「アドレス/ID で選ぶ」「優先度」「実データと設定を分ける」は、上の階でも、ぜんぶ顔を出す。