TomiXRM / utterances-tomixrm

the blog comments
0 stars 0 forks source link

ESP32でCAN通信(データ衝突の回避) #3

Open utterances-bot opened 1 year ago

utterances-bot commented 1 year ago

ESP32でCAN通信(データ衝突の回避)

CAN通信でのデータ衝突の回避を頑張ってやってみたので備忘録がてらまとめてみました。

https://tomixrm.vercel.app/esp32can-b15119dea8b940c9ac349f9ce469ef0b

ajinori3 commented 1 year ago

素晴らしい記事を公開してくださりありがとうございます。 素人の私見で、不完全な点も多々あり恐縮ですが、いくつかコメントさせていただきたく存じます。

衝突の回避について

衝突の回避方法はCANプロトコル側でCSMA/CR方式を使うと規定されています(参考:CAN入門書p10)。
したがって既製品(例えばTomixさんの例ではESP32に内蔵されているCANドライバ)を利用する限り、衝突回避・再送などはCANドライバがよしなに対処してくれるため、あまり気にする必要はないかと思います。
ただ、自分も非常に気になる事項ではあったので少し調べてみました。

余談 ※最近はCSMA/CR方式だ、とする意見があるようです(参考: [CAN入門書 p.5](https://japan.renesasrulz.com/cfs-file/__key/communityserver-discussions-components-files/83/RJJ05B0937_2D00_0100.pdf))。 これは、CSMA/CA方式の特徴である、乱数時間(=バックオフ時間)経過後にデータを送信する機能を持たない点が理由として挙げられるのかな、と考えていますが、 文献によって表現もまちまちのようで自信ありません・・・(参考: [株式会社サニー技研 CAN(Controller Area Network)とは](https://sunnygiken.jp/product/can-tool/aboutcan/)

衝突回避方法

Tomixさんが挙げられている単語を使いつつ、ざっくりまとめると以下のようなイメージになるかと思います。

  1. CANはすべてのデバイスが常時バスを監視しており、すでにバスが使用中の場合はメッセージ送信を控えます。(=CSMA/CR のうち CSMAの部分の考え方)(参考: はじめてのCAN/CAN FD p.9)
    会話するとき他の人が話し終わるまで待っている、みたいなイメージです。

  2. ただし 1. の仕組みだけでは、複数のデバイスがほぼ同時にメッセージ送信を始めた場合対処できず、衝突(=コリジョン)が発生します。
    複数の人が同時に「「そういえばさぁ」」って話し出して気まずくなる、みたいなイメージです。

  3. 2.が発生した際、CANでは各メッセージのCAN IDが最も小さいデバイスが送信権を維持、それ以外のデバイスは送信を停止します。(CSMA/CRのうちCRの部分の考え方) (=アービトレーション)
    つまりCAN ID = メッセージの優先度(=プライオリティ) です。

  4. 残念ながら3. で送信権を維持出来なかった(=プライオリティが低い)メッセージは、バスが空き次第再送を試みます。

CAN IDの使い方について

前述のように、CAN IDはメッセージの優先度を意味します。
そのため、1つのデバイスで複数のCAN IDを使ってメッセージの送受信を行う、といった使い方が可能です。(参考: CAN(2.0A, 2.0B)/UAVCAN Servo Control Protocol Manual)

例えば、多少遅れてもいい、インジケータの点灯/消灯メッセージはCAN ID=100に、 優先度の高い、モータの回転速度指示メッセージはCAN ID=5にする、などなど...

もちろん、I2Cのように各デバイスにIDを割り振る使い方もできます。 (参考: RoboMaster GM6020ブラシレス直流モータ)

CANの使い方について

バスの帯域を圧迫しないため、あるいはバスの占有率を一定に保つために、リモートフレームは使わず、データフレームのみを使う場合が多いようです。 (参考: CAN通信におけるデータ送信の仕組みとは? - MONOist)

例えば、センサはバス上に一定間隔でデータを吐き出し続け、他のデバイスは必要に応じてその情報を取り、不要なら単に無視するという運用が多いとのことです。

マルチマスタについて

マルチマスタ = どのデバイスも送信側になれる、と読み替えてみるのはいかがでしょうか。

I2Cなどのマスタ-スレーブの関係がある1:Nの通信プロトコルでは、 基本的にマスタ側がスレーブ側にリクエストを送信→それに応じてスレーブ側が動作/レスポンス、という動作の流れになっていました。

CAN通信では、どのデバイスからでも送信側になれる点がI2Cなどと異なります。

例えば、前述した「センサはバス上に一定間隔でデータを吐き出し続け」る、という機能をI2Cで実現しようとすると、センサ側をマスタにしないと成立しません。 ただ、これではメインのマイコン側からセンサに通信を仕掛けることができないため、例えばロボットの起動時にセンサのキャリブレーションをする、などの動作の実装が少し難しくなりそうです(当然工夫次第でどうにでもなる問題ではありますが)。

最後に

長文駄文失礼いたしました。自分も勉強中のため、至らぬ点もあったかと思いますが、 なにかの参考になれば幸いです。