2
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Z900RSのCANデータをAWS IoT FleetWiseで収集する

Posted at

バイクも電子制御が高度化しており、しばらく前からバイクにも診断用にOBD2のコネクタが装備されている車種が増えてきています。(新型は2020年12月から、継続生産車は2022年4月から義務化らしい)

そんなわけで、先日乗り換えたZ900RSにも搭載されており、これを試してみたいなと思いました。

注意:この記事で紹介している内容は、メーカーが保証している作業ではありません。場合によっては故障の原因となります。参考にする場合はすべて自己責任で作業してください。

シートを外すと赤いカプラーがフレームに固定されています。
IMG_8747.jpg

車のOBD2コネクタとは形状が違い、6ピンのカプラーということもあり、汎用的なOBD2ケーブルは直接繋げられないので、キタコが出している変換コネクタを使います。(ホンダ車用と書かれてますが、Z900RSはこのタイプでした)

OBDのデータを読み出すなら、Pythonなどのライブラリもあるので、簡単に試せるのですが、せっかくなのでコネクテッドバイクとしての構成も考え、AWS IoT FleetWiseを使ってデータの収集をしてみたいと思います。

AWS IoT FleetWiseを実行するデバイスはLinuxベースである必要があるため、家に転がってたRaspberry Pi 3を使うことにしました。OBD2のコネクタからCAN Busに接続できるので、Raspberry Pi用のCAN BUS Hatを使い、OBD2のコネクタに繋いで接続します。

ネットワークも必要なので、これまた家に転がっていたSoracomのSIMとドングルを使って直接通信できるようにしました。
今回使ったのは3G向けのSIMですが、今後停波が予定されているので、この辺のデバイスも新しく揃えないと。。。

最終的にこんな感じのデバイスとなりました。

IMG_9016.jpg

電源はOBD2コネクター経由でも取れるのですが、12vであるため降圧する必要があり、めんどくさかったのでモバイルバッテリーを繋いで試しました。

実際に走行してみて収集できたデータデータをGrafanaで可視化してみるとこのようなグラフが見られました。

grafana.png

取れるかなと思ったシグナルの内、エンジン回転数、速度、水温、スロットルポジションだけが取れてました。OBDのシグナルのIDは、各社独自の値を使ってたりするので、AWS IoT FleetWiseが用意している標準の設定だと合わないことがあります。メーカーから公開されていれば、その情報をAWS IoT FleetWIseに登録すれば、正しく取れるようになるはず。

実走で発生した通信量はSoracomのコンソールから確認するとこんな感じ。

soracom.png

17時〜19時の間はかなり下りの通信が発生していますが、これはリモートからSSHしたくてAWS IoT GreengrassのSecure TunnelingのデプロイとかをSIM通信を有効にした後、実行してしまったから。

AWS IoT FleetWiseの通信部分は、19時の時間だけ見ると、上りで 594 KiB、下りで 129 KiB でした。

今回は、4種類のシグナルを1秒おきに収集したシグナルを10秒間隔で送信するキャンペーンをAWS IoT FleetWiseで設定したので、そこそこ高頻度なデータ収集となってます。

grafana-2.png

こんな感じで、もっと細かくデータを見ることもできます。

最近はバイクのアクティビティーを記録するアプリもあり、私も使っています。ただ、GPSから想定した速度しか記録できないので、このように直接バイクからデータを取れると、より詳細な情報が見られるようになり、面白そうだなと思いました。

以降では、AWS IoT FleetWiseのセットアップや、キャンペーンの設定を行った際の手順を紹介しています。

AWS IoT FleetWise agentの準備

この手順で用意されているCloudFormationのテンプレートを使ってインスタンスを起動します。
https://github.com/aws/aws-iot-fleetwise-edge/blob/main/docs/rpi-tutorial/raspberry-pi-tutorial.md#step-2-launch-your-development-machine

起動されたインスタンスの情報

uname -a

Linux ip-172-31-35-230 5.15.0-1075-aws #82~20.04.1-Ubuntu SMP Thu Dec 19 05:23:06 UTC 2024 aarch64 aarch64 aarch64 GNU/Linux

ビルド

git clone https://github.com/aws/aws-iot-fleetwise-edge.git ~/aws-iot-fleetwise-edge

cd ~/aws-iot-fleetwise-edge \
&& sudo -H ./tools/install-deps-native.sh

./tools/build-fwe-native.sh

必要な情報をプロビジョニング

実行する前にAWSのクレデンシャルが必要です。REGIONVEHICLE_NAME 自分の環境に合わせます。

REGION=us-east-1
VEHICLE_NAME=z900rs

mkdir -p ~/aws-iot-fleetwise-deploy \
&& cd ~/aws-iot-fleetwise-deploy \
&& cp -r ~/aws-iot-fleetwise-edge/tools . \
&& mkdir -p build \
&& cp ~/aws-iot-fleetwise-edge/build/aws-iot-fleetwise-edge build \
&& mkdir -p config \
&& cd config \
&& ../tools/provision.sh \
   --region $REGION \
   --vehicle-name $VEHICLE_NAME \
   --certificate-pem-outfile certificate.pem \
   --private-key-outfile private-key.key \
   --endpoint-url-outfile endpoint.txt \
   --vehicle-name-outfile vehicle-name.txt \
&& ../tools/configure-fwe.sh \
   --input-config-file ~/aws-iot-fleetwise-edge/configuration/static-config.json \
   --output-config-file config-0.json \
   --log-color Yes \
   --vehicle-name `cat vehicle-name.txt` \
   --endpoint-url `cat endpoint.txt` \
   --can-bus0 can0 \
&& cd .. \
&& zip -r aws-iot-fleetwise-deploy.zip .

SCPでローカルに ~/aws-iot-fleetwise-deploy/aws-iot-fleetwise-deploy.zip をダウンロードします。

Raspberry Piのセットアップ

使ったのは、Raspberry Pi 3、Ubuntu Server 20.04.5 LTS (64bit)のOS

uname -a
Linux ubuntu 5.4.0-1122-raspi #134-Ubuntu SMP PREEMPT Fri Jan 17 12:48:32 UTC 2025 aarch64 aarch64 aarch64 GNU/Linux

アップデート

sudo apt update \
&& sudo apt upgrade -y \
&& sudo apt install -y unzip

CAN Hatの設定

利用している Can Hatはこちらのものですので、サイトの手順を参考に必要な設定を行います。

sudo vi /boot/config.txt

以下を追記

dtparam=spi=on
dtoverlay=mcp2515-can0,oscillator=12000000,interrupt=25,spimaxfrequency=2000000

sudo reboot で再起動

FleetWise agentをインストール

SCPでダウンロードした aws-iot-fleetwise-deploy.zip をラズパイにSCPでコピーします。

mkdir -p ~/aws-iot-fleetwise-deploy && cd ~/aws-iot-fleetwise-deploy \
&& unzip -o ~/aws-iot-fleetwise-deploy.zip \
&& sudo mkdir -p /etc/aws-iot-fleetwise \
&& sudo cp config/* /etc/aws-iot-fleetwise \
&& sudo ./tools/install-fwe.sh

sudo -H ~/aws-iot-fleetwise-deploy/tools/install-socketcan.sh

CANを有効にするため /usr/local/bin/setup-socketcan.sh へ以下を追記

ip link set up can0 txqueuelen 1000 type can bitrate 500000 restart-ms 100

サービスを再起動

sudo systemctl restart setup-socketcan
sudo systemctl restart fwe@0

FleetWise agentのログを確認

sudo journalctl -fu fwe@0 --output=cat

[Thread: 8288] [2025-03-22T03:46:27.984Z] [WARN ] [AwsBootstrap.cpp:52] [LogStream()]: [FileSystemUtils: Home dir not stored in environment, trying to fetch manually from the OS.]
[Thread: 8288] [2025-03-22T03:46:28.033Z] [INFO ] [IoTFleetWiseEngine.cpp:390] [connect()]: [Maximum AWS SDK Heap Memory Bytes has been configured:10000000]
[Thread: 8288] [2025-03-22T03:46:28.033Z] [INFO ] [IoTFleetWiseEngine.cpp:420] [connect()]: [ConnectionType is iotCore]
[Thread: 8288] [2025-03-22T03:46:28.035Z] [INFO ] [AwsIotConnectivityModule.cpp:184] [createMqttClient()]: [Creating MQTT client]
[Thread: 8289] [2025-03-22T03:46:28.096Z] [INFO ] [AwsIotConnectivityModule.cpp:299] [operator()()]: [Attempting MQTT connection]
[Thread: 8288] [2025-03-22T03:46:28.096Z] [INFO ] [CollectionSchemeManager.cpp:72] [start()]: [Thread started]
[Thread: 8288] [2025-03-22T03:46:28.097Z] [INFO ] [IoTFleetWiseEngine.cpp:1689] [connect()]: [Engine Connected]
[Thread: 8296] [2025-03-22T03:46:28.097Z] [INFO ] [Persistency.cpp:61] [retrieve()]: [Retrieved a CollectionSchemeList of size zero]
[Thread: 8296] [2025-03-22T03:46:28.097Z] [INFO ] [Persistency.cpp:61] [retrieve()]: [Retrieved a DecoderManifest of size zero]
Started successfully

以上で、デバイス側の準備ができました。

クラウドのリソースを作成

クラウドのリソースを作成するので、FleetWise agentをビルドした時に使ったEC2インスタンスから実行します。githubのリポジトリに含まれていたサンプル値をいくつか利用しています。

cd ~/aws-iot-fleetwise-edge/tools/cloud

Timestream DBの作成

aws timestream-write create-database --database-name BikeDatabase
aws timestream-write create-table --database-name BikeDatabase --table-name BikeTable

Signal catalogの作成

SIGNAL_CATALOG_NAME=obd-signals

aws iotfleetwise create-signal-catalog \
--name $SIGNAL_CATALOG_NAME \
--nodes file://vehicle-node.json

aws iotfleetwise update-signal-catalog \
--name $SIGNAL_CATALOG_NAME \
--nodes-to-update file://obd-nodes.json

Model Manifestの作成

SIGNAL_CATALOG_ARN=`aws iotfleetwise get-signal-catalog --name $SIGNAL_CATALOG_NAME --query "arn" --output text`
MODEL_NAME=z900rs-2025
MODEL_MANIFEST=$MODEL_NAME-manifest

このモデルが持つSignalの一覧を作成。(Signal catalogからめぼしいものを指定。が、実際にはこの中から4種類しか取れなかった)

cat << EOF > ./obd-model-nodes.json
[
    "Vehicle.OBD.CoolantTemperature",
    "Vehicle.OBD.EngineCoolantTemperature",
    "Vehicle.OBD.OilTemperature",
    "Vehicle.OBD.EngineSpeed",
    "Vehicle.OBD.Speed",
    "Vehicle.OBD.ThrottlePosition",
    "Vehicle.OBD.FuelLevel",
    "Vehicle.OBD.DemandEngineTorque",
    "Vehicle.OBD.Odometer",
    "Vehicle.OBD.ControlModuleVoltage"
]
EOF

Model manifestを作成して有効化

aws iotfleetwise create-model-manifest \
--name $MODEL_MANIFEST \
--signal-catalog-arn $SIGNAL_CATALOG_ARN \
--nodes file://obd-model-nodes.json

aws iotfleetwise update-model-manifest \
--name $MODEL_MANIFEST \
--status ACTIVE

Decoder Manifestの作成

DECODER_MANIFEST_NAME=$MODEL_NAME-decoder-manifest
MODEL_MANIFEST_ARN=`aws iotfleetwise get-model-manifest --name $MODEL_MANIFEST --query "arn" --output text`

Model Manifestに登録したSignalのdecode情報を obd-decoders.json から抜粋して作成

cat << EOF > ./$MODEL_NAME-obd-decoders.json
[
  {
    "fullyQualifiedName": "Vehicle.OBD.CoolantTemperature",
    "interfaceId": "0",
    "type": "OBD_SIGNAL",
    "obdSignal": {
      "byteLength": 1,
      "offset": -40,
      "pid": 5,
      "pidResponseLength": 1,
      "scaling": 1,
      "serviceMode": 1,
      "startByte": 0,
      "bitMaskLength": 8,
      "bitRightShift": 0
    }
  },
  {
    "fullyQualifiedName": "Vehicle.OBD.EngineCoolantTemperature",
    "interfaceId": "0",
    "type": "OBD_SIGNAL",
    "obdSignal": {
      "byteLength": 1,
      "offset": 0,
      "pid": 103,
      "pidResponseLength": 3,
      "scaling": 1,
      "serviceMode": 1,
      "startByte": 0,
      "bitMaskLength": 8,
      "bitRightShift": 0
    }
  },
  {
    "fullyQualifiedName": "Vehicle.OBD.OilTemperature",
    "interfaceId": "0",
    "type": "OBD_SIGNAL",
    "obdSignal": {
      "byteLength": 1,
      "offset": -40,
      "pid": 92,
      "pidResponseLength": 1,
      "scaling": 1,
      "serviceMode": 1,
      "startByte": 0,
      "bitMaskLength": 8,
      "bitRightShift": 0
    }
  },
  {
    "fullyQualifiedName": "Vehicle.OBD.EngineSpeed",
    "interfaceId": "0",
    "type": "OBD_SIGNAL",
    "obdSignal": {
      "byteLength": 2,
      "offset": 0,
      "pid": 12,
      "pidResponseLength": 2,
      "scaling": 0.25,
      "serviceMode": 1,
      "startByte": 0,
      "bitMaskLength": 8,
      "bitRightShift": 0
    }
  },
  {
    "fullyQualifiedName": "Vehicle.OBD.Speed",
    "interfaceId": "0",
    "type": "OBD_SIGNAL",
    "obdSignal": {
      "byteLength": 1,
      "offset": 0,
      "pid": 13,
      "pidResponseLength": 1,
      "scaling": 1,
      "serviceMode": 1,
      "startByte": 0,
      "bitMaskLength": 8,
      "bitRightShift": 0
    }
  },
  {
    "fullyQualifiedName": "Vehicle.OBD.ThrottlePosition",
    "interfaceId": "0",
    "type": "OBD_SIGNAL",
    "obdSignal": {
      "byteLength": 1,
      "offset": 0,
      "pid": 17,
      "pidResponseLength": 1,
      "scaling": 0.39215686274509803922,
      "serviceMode": 1,
      "startByte": 0,
      "bitMaskLength": 8,
      "bitRightShift": 0
    }
  },
  {
    "fullyQualifiedName": "Vehicle.OBD.FuelLevel",
    "interfaceId": "0",
    "type": "OBD_SIGNAL",
    "obdSignal": {
      "byteLength": 1,
      "offset": 0,
      "pid": 47,
      "pidResponseLength": 1,
      "scaling": 0.39215686274509803922,
      "serviceMode": 1,
      "startByte": 0,
      "bitMaskLength": 8,
      "bitRightShift": 0
    }
  },
  {
    "fullyQualifiedName": "Vehicle.OBD.DemandEngineTorque",
    "interfaceId": "0",
    "type": "OBD_SIGNAL",
    "obdSignal": {
      "byteLength": 1,
      "offset": -125,
      "pid": 97,
      "pidResponseLength": 1,
      "scaling": 1,
      "serviceMode": 1,
      "startByte": 0,
      "bitMaskLength": 8,
      "bitRightShift": 0
    }
  },
  {
    "fullyQualifiedName": "Vehicle.OBD.Odometer",
    "interfaceId": "0",
    "type": "OBD_SIGNAL",
    "obdSignal": {
      "byteLength": 4,
      "offset": 0,
      "pid": 166,
      "pidResponseLength": 4,
      "scaling": 0.1,
      "serviceMode": 1,
      "startByte": 0,
      "bitMaskLength": 8,
      "bitRightShift": 0
    }
  },
  {
    "fullyQualifiedName": "Vehicle.OBD.ControlModuleVoltage",
    "interfaceId": "0",
    "type": "OBD_SIGNAL",
    "obdSignal": {
      "byteLength": 2,
      "offset": 0,
      "pid": 66,
      "pidResponseLength": 2,
      "scaling": 0.001,
      "serviceMode": 1,
      "startByte": 0,
      "bitMaskLength": 8,
      "bitRightShift": 0
    }
  }
]
EOF

decoder manifestを作成


aws iotfleetwise create-decoder-manifest \
--name $DECODER_MANIFEST_NAME \
--model-manifest-arn $MODEL_MANIFEST_ARN \
--network-interfaces file://network-interface-obd.json \
--signal-decoders file://$MODEL_NAME-obd-decoders.json

aws iotfleetwise update-decoder-manifest \
--name $DECODER_MANIFEST_NAME \
--status ACTIVE

Vehicleの作成

VEHICLE_NAME=z900rs
DECODER_MANIFEST_ARN=`aws iotfleetwise get-decoder-manifest --name $DECODER_MANIFEST_NAME --query "arn" --output text`

aws iotfleetwise create-vehicle \
--vehicle-name $VEHICLE_NAME \
--model-manifest-arn $MODEL_MANIFEST_ARN \
--decoder-manifest-arn $DECODER_MANIFEST_ARN

キャンペーンを作成

キャンペーン用のRoleを作成

cat << EOF > ./trust-policy.json
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "Service": "iotfleetwise.amazonaws.com"
      },
      "Action": "sts:AssumeRole"
    }
  ]
}
EOF

Roleの作成

CAMPAIGNE_ROLE=BikeCampaigneRole

aws iam create-role --role-name $CAMPAIGNE_ROLE \
--assume-role-policy-document file://trust-policy.json

Timestream DBに書き込む権限を持つPolicyを作成

TS_TABLE_ARN=`aws timestream-write describe-table --database-name BikeDatabase --table-name BikeTable --query "Table.Arn" --output text`

cat << EOF > ./permissions-policy.json
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "timestreamIngestion",
      "Effect": "Allow",
      "Action": [
        "timestream:WriteRecords",
        "timestream:Select",
        "timestream:DescribeTable"
      ],
      "Resource": "$TS_TABLE_ARN"
    },
    {
      "Sid": "timestreamDescribeEndpoint",
      "Effect": "Allow",
      "Action": [
        "timestream:DescribeEndpoints"
      ],
      "Resource": "*"
    }
  ]
}
EOF

aws iam create-policy --policy-name ${CAMPAIGNE_ROLE}_TSPolicy \
--policy-document file://permissions-policy.json

PolicyをRoleにアタッチ

POLICY_ARN=`aws iam list-policies --query "Policies[?PolicyName=='${CAMPAIGNE_ROLE}_TSPolicy'].Arn" --output text`

aws iam attach-role-policy \
--policy-arn $POLICY_ARN \
--role-name $CAMPAIGNE_ROLE

キャンペーンに必要なARNを確認

TARGET_ARN=`aws iotfleetwise get-vehicle --vehicle-name $VEHICLE_NAME --query "arn" --output text`
ROLE_ARN=`aws iam get-role --role-name $CAMPAIGNE_ROLE --query "Role.Arn" --output text`

キャンペーンで収集するシグナルを定義

cat << EOF > ./campaigne-nodes.json
[
    {
        "maxSampleCount": 10,
        "minimumSamplingIntervalMs": 1000,
        "name": "Vehicle.OBD.CoolantTemperature"
    },
    {
        "maxSampleCount": 10,
        "minimumSamplingIntervalMs": 1000,
        "name": "Vehicle.OBD.EngineCoolantTemperature"
    },
    {
        "maxSampleCount": 10,
        "minimumSamplingIntervalMs": 1000,
        "name": "Vehicle.OBD.OilTemperature"
    },
    {
        "maxSampleCount": 10,
        "minimumSamplingIntervalMs": 1000,
        "name": "Vehicle.OBD.EngineSpeed"
    },
    {
        "maxSampleCount": 10,
        "minimumSamplingIntervalMs": 1000,
        "name": "Vehicle.OBD.Speed"
    },
    {
        "maxSampleCount": 10,
        "minimumSamplingIntervalMs": 1000,
        "name": "Vehicle.OBD.ThrottlePosition"
    },
    {
        "maxSampleCount": 10,
        "minimumSamplingIntervalMs": 1000,
        "name": "Vehicle.OBD.FuelLevel"
    },
    {
        "maxSampleCount": 10,
        "minimumSamplingIntervalMs": 1000,
        "name": "Vehicle.OBD.DemandEngineTorque"
    },
    {
        "maxSampleCount": 1,
        "minimumSamplingIntervalMs": 1000,
        "name": "Vehicle.OBD.Odometer"
    },
    {
        "maxSampleCount": 1,
        "minimumSamplingIntervalMs": 1000,
        "name": "Vehicle.OBD.ControlModuleVoltage"
    }
]
EOF

キャンペーンを作成

aws iotfleetwise create-campaign \
--name bike-timebase-10sec \
--signal-catalog-arn $SIGNAL_CATALOG_ARN \
--target-arn $TARGET_ARN \
--collection-scheme "timeBasedCollectionScheme={periodMs=10000}" \
--spooling-mode TO_DISK \
--data-destination-configs "timestreamConfig={timestreamTableArn=$TS_TABLE_ARN,executionRoleArn=$ROLE_ARN}" \
--signals-to-collect file://campaigne-nodes.json

キャンペーンを有効化

aws iotfleetwise update-campaign \
--name bike-timebase-10sec \
--action APPROVE

キャンペーンを有効化すると、targetに登録されているFleetWise agentに設定情報が配信され、自動的に収集が開始されます。

2
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?