Yura YuLife

ITエンジニアの覚え書き。

ROSのPointCloud2で独自のフィールドを定義

ROSのpclパッケージで独自のフィールドを定義したPointCloud2のトピックをpublish, subscribeする方法です。

環境

スクリプト例(Publisher)

rvizで確認

上記のスクリプトを動かし、rvizでPointCloud2型の/custom_point_cloudトピックを表示すると、下図のように生成した3つの点が色付きで表示されることが確認できます。

$ rosrun some_package  publish_custom_point_cloud.py

f:id:yurayur:20160226151803p:plain

フィールドの定義

上記スクリプトではFIELDSの部分で独自のフィールドを定義しています。

FIELDS = [
    # x, y, zやrgbなどはよく使われるフィールド名
    PointField(name='x', offset=0, datatype=PointField.FLOAT32, count=1),
    PointField(name='y', offset=4, datatype=PointField.FLOAT32, count=1),
    ...
    # 以下が独自のフィールド
    PointField(name='my_field1', offset=16, datatype=PointField.FLOAT32, count=1),
    ]

よく使われるフィールドについては pcl/Overview - ROS Wiki1.3 Common PointCloud2 field names の項目で列挙されています。

PointFieldの各引数は以下のように定義されています。

string name      # Name of field
uint32 offset    # Offset from start of point struct
uint8  datatype  # Datatype enumeration, see above
uint32 count     # How many elements in the field

namedatatypeは見ての通り、フィールド名とデータ型です。

offsetはPointCloud2の各点を表す構造体の中で、何バイトのところからがそのフィールドを表しているかを定義するようです。 例えばx座標のフィールドのFloat32は4バイトなので、後続するy座標のフィールドはoffset=4となっています。

また、countは当該フィールドのデータ数を表しています。通常は1で良いと思います。

ポイントの生成

POINTS = [
    # FIELDSで定義したフィールドを列挙
    # [x, y, z, rgb, my_field1, my_field2]
    [0.3, 0.0, 0.0, 0xff0000, 0.5, 1.2],
    [0.0, 0.3, 0.0, 0x00ff00, 1.8, 0.0],
    [0.0, 0.0, 0.3, 0x0000ff, 0.9, 0.4],
]

create_cloudの3番目の引数には点のリストであるPOINTSを渡しています。

POINTSの各要素はそれぞれがポイントに対応しており、各ポイントもリスト型になっていて、FIELDSで定義したフィールドの順に値が並んでいます。

例えば、count=1のフィールドが3個の場合は長さ3のリストに、count=1のフィールドが3個とcount=3のフィールドが1個の場合は長さ6にリストになります。

スクリプト例(Subscriber)

このスクリプトを動かすと以下のような出力が表示されます。

$ rosrun some_package  subscribe_custom_point_cloud.py

[WARN] [WallTime: 1456466400.492649] x, y, z: 0.3, 0.0, 0.0
[WARN] [WallTime: 1456466400.492909] my field 1: 0.500000
[WARN] [WallTime: 1456466400.493283] my field 2: 1.200000
[WARN] [WallTime: 1456466400.493446] x, y, z: 0.0, 0.3, 0.0
[WARN] [WallTime: 1456466400.493641] my field 1: 1.800000
[WARN] [WallTime: 1456466400.493788] my field 2: 0.000000
[WARN] [WallTime: 1456466400.493930] x, y, z: 0.0, 0.0, 0.3
[WARN] [WallTime: 1456466400.494073] my field 1: 0.900000
[WARN] [WallTime: 1456466400.494212] my field 2: 0.400000

各ポイントを使うときはread_points関数を利用すると、publisherのPOINTSと同じ形式で点群を取得できます。

参考URL

Python, OpenCVでRGBとHSVを相互変換

動作環境

OpenCVRGBHSVを相互変換

画像のRGBHSVをまるごと変換するにはcv2.cvtColorをそのまま使えばよいのですが、こちらはRGBHSVの値を1ピクセルだけ変換するためのラッパー関数です。

import numpy as np
import cv2


def hsv_to_rgb(h, s, v):
    bgr = cv2.cvtColor(np.array([[[h, s, v]]], dtype=np.uint8), cv2.COLOR_HSV2BGR)[0][0]
    return (bgr[2], bgr[1], bgr[0])


def rgb_to_hsv(r, g, b):
    hsv = cv2.cvtColor(np.array([[[b, g, r]]], dtype=np.uint8), cv2.COLOR_BGR2HSV)[0][0]
    return (hsv[0], hsv[1], hsv[2])
>>> hsv_to_rgb(0, 255, 255)
(255, 0, 0)
>>> hsv_to_rgb(60, 255, 255)
(0, 255, 0)
>>> hsv_to_rgb(120, 255, 255)
(0, 0, 255)
>>> rgb_to_hsv(255, 0, 0)
(0, 255, 255)
>>> rgb_to_hsv(0, 255, 0)
(60, 255, 255)
>>> rgb_to_hsv(0, 0, 255)
(120, 255, 255)

人感センサ(SB00412A-1)検知時にLEDを光らせる

aitendoで人感センサ(SB00412A-1)を購入したので、センサが人を検知した時にLEDを光らせてみました。

追記(2016/02/28)

SB00412A-1を3.3Vで接続すると動作が不安定になるため、5Vでの接続を推奨します!

接続方法は、Raspberry Piで人感センサ(SB00412A-1)を5Vで利用する方法 - Yura YuLifeの記事を参照してください。


f:id:yurayur:20160216234515j:plain

ちなみに人感センサことPIRセンサは赤外線の変化を捉えるセンサで、人間が発する赤外線によって人が近づいたのを検知できます。

性能

一回点灯すると人がいなくなっても7〜8秒は点灯し続けています。

スペックによると感知距離は3〜5mとのこと。机の上に上向きにセンサを設置した部屋に入ると、LEDがピカッと光りました。机とドアの距離は大体1.5mくらいです。

必要なもの

配線

f:id:yurayur:20160217002051p:plain

SB00412A-1

f:id:yurayur:20160217000118j:plain

基板に+と-が書いてあるので、それぞれ3.3VとGNDへ。GPIOはどこでも大丈夫です。

LEDと抵抗

LEDの足の長い方をGPIOに、短い方を抵抗を介してGNDに接続します。

スクリプト

プログラム中のSENSOR_PINLED_PINを、それぞれSB00412A-1とLEDが接続されたGPIOのピン番号に変更します。

$ python sync_sensor_led.pyを実行するとセンサーが人を検知した時にLEDが光ります。

参考URL

Raspberry Piでスイッチを押すと音楽を再生する

Raspberry Piに接続したタクトスイッチを押すと、音楽を再生するPythonスクリプトです。

ちなみに、上の動画で流れているのは僕のバンドCosmic Time Scaleの曲です。

必要なもの

Raspberry Piとタクトスイッチを接続

こんな感じで配線します。

f:id:yurayur:20160214191937p:plain

GPIOピンは今回は19番を使っていますが、空いていればどのピンでも大丈夫。

スイッチの動作をテスト

以下のスクリプトraspi_gpio_pin.pyとして保存します。

$ python raspi_gpio_pin.pyを実行し、スイッチを押していない時は0、スイッチを押している時は1がコンソールに出力されれば、問題なく配線されています。

スイッチ押下で音楽を再生

以下のスクリプトraspi_play_music.pyとして保存します。

$ python raspi_play_music.pyを実行し、スイッチを押すとSONG_LISTの中からランダムに曲が再生されます。

これを応用すればRaspberry Piで音響さんやDJができますね。

参考URL

Raspberry Piに接続したLCD(ACM1602NI)をPythonで動かす

Raspberry PiにI2Cで接続したLCD(ACM1602NI-FLW-FBW-M01)を、Pythonから動かします。

f:id:yurayur:20160213215623j:plain

ソースコード、セットアップ手順はGitHubにて公開しています。

github.com

必要なもの

Raspberry PiとLCDを接続

LCDにハンダ付け

LCDの基板に7ピンのピンフレームをハンダ付けします。

ブレッドボードにピンを刺した状態でハンダ付けすると、ピンを垂直に固定するのが容易になるのでオススメです。

LCDとRaspberry Piを接続

ブレッドボード上はこんな感じで接続します。

f:id:yurayur:20160213221550j:plain

ちなみに本体側のピンはこちら。

f:id:yurayur:20160213222044j:plain

ここまでできたらRaspberry Piを起動します。

Raspbianの設定

I2Cを有効にする

$ sudo raspi-config

9 Advanced Options から A7 I2C を選択し、 Yes を2回選択します。raspi-configを抜けたらRaspberry Piを再起動します。

必要なライブラリのインストール

$ sudo apt-get install i2c-tools python-smbus

ドライバーのロード

$ sudo modprobe i2c-bcm2708
$ sudo modprobe i2c-dev

I2C Configの編集

/boot/config.txtを開いて以下の行を追記します。

dtparam=i2c_baudrate=50000

ここで再度Raspberry Piを再起動します。

設定の確認

以下のコマンドを実行し、bcm2708がロードされていること、baudrate50000に変更されていることを確認します。

$ dmesg | grep i2c
[    3.787020] bcm2708_i2c 3f804000.i2c: BSC1 Controller at 0x3f804000 (irq 79) (baudrate 50000)
[    3.820524] i2c /dev entries driver

LCDの動作テスト

以下のコマンドを実行し、LCDAと表示されることを確認します。

$ sudo i2cset -y 1 0x50 0x00 0x01
$ sudo i2cset -y 1 0x50 0x00 0x38
$ sudo i2cset -y 1 0x50 0x00 0x0c
$ sudo i2cset -y 1 0x50 0x00 0x06
$ sudo i2cset -y 1 0x50 0x80 0x41

なお、i2csetコマンドの引数の1はI2Cバスの番号、0x50LCDのアドレスです。

通常これらはi2cdetectコマンドで調べられるのですが、このコマンドを実行するとLCDがハングするため絶対に行ってはいけません

PythonからLCDを操作

$ git clone https://github.com/yuma-m/raspi_lcd_acm1602ni.git
$ cd raspi_lcd_acm1602ni
$ sudo python raspi_lcd.py "Hello world!"
$ sudo python raspi_lcd.py "ラズベリーパイデ、" "ニホンゴヲLCDヒョウジ!"

raspi_lcd.pyは引数を1つ、もしくは2つ取ることができ、それぞれが1行目、2行目の表示内容に対応しています。

入力可能な文字は、半角英数記号、半角・全角のカタカナ、一部の特殊文字(千、万、円、Σ、α、βなど)です。

f:id:yurayur:20160213224244j:plain

参考URL