🍣

NuScenesの車両運転CAN-BUSデータをクラスタリング

2023/04/14に公開

こんにちは!Fusic 機械学習チームの塚本です。

機械学習モデルの開発から運用までなんでもしています。もし、機械学習で困っていることがあれば、気軽にお問い合わせください。


やること

まず、CAN-BUSデータは、速度、エンジンの回転数、ブレーキの状態などのテーブルデータになっています。

このCAN-BUSデータの利用に慣れることも兼ねて、NuScenesのCAN-BUSデータセットを利用して、車両の運転行動の視覚化を試します。

簡単ですが、以下をやります。

  • UMAPを利用した次元削減
  • DTWによる時系列クラスタリング
  • 視覚化

[1903.11027] nuScenes: A multimodal dataset for autonomous driving

NuScenesのデータセット

https://www.nuscenes.org/nuscenes?tutorial=nuscenes
ここのチュートリアルにある通りで基本的な操作はできますが、量が多いので少し迷うかもです。

走行データの画像は以下で取得できます。

from nuscenes.nuscenes import NuScenes
from PIL import Image

scenes_path = ... # nuscenesをダウンロードしてきたフォルダ
nusc = NuScenes(version='v1.0-mini', dataroot=scenes_path, verbose=True)

# 例として最初のサンプルを選択
sample = nusc.sample[0]

# 動画の各フレーム(0.5sec単位)
scene_token = sample["scene_token"]

cam_front = nusc.get('sample_data', sample['data']['CAM_FRONT'])
img = Image.open(f"{scenes_path}/{cam_front['filename']}")

今回自分は見やすさのために、無理やり画像を繋げて、gifで利用しました。
全体的に20秒程度の動画になるようです。

NuScenes CAN-BUSのデータセット

https://www.nuscenes.org/nuscenes?tutorial=can-bus
https://github.com/nutonomy/nuscenes-devkit/blob/master/python-sdk/nuscenes/can_bus/README.md

今回は、この中のデータの「Zoe Vehicle Info」を利用していきます。
ここには車輪の速度やステアリング角度などの情報が入っています。
このデータを利用して いきます。

今回特徴量は検出窓を0.5秒単位で、単純に平均を取ったものを使います。

import numpy as np

nusc_can = NuScenesCanBus(dataroot=scenes_path)

features = []

for scene in nusc.scene:
    name = scene["name"]
    
    messages = pd.DataFrame(nusc_can.get_messages(name, 'zoe_veh_info'))

    timestamp = messages.utime - messages.utime.min()
    
    FL_wheel_speed = messages.FL_wheel_speed * 2 * np.pi * 0.305 / 60
    FR_wheel_speed = messages.FR_wheel_speed * 2 * np.pi * 0.305 / 60
    RL_wheel_speed = messages.RL_wheel_speed * 2 * np.pi * 0.305 / 60
    RR_wheel_speed = messages.RR_wheel_speed * 2 * np.pi * 0.305 / 60

    longitudinal_accel = messages.longitudinal_accel
    transversal_accel = messages.transversal_accel

    steer_raw = (messages.steer_raw) * np.pi / 180

        print(name, ":", sample_size)
    
    # 0.5秒単位で特徴量を作成
    timewindow = 1e6/2
    sample_size = int(np.ceil((timestamp.max() - timestamp.min()) / timewindow))

    for i in range(sample_size):
        start_time = timestamp.min() + i * timewindow
        end_time = start_time + timewindow

        idx = np.logical_and(start_time <= timestamp, timestamp < end_time)

        if not idx.any():
            continue
            
        features.append({
            "FL_wheel_speed": FL_wheel_speed[idx].mean(),
            "FR_wheel_speed": FR_wheel_speed[idx].mean(),
            "RL_wheel_speed": RL_wheel_speed[idx].mean(),
            "RR_wheel_speed": RR_wheel_speed[idx].mean(),
            "longitudinal_accel": longitudinal_accel[idx].mean(),
            "transversal_accel": transversal_accel[idx].mean(),
            "steer_raw": steer_raw[idx].mean(),
        })

次元圧縮

UMAPを利用して、特徴量を2次元に落として、視覚化してみます。

import umap

t = umap.UMAP(n_components=2, random_state=0)
X = t.fit_transform(features)

plt.scatter(X[:, 0], X[:, 1], c=np.array([0]*len(X)), cmap='Accent', alpha=0.7, s=20)
plt.title('UMAP plot')
plt.colorbar()
plt.show()

クラスター分析

6つ程度のクラスタに分けてみます。

from tslearn.clustering import TimeSeriesKMeans

classifier = TimeSeriesKMeans(n_clusters=6, random_state=42, metric="dtw")
labels = classifier.fit_predict(X)

plt.scatter(X[:, 0], X[:, 1], c=labels, cmap='Accent', alpha=0.7, s=10)
plt.title('UMAP-KMeans plot')
plt.colorbar()
plt.show()

各クラスタについて、雑ですが、おおよそこんな感じになりました。

これと画像の一部比較です。

  • scene-0061の画像

  • scene-0553の画像

小さいですが、右の赤点が対応する点です。

やや恣意的に見えるかもですが、おおよそこんな形でクラスタリングできています。

今回は大した分析は行っていませんが、このような分析から、急カーブや急ブレーキなど自動走行に必要な予測などを行っていくことになるかと思います。


最後に宣伝になりますが、機械学習でビジネスの成長を加速するために、Fusicの機械学習チームがお手伝いしています。機械学習のPoCから運用まで、すべての場面でサポートした実績があります。もし、困っている方がいましたら、ぜひFusicにご相談ください。

お問い合わせ

Fusic 技術ブログ

Discussion