空飛ぶロボットのつくりかた

ロボットをつくるために必要な技術をまとめます。ロボットの未来についても考えたりします。

マイコン x Linux のお勉強

やりたいこと

UbuntuやTX2からマイコンを操作し、いろいろなデバイスを動かしたい

TX2での準備

以下を実行し、ACMを使えるようにする必要がある

Build Kernel and ttyACM Module – NVIDIA Jetson TX2 | JetsonHacks

Arduinoの設定

  1. UbuntuにArduino IDE(1.8.5)インストール | ねこめも を参考に64bitをダウンロード

  2. sudo chmod a+rw /dev/ttyACM0

  3. ~/arduino-1.8.5/arduinoを実行

  4. ビルド -> arduinoに転送

ToDo: /dev/ttyACM0に権限をつけておく方法調査

mbedの設定

OSにあまり関係しない

  1. ブラウザで開発

  2. ビルドでできたバイナリをmbedフォルダに移動

マイコンとの通信

マイコンとUSB接続してACM経由で通信する

準備

  • pip install pyserial

PC側実装

標準入力のコマンドをマイコンに送る

注意!

  • serialのopen()してからtime.sleep(2.0)のように2秒以上いれないと通信できないことがあった! Debugの時は念の為長くとっておこう。

  • python3では文字のエンコードがpython2と異なるため、serial writeする時に<送りたい文字列>.encode()とする必要がある。

#!/usr/bin/env python
# coding: utf-8

import serial
import time

if __name__ == '__main__':
  print "hello serial!"
  ser = serial.Serial()
  ser.port = '/dev/ttyACM0'
  ser.baudrate = 9600
  ser.open()
  time.sleep(2.0)

  while(1):
    position = bytes(raw_input())
    ser.write(position)

    # for Debug 
    read_ser = ser.readline().rstrip()
    print read_ser

Arduino側実装

#include "enum.h"

const char RX_FOOT = ';';

void setup() {
  // settings
  Serial.begin(9600);
  Serial.setTimeout(1500);
}

void loop() {

  // シリアル受信
  if(Serial.available() > 0)
  {
    // 受信しきるまでのバッファ時間
    delay(5);
    // データ受信
    String buf = Serial.readStringUntil(RX_FOOT);
    Serial.println(buf);
  }
  delay(1);
}

mbed側実装

#include "mbed.h"
#include "MODSERIAL.h"
#include <list>
#include <string>
#include <cstdlib>

int main() 
{
    MODSERIAL pc(USBTX, USBRX, 8192);
    pc.baud(9600); 
    
    char data[1100];
    int data_index = 0;
  
    while(1) 
    {
        if (!pc.readable()) continue;
        char c = pc.getc();
        data[data_index++] = c;
        if (c == '\n')
        {
            data[data_index] = '\0';
            string command = data;
            pc.puts(command.c_str());
            data_index = 0;
        }
    }

mbedの遠隔リセット

ROSの基礎(通信編)

やりたいこと

ROSの復習がてら、基礎の部分で理解が浅い部分をまとめる

ピアツーピア設計方針

f:id:robonchu:20180126100735p:plain

参考:ROS/Technical Overview - ROS Wiki

「ピアツーピア」ではコンピュータさんの役割が決まっていません。 すべてのコンピュータさんが必要に応じてサーバにもなればクライアントにもなるのです。

参考:http://wa3.i-3-i.info/word1306.html

ピアアドレスの確認

$ rosnode list -a

-> http://localhost:58031/ /rosout

これによってlocalhost:58031というピアアドレスが使用されていることがわかる

XML-RPC(eXtensible Markup Language Remote Procedure Cal)

まぁ「XML-RPC」って単語が出てきたら「XML形式のデータをHTTPでやり取りするんだな~」と、お考えください。

point通信プロトコルだよ

pointXML形式のデータをやり取りするよ

pointHTTPでやり取りするよ

pointPOSTメソッドを使ってやり取りするよ

参考:http://wa3.i-3-i.info/word15419.html

POSTメソッド

まぁ「POSTメソッド」って単語が出てきたら「見えない所に隠してサーバに送るんだな~」と、お考えください。

参考:http://wa3.i-3-i.info/word1496.html

TCP/IP通信のpython実装

milestone-of-se.nesuke.com

参考:Pythonによる通信処理 - Qiita

client.py

# -*- coding:utf-8 -*-
import socket

host = "192.168.xxx.xxx" 
port = 2222 # 適当 

client = socket.socket(socket.AF_INET, socket.SOCK_STREAM) #オブジェクトの作成をします

client.connect((host, port)) #これでサーバーに接続します

client.send("from robonchu") #適当なデータを送信します(届く側にわかるように)

response = client.recv(4096) #レシーブは適当な2の累乗にします(大きすぎるとダメ)

print response

server.py

# -*- coding:utf-8 -*-
import socket

host ="192.168.xxx.xxx" 
port = 2222 # クライアントと揃える

serversock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
serversock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
serversock.bind((host,port)) #IPとPORTを指定してバインドします
serversock.listen(10) #接続の待ち受けをします(キューの最大数を指定)

print 'Waiting for connections...'
clientsock, client_address = serversock.accept() #接続されればデータを格納

while True:
    rcvmsg = clientsock.recv(1024)
    print 'Received -> %s' % (rcvmsg)
    if rcvmsg == '':
      break
    print 'Type message...'
    s_msg = raw_input()
    if s_msg == '':
      break
    print 'Wait...'

    clientsock.sendall(s_msg) #メッセージを返します
clientsock.close()

UDP通信のpython実装

参考:Pythonでネットワークプログラミング | saito's memo

TODO

トピックの平均転送速度を求める

$ rostopic bw /turtle1/pose

トピックの配布速度を求める

$ rostopic hz /turtle1/pose

サービスの引数リストの表示

$ rosservice args /turtle1/set_pen

シミュレーターを作ってみる

やりたいこと

簡単な機構のロボットシミュレータをつくってみる

モデル

f:id:robonchu:20180121084802p:plain ls

順運動学を解いてみる

# -*- coding: utf-8 -*-
import numpy as np
from numpy import sin,cos
import matplotlib.pyplot as plt

def fk(l1, l2, l3, th1, th2):
    x2 = l2 * cos(th2) - (l1 + l3) * cos(th1)
    y2 = l2 * sin(th2) + (l1 + l3) * sin(th1)
    
    x1 = -l1 * cos(th1)
    y1 = l1 * sin(th1)

    return x1, y1, x2, y2

def fk_frame(l1, l2, l3, l4, l5, l6, l7, th1, th2, x1, y1, x2, y2):
    x3 = - l4 * cos(th2) - l1 * cos(th1)
    y3 = - l4 * sin(th2) + l1 * sin(th1)

    x4 = (l2 + l6) * cos(th2) - (l1 + l3) * cos(th1) - l7 * sin(th2)
    y4 = (l2 + l6) * sin(th2) + (l1 + l3) * sin(th1) + l7 * cos(th2)

    x5 = (l2 + l6) * cos(th2) - (l1 + l3) * cos(th1) + l7 * sin(th2)
    y5 = (l2 + l6) * sin(th2) + (l1 + l3) * sin(th1) - l7 * cos(th2)

    x_f1 = [0, -l4 * cos(th2), x3, x1]
    y_f1 = [0, -l4 * sin(th2), y3, y1]

    x_f2 = [x3, x1 - l5 * sin(th2), x2]
    y_f2 = [y3, y1 + l5 * cos(th2), y2]

    x_l = [x2, x4, x5, x2]
    y_l = [y2, y4, y5, y2]

    return x_f1, y_f1, x_f2, y_f2, x_l, y_l

# グラフの描画
def plot(x, y, x_f1, y_f1, x_f2, y_f2, x_l, y_l):
    fig = plt.figure()
    ax = fig.add_subplot(111)
    # リンクの描画
    plt.plot(x, y,"-g",lw=5,label="link")
    plt.plot(x_f1, y_f1,"-g",lw=5,label="link")
    plt.plot(x_f2, y_f2,"-g",lw=5,label="link")
    plt.plot(x_l, y_l,"-g",lw=5,label="link")
    # 関節の描画
    plt.plot(x, y,"or",lw=5, ms=10,label="joint")
    plt.plot(x_f1, y_f1,"or",lw=5, ms=10,label="joint")
    plt.plot(x_f2, y_f2,"or",lw=5, ms=10,label="joint")
    plt.plot(x_l, y_l,"or",lw=5, ms=10,label="joint")
    plt.xlim(-0.4, 0.4)
    plt.ylim(-0.1,0.4)
    plt.grid()
    plt.show()

def main():
    # リンクの長さ
    l1, l2, l3, l4, l5, l6, l7= 0.18, 0.16, 0.0, 0.05, 0.03, 0.07, 0.07

    # 第1, 2の関節角度
    [th1, th2] = np.radians([90, 0])

    # 順運動学の計算
    x1, y1, x2, y2 = fk(l1, l2, l3, th1, th2)

    # ロボットアームのx座標, y座標をリストに格納
    x = [0, x1, x2]
    y = [0, y1, y2]

    x_f1, y_f1, x_f2, y_f2, x_l, y_l = fk_frame(l1, l2, l3, l4, l5, l6, l7, th1, th2, x1, y1, x2, y2)

    # ロボットアームの姿勢をグラフにプロット
    plot(x, y, x_f1, y_f1, x_f2, y_f2, x_l, y_l)

if __name__ == '__main__':
    main()

f:id:robonchu:20180121102438p:plain

参考:【Python】2リンクマニピュレータの順運動学シミュレーション | アルゴリズム雑記

解析的に逆運動学を解いてみる

sympyのシンボリック計算を用いて解いてみる

from sympy import *

theta1, theta2 = symbols('theta1 theta2')
l1, l2 ,l3, x, y = symbols('l1 l2 l3 x y')
eq1 = l2 * sin(theta2) + (l1 + l3) * sin(theta1) - y
eq2 = l2 * cos(theta2) - (l1 + l3) * cos(theta1) - x

init_printing()
ans = solve([eq1, eq2], [theta1, theta2])
print ans

計算結果

[(asin((l2*sin(2*atan((2*l2*y - sqrt(-l1**4 - 4*l1**3*l3 + 2*l1**2*l2**2 - 6*l1**2*l3**2 + 2*l1**2*x**2 + 2*l1**2*y**2 + 4*l1*l2**2*l3 - 4*l1*l3**3 + 4*l1*l3*x**2 + 4*l1*l3*y**2 - l2**4 + 2*l2**2*l3**2 + 2*l2**2*x**2 + 2*l2**2*y**2 - l3**4 + 2*l3**2*x**2 + 2*l3**2*y**2 - x**4 - 2*x**2*y**2 - y**4))/(-l1**2 - 2*l1*l3 + l2**2 + 2*l2*x - l3**2 + x**2 + y**2))) - y)/(l1 + l3)) + pi, 2*atan((2*l2*y - sqrt(-l1**4 - 4*l1**3*l3 + 2*l1**2*l2**2 - 6*l1**2*l3**2 + 2*l1**2*x**2 + 2*l1**2*y**2 + 4*l1*l2**2*l3 - 4*l1*l3**3 + 4*l1*l3*x**2 + 4*l1*l3*y**2 - l2**4 + 2*l2**2*l3**2 + 2*l2**2*x**2 + 2*l2**2*y**2 - l3**4 + 2*l3**2*x**2 + 2*l3**2*y**2 - x**4 - 2*x**2*y**2 - y**4))/(-l1**2 - 2*l1*l3 + l2**2 + 2*l2*x - l3**2 + x**2 + y**2))) ,
(asin((l2*sin(2*atan((2*l2*y + sqrt(-l1**4 - 4*l1**3*l3 + 2*l1**2*l2**2 - 6*l1**2*l3**2 + 2*l1**2*x**2 + 2*l1**2*y**2 + 4*l1*l2**2*l3 - 4*l1*l3**3 + 4*l1*l3*x**2 + 4*l1*l3*y**2 - l2**4 + 2*l2**2*l3**2 + 2*l2**2*x**2 + 2*l2**2*y**2 - l3**4 + 2*l3**2*x**2 + 2*l3**2*y**2 - x**4 - 2*x**2*y**2 - y**4))/(-l1**2 - 2*l1*l3 + l2**2 + 2*l2*x - l3**2 + x**2 + y**2))) - y)/(l1 + l3)) + pi, 2*atan((2*l2*y + sqrt(-l1**4 - 4*l1**3*l3 + 2*l1**2*l2**2 - 6*l1**2*l3**2 + 2*l1**2*x**2 + 2*l1**2*y**2 + 4*l1*l2**2*l3 - 4*l1*l3**3 + 4*l1*l3*x**2 + 4*l1*l3*y**2 - l2**4 + 2*l2**2*l3**2 + 2*l2**2*x**2 + 2*l2**2*y**2 - l3**4 + 2*l3**2*x**2 + 2*l3**2*y**2 - x**4 - 2*x**2*y**2 - y**4))/(-l1**2 - 2*l1*l3 + l2**2 + 2*l2*x - l3**2 + x**2 + y**2))) ,
(-asin((l2*sin(2*atan((2*l2*y - sqrt(-l1**4 - 4*l1**3*l3 + 2*l1**2*l2**2 - 6*l1**2*l3**2 + 2*l1**2*x**2 + 2*l1**2*y**2 + 4*l1*l2**2*l3 - 4*l1*l3**3 + 4*l1*l3*x**2 + 4*l1*l3*y**2 - l2**4 + 2*l2**2*l3**2 + 2*l2**2*x**2 + 2*l2**2*y**2 - l3**4 + 2*l3**2*x**2 + 2*l3**2*y**2 - x**4 - 2*x**2*y**2 - y**4))/(-l1**2 - 2*l1*l3 + l2**2 + 2*l2*x - l3**2 + x**2 + y**2))) - y)/(l1 + l3)), 2*atan((2*l2*y - sqrt(-l1**4 - 4*l1**3*l3 + 2*l1**2*l2**2 - 6*l1**2*l3**2 + 2*l1**2*x**2 + 2*l1**2*y**2 + 4*l1*l2**2*l3 - 4*l1*l3**3 + 4*l1*l3*x**2 + 4*l1*l3*y**2 - l2**4 + 2*l2**2*l3**2 + 2*l2**2*x**2 + 2*l2**2*y**2 - l3**4 + 2*l3**2*x**2 + 2*l3**2*y**2 - x**4 - 2*x**2*y**2 - y**4))/(-l1**2 - 2*l1*l3 + l2**2 + 2*l2*x - l3**2 + x**2 + y**2))) ,
(-asin((l2*sin(2*atan((2*l2*y + sqrt(-l1**4 - 4*l1**3*l3 + 2*l1**2*l2**2 - 6*l1**2*l3**2 + 2*l1**2*x**2 + 2*l1**2*y**2 + 4*l1*l2**2*l3 - 4*l1*l3**3 + 4*l1*l3*x**2 + 4*l1*l3*y**2 - l2**4 + 2*l2**2*l3**2 + 2*l2**2*x**2 + 2*l2**2*y**2 - l3**4 + 2*l3**2*x**2 + 2*l3**2*y**2 - x**4 - 2*x**2*y**2 - y**4))/(-l1**2 - 2*l1*l3 + l2**2 + 2*l2*x - l3**2 + x**2 + y**2))) - y)/(l1 + l3)), 2*atan((2*l2*y + sqrt(-l1**4 - 4*l1**3*l3 + 2*l1**2*l2**2 - 6*l1**2*l3**2 + 2*l1**2*x**2 + 2*l1**2*y**2 + 4*l1*l2**2*l3 - 4*l1*l3**3 + 4*l1*l3*x**2 + 4*l1*l3*y**2 - l2**4 + 2*l2**2*l3**2 + 2*l2**2*x**2 + 2*l2**2*y**2 - l3**4 + 2*l3**2*x**2 + 2*l3**2*y**2 - x**4 - 2*x**2*y**2 - y**4))/(-l1**2 - 2*l1*l3 + l2**2 + 2*l2*x - l3**2 + x**2 + y**2)))]

4つ解出てきた。えげつない。。。

解が正しく出ているかチェック

上記スクリプトをちょっと修正。一番上の解を使用。

# -*- coding: utf-8 -*-
import numpy as np
from numpy import sin,cos,pi,sqrt
from numpy import arcsin as asin
from numpy import arccos as acos
from numpy import arctan as atan
import matplotlib.pyplot as plt

def fk(l1, l2, l3, th1, th2):
    x2 = l2 * cos(th2) - (l1 + l3) * cos(th1)
    y2 = l2 * sin(th2) + (l1 + l3) * sin(th1)
    
    x1 = -l1 * cos(th1)
    y1 = l1 * sin(th1)

    return x1, y1, x2, y2

def fk_frame(l1, l2, l3, l4, l5, l6, l7, th1, th2, x1, y1, x2, y2):
    x3 = - l4 * cos(th2) - l1 * cos(th1)
    y3 = - l4 * sin(th2) + l1 * sin(th1)

    x4 = (l2 + l6) * cos(th2) - (l1 + l3) * cos(th1) - l7 * sin(th2)
    y4 = (l2 + l6) * sin(th2) + (l1 + l3) * sin(th1) + l7 * cos(th2)

    x5 = (l2 + l6) * cos(th2) - (l1 + l3) * cos(th1) + l7 * sin(th2)
    y5 = (l2 + l6) * sin(th2) + (l1 + l3) * sin(th1) - l7 * cos(th2)

    x_f1 = [0, -l4 * cos(th2), x3, x1]
    y_f1 = [0, -l4 * sin(th2), y3, y1]

    x_f2 = [x3, x1 - l5 * sin(th2), x2]
    y_f2 = [y3, y1 + l5 * cos(th2), y2]

    x_l = [x2, x4, x5, x2]
    y_l = [y2, y4, y5, y2]

    return x_f1, y_f1, x_f2, y_f2, x_l, y_l

# グラフの描画
def plot(x, y, x_f1, y_f1, x_f2, y_f2, x_l, y_l):
    fig = plt.figure()
    ax = fig.add_subplot(111)
    # リンクの描画
    plt.plot(x, y,"-g",lw=5,label="link")
    plt.plot(x_f1, y_f1,"-g",lw=5,label="link")
    plt.plot(x_f2, y_f2,"-g",lw=5,label="link")
    plt.plot(x_l, y_l,"-g",lw=5,label="link")
    # 関節の描画
    plt.plot(x, y,"or",lw=5, ms=10,label="joint")
    plt.plot(x_f1, y_f1,"or",lw=5, ms=10,label="joint")
    plt.plot(x_f2, y_f2,"or",lw=5, ms=10,label="joint")
    plt.plot(x_l, y_l,"or",lw=5, ms=10,label="joint")
    plt.xlim(-0.4, 0.4)
    plt.ylim(-0.1,0.4)
    plt.grid()
    plt.show()

def main(th1, th2):
    # リンクの長さ
    l1, l2, l3, l4, l5, l6, l7= 0.18, 0.16, 0.0, 0.05, 0.03, 0.07, 0.07

    # 第1, 2の関節角度
    # [th1, th2] = np.radians([110, 15])

    # 順運動学の計算
    x1, y1, x2, y2 = fk(l1, l2, l3, th1, th2)

    # ロボットアームのx座標, y座標をリストに格納
    x = [0, x1, x2]
    y = [0, y1, y2]

    x_f1, y_f1, x_f2, y_f2, x_l, y_l = fk_frame(l1, l2, l3, l4, l5, l6, l7, th1, th2, x1, y1, x2, y2)

    # ロボットアームの姿勢をグラフにプロット
    plot(x, y, x_f1, y_f1, x_f2, y_f2, x_l, y_l)

if __name__ == '__main__':
    # リンクの長さ
    l1, l2, l3, l4, l5, l6, l7= 0.18, 0.16, 0.0, 0.05, 0.03, 0.07, 0.07

    x = 0.15
    y = 0.15

    th = (asin((l2*sin(2*atan((2*l2*y - sqrt(-l1**4 - 4*l1**3*l3 + 2*l1**2*l2**2 - 6*l1**2*l3**2 + 2*l1**2*x**2 + 2*l1**2*y**2 + 4*l1*l2**2*l3 - 4*l1*l3**3 + 4*l1*l3*x**2 + 4*l1*l3*y**2 - l2**4 + 2*l2**2*l3**2 + 2*l2**2*x**2 + 2*l2**2*y**2 - l3**4 + 2*l3**2*x**2 + 2*l3**2*y**2 - x**4 - 2*x**2*y**2 - y**4))/(-l1**2 - 2*l1*l3 + l2**2 + 2*l2*x - l3**2 + x**2 + y**2))) - y)/(l1 + l3)) + pi, 2*atan((2*l2*y - sqrt(-l1**4 - 4*l1**3*l3 + 2*l1**2*l2**2 - 6*l1**2*l3**2 + 2*l1**2*x**2 + 2*l1**2*y**2 + 4*l1*l2**2*l3 - 4*l1*l3**3 + 4*l1*l3*x**2 + 4*l1*l3*y**2 - l2**4 + 2*l2**2*l3**2 + 2*l2**2*x**2 + 2*l2**2*y**2 - l3**4 + 2*l3**2*x**2 + 2*l3**2*y**2 - x**4 - 2*x**2*y**2 - y**4))/(-l1**2 - 2*l1*l3 + l2**2 + 2*l2*x - l3**2 + x**2 + y**2)))

    th1, th2 = th[0], th[1]

    main(th1, th2)

f:id:robonchu:20180121111446p:plain

あってる。sympy使いやすい。

アニメーションを作ってみる

import numpy as np
from numpy import sin,cos,pi,sqrt
from numpy import arcsin as asin
from numpy import arccos as acos
from numpy import arctan as atan

import matplotlib.pyplot as plt
import matplotlib.animation as animation
from matplotlib.animation import FuncAnimation

def fk(l1, l2, l3, th1, th2):
    x2 = l2 * cos(th2) - (l1 + l3) * cos(th1)
    y2 = l2 * sin(th2) + (l1 + l3) * sin(th1)
    
    x1 = -l1 * cos(th1)
    y1 = l1 * sin(th1)

    return x1, y1, x2, y2

def fk_frame(l1, l2, l3, l4, l5, l6, l7, th1, th2, x1, y1, x2, y2):
    x3 = - l4 * cos(th2) - l1 * cos(th1)
    y3 = - l4 * sin(th2) + l1 * sin(th1)

    x4 = (l2 + l6) * cos(th2) - (l1 + l3) * cos(th1) - l7 * sin(th2)
    y4 = (l2 + l6) * sin(th2) + (l1 + l3) * sin(th1) + l7 * cos(th2)

    x5 = (l2 + l6) * cos(th2) - (l1 + l3) * cos(th1) + l7 * sin(th2)
    y5 = (l2 + l6) * sin(th2) + (l1 + l3) * sin(th1) - l7 * cos(th2)

    x_f1 = [0, -l4 * cos(th2), x3, x1]
    y_f1 = [0, -l4 * sin(th2), y3, y1]

    x_f2 = [x3, x1 - l5 * sin(th2), x2]
    y_f2 = [y3, y1 + l5 * cos(th2), y2]

    x_l = [x2, x4, x5, x2]
    y_l = [y2, y4, y5, y2]

    return x_f1, y_f1, x_f2, y_f2, x_l, y_l


fig = plt.figure(1)
ax = fig.add_subplot(111, aspect='equal', autoscale_on=False, xlim=(-0.4, 0.4), ylim=(-0.1, 0.4))
ax.grid()

#th1 = [pi / 4] * 100
#th2 = np.linspace(- pi / 6, pi / 6, 100)

l1, l2, l3, l4, l5, l6, l7= 0.18, 0.16, 0.0, 0.05, 0.03, 0.07, 0.07

x0 = np.linspace(0.15, 0.2, 100) 
x1 = np.linspace(0.2, 0.2, 100)
y0 = np.linspace(0.15, 0.2, 100)
y1 = np.linspace(0.2, 0.25, 100)

x = np.append(x0, x1)
y = np.append(y0, y1)

ite_len = len(x)

# 90 < th1
th1 = asin((l2*sin(2*atan((2*l2*y - sqrt(-l1**4 - 4*l1**3*l3 + 2*l1**2*l2**2 - 6*l1**2*l3**2 + 2*l1**2*x**2 + 2*l1**2*y**2 + 4*l1*l2**2*l3 - 4*l1*l3**3 + 4*l1*l3*x**2 + 4*l1*l3*y**2 - l2**4 + 2*l2**2*l3**2 + 2*l2**2*x**2 + 2*l2**2*y**2 - l3**4 + 2*l3**2*x**2 + 2*l3**2*y**2 - x**4 - 2*x**2*y**2 - y**4))/(-l1**2 - 2*l1*l3 + l2**2 + 2*l2*x - l3**2 + x**2 + y**2))) - y)/(l1 + l3)) + pi
print th1
th2 = 2*atan((2*l2*y - sqrt(-l1**4 - 4*l1**3*l3 + 2*l1**2*l2**2 - 6*l1**2*l3**2 + 2*l1**2*x**2 + 2*l1**2*y**2 + 4*l1*l2**2*l3 - 4*l1*l3**3 + 4*l1*l3*x**2 + 4*l1*l3*y**2 - l2**4 + 2*l2**2*l3**2 + 2*l2**2*x**2 + 2*l2**2*y**2 - l3**4 + 2*l3**2*x**2 + 2*l3**2*y**2 - x**4 - 2*x**2*y**2 - y**4))/(-l1**2 - 2*l1*l3 + l2**2 + 2*l2*x - l3**2 + x**2 + y**2))
print th2

# 0 < 90 < th1
# th1 = -asin((l2*sin(2*atan((2*l2*y - sqrt(-l1**4 - 4*l1**3*l3 + 2*l1**2*l2**2 - 6*l1**2*l3**2 + 2*l1**2*x**2 + 2*l1**2*y**2 + 4*l1*l2**2*l3 - 4*l1*l3**3 + 4*l1*l3*x**2 + 4*l1*l3*y**2 - l2**4 + 2*l2**2*l3**2 + 2*l2**2*x**2 + 2*l2**2*y**2 - l3**4 + 2*l3**2*x**2 + 2*l3**2*y**2 - x**4 - 2*x**2*y**2 - y**4))/(-l1**2 - 2*l1*l3 + l2**2 + 2*l2*x - l3**2 + x**2 + y**2))) - y)/(l1 + l3))
# th2 = 2*atan((2*l2*y - sqrt(-l1**4 - 4*l1**3*l3 + 2*l1**2*l2**2 - 6*l1**2*l3**2 + 2*l1**2*x**2 + 2*l1**2*y**2 + 4*l1*l2**2*l3 - 4*l1*l3**3 + 4*l1*l3*x**2 + 4*l1*l3*y**2 - l2**4 + 2*l2**2*l3**2 + 2*l2**2*x**2 + 2*l2**2*y**2 - l3**4 + 2*l3**2*x**2 + 2*l3**2*y**2 - x**4 - 2*x**2*y**2 - y**4))/(-l1**2 - 2*l1*l3 + l2**2 + 2*l2*x - l3**2 + x**2 + y**2))

def two_link(th1, th2):
    l1, l2, l3, l4, l5, l6, l7= 0.18, 0.16, 0.0, 0.05, 0.03, 0.07, 0.07

    # [th1, th2] = np.radians([110, 15])

    x1, y1, x2, y2 = fk(l1, l2, l3, th1, th2)

    x = [0, x1, x2]
    y = [0, y1, y2]

    x_f1, y_f1, x_f2, y_f2, x_l, y_l = fk_frame(l1, l2, l3, l4, l5, l6, l7, th1, th2, x1, y1, x2, y2)

    return x, y, x_f1, y_f1, x_f2, y_f2, x_l, y_l

xl, yl, x_f1l, y_f1l, x_f2l, y_f2l, x_ll, y_ll = [], [], [], [], [], [], [], []

for t1, t2 in zip(th1, th2):
    x, y, x_f1, y_f1, x_f2, y_f2, x_l, y_l = two_link(t1, t2)
    
    xl.append(x)
    yl.append(y)
    x_f1l.append(x_f1)
    y_f1l.append(y_f1)
    x_f2l.append(x_f2)
    y_f2l.append(y_f2)
    x_ll.append(x_l)
    y_ll.append(y_l)
    
line1, = plt.plot([], [],"-g",lw=5,label="link")
line2, = plt.plot([], [],"-g",lw=5,label="link")
line3, = plt.plot([], [],"-g",lw=5,label="link")
line4, = plt.plot([], [],"-g",lw=5,label="link")
circle1, = plt.plot([], [],"or",lw=5, ms=10,label="joint")
circle2, = plt.plot([], [],"or",lw=5, ms=10,label="joint")
circle3, = plt.plot([], [],"or",lw=5, ms=10,label="joint")
circle4, = plt.plot([], [],"or",lw=5, ms=10,label="joint")

def update(i):
    line1.set_data(xl[i], yl[i])
    line2.set_data(x_f1l[i], y_f1l[i])
    line3.set_data(x_f2l[i], y_f2l[i])
    line4.set_data(x_ll[i], y_ll[i])

    circle1.set_data(xl[i], yl[i])
    circle2.set_data(x_f1l[i], y_f1l[i])
    circle3.set_data(x_f2l[i], y_f2l[i])
    circle4.set_data(x_ll[i], y_ll[i])
    
ani = animation.FuncAnimation(fig, update, ite_len, blit=False, interval=10, repeat=False)

plt.show()

matplotlibのanimation.FuncAnimationを用いて柔軟にアニメーション作成 - Qiita

Animation

pythonで二重振り子のアニメーションを作る – into the lambda

参考まとめ

物理計算エンジン

倒立振子のシミュレーション(スクラッチ)

simpy

アームリンク

↓是非時間を見つけて一度流したい

パラレルリンク

逆運動学

MoveIt!

新しいLinux PCの設定方法まとめ (ラズパイやTX2など)

やりたいこと

新しいLinuxPCをこさえた時に、英語キーボードだったり、sshしにくかったりするので、最低限必要な設定をまとめる。

今後ガンガン追記していく予定

ラズパイ

  1. SSH

    • raspi-configでsshの設定をonに
  2. キーボード:

TX2

  1. キーボード

  2. リモートデスクトップ

参考

TX2全般

リモートデスクトップ

sshでXを飛ばす方法

raspi x rosメモ

いつものまにかROSWIKIにraspiでのインストール方法書いてる。最高。

raspi3用 Ubuntu16 + rosのイメージ

raspi zerp用 rosのイメージ

参考

Installing ROS Indigo on the Raspberry Pi | Learning Robotics Using ROS

ラズパイで動くロボット「GoPiGo」をつかって遠隔見守りロボットを作ろう(1) 開発準備編 (1/6):CodeZine(コードジン)

snowboyで遊んでみる

やりたいこと

Hey , SiriやOK, GoogleのようなHotWordを変更して、音声認識を行いたい

snowboy

install & demo

ubuntu16.04でも動いた♪

  1. install -> https://s3-us-west-2.amazonaws.com/snowboy/snowboy-releases/ubuntu1404-x86_64-1.1.1.tar.bz2

  2. sudo apt-get install python-pyaudio python3-pyaudio sox

  3. pip install pyaudio

  4. Snowboy Hotword DetectionのCreate Hotwordでtest.pmdlを作成

  5. python demo.py test.pmdl

demo.py

import snowboydecoder
import sys
import signal

interrupted = False

def signal_handler(signal, frame):
    global interrupted
    interrupted = True

def interrupt_callback():
    global interrupted
    return interrupted

if len(sys.argv) == 1:
    print("Error: need to specify model name")
    print("Usage: python demo.py your.model")
    sys.exit(-1)

model = sys.argv[1]

signal.signal(signal.SIGINT, signal_handler)

detector = snowboydecoder.HotwordDetector(model, sensitivity=0.5)
print('Listening... Press Ctrl+C to exit')

detector.start(detected_callback=snowboydecoder.ding_callback,
               interrupt_check=interrupt_callback,
               sleep_time=0.03)

detector.terminate()

このdetected_callback=snowboydecoder.ding_callbackに自作関数を入れる。

そうすると、HotWordが入った時に関数が呼ばれる。

注意

Do not append () to your callback function: the correct way is to assign detected_callback=your_func instead of detected_callback=your_func(). However, what if you have parameters to assign in your callback functions? Use a lambda function! So your callback would look like: callback=lambda: callback_function(parameters).

参考

Snowboy Hotword DetectionをRaspberry Piで動かす - Qiita

tf-pose-estimationのコード理解

やりたいこと

tf-pose-estimationを用いた面白いタスクを作るため、tf-pose-estimationを理解する

GitHub - ildoonet/tf-pose-estimation: Openpose from CMU implemented using Tensorflow with Custom Architecture for fast inference.

いつのまにかROS対応してる。素晴らしい。

rosでの動かし方

  1. sudo apt-get update

  2. sudo apt-get upgrade

  3. sudo apt-get install ros-kinetic-video-stream-opencv

  4. sudo apt-get install ros-kinetic-image-view

  5. git clone https://github.com/ildoonet/ros-video-recorder.git

  6. git clone https://github.com/ildoonet/tf-pose-estimation.git

  7. pip install -U setuptools

  8. pip install -r tf-pose-estimation/requirements.txt

  9. catkin_make

  10. roslaunch tfpose_ros demo_video.launch

Tips

launchのモデルをmobilenetに変更するとCPU only でもかろうじて動く!

msg

BodyPartElm.msg

int32 part_id
float32 x
float32 y
float32 confidence

Person,msg

BodyPartElm[] body_part

Persons.msg

Person[] persons
uint32 image_w
uint32 image_h
Header header

broadcaster_ros.py

TfPoseEstimatorROSのノード

Personsのmsg型に変換

def humans_to_msg(humans):
    persons = Persons()

    for human in humans:
        person = Person()

        for k in human.body_parts:
            body_part = human.body_parts[k]

            body_part_msg = BodyPartElm()
            body_part_msg.part_id = body_part.part_idx
            body_part_msg.x = body_part.x
            body_part_msg.y = body_part.y
            body_part_msg.confidence = body_part.score
            person.body_part.append(body_part_msg)
        persons.persons.append(person)

    return persons

以下のようにしてpathを取得することができる

        w, h = model_wh(model)
        graph_path = get_graph_path(model)

        rospack = rospkg.RosPack()
        graph_path = os.path.join(rospack.get_path('tfpose_ros'), graph_path)

estimator.py

from estimator import TfPoseEstimator

画像から予測するスクリプト

class BodyPart:
    """                                                                                                                                        
    part_idx : part index(eg. 0 for nose)                                                                                                      
    x, y: coordinate of body part                                                                                                              
    score : confidence score                                                                                                                   
    """
    __slots__ = ('uidx', 'part_idx', 'x', 'y', 'score')

    def __init__(self, uidx, part_idx, x, y, score):
        self.uidx = uidx
        self.part_idx = part_idx
        self.x, self.y = x, y
        self.score = score

    def get_part_name(self):
        return CocoPart(self.part_idx)

    def __str__(self):
        return 'BodyPart:%d-(%.2f, %.2f) score=%.2f' % (self.part_idx, self.x, self.y, self.score)

で構成されたhuman情報を返す

新しいpythonの知識

slots``__slots__``を使ってメモリを節約 - Qiita

Pythonで__slots__を使う - StoryEdit 開発日誌

@staticmethod: Pythonの「@staticmethod」はどのように役立つのか - モジログ

def str_(self): str()メソッドは、print(x)するときにも呼び出される。

networks.py

from networks import get_graph_path, model_wh

def get_graph_path(model_name):
    return {
        'cmu_640x480': './models/graph/cmu_640x480/graph_opt.pb',
        'cmuq_640x480': './models/graph/cmu_640x480/graph_q.pb',

        'cmu_640x360': './models/graph/cmu_640x360/graph_opt.pb',
        'cmuq_640x360': './models/graph/cmu_640x360/graph_q.pb',

        'mobilenet_thin_432x368': './models/graph/mobilenet_thin_432x368/graph_opt.pb',
    }[model_name]


def model_wh(model_name):
    width, height = model_name.split('_')[-1].split('x')
    return int(width), int(height)

run_webcam.py

tf-pose-estimation/run_webcam.py at master · ildoonet/tf-pose-estimation · GitHub

引数

  • parser.add_argument('--camera', type=int, default=0) : カメラ番号の選択

  • parser.add_argument('--zoom', type=float, default=1.0) : zoom

  • parser.add_argument('--model', type=str, default='mobilenet_thin_432x368', help='cmu_640x480 / cmu_640x360 / mobilenet_thin_432x368') : モデルを選択できる。mobilenetが高速。

zoom

        if args.zoom < 1.0:
            canvas = np.zeros_like(image)
            img_scaled = cv2.resize(image, None, fx=args.zoom, fy=args.zoom, interpolation=cv2.INTER_LINEAR)
            dx = (canvas.shape[1] - img_scaled.shape[1]) // 2
            dy = (canvas.shape[0] - img_scaled.shape[0]) // 2
            canvas[dy:dy + img_scaled.shape[0], dx:dx + img_scaled.shape[1]] = img_scaled
            image = canvas
        elif args.zoom > 1.0:
            img_scaled = cv2.resize(image, None, fx=args.zoom, fy=args.zoom, interpolation=cv2.INTER_LINEAR)
            dx = (img_scaled.shape[1] - image.shape[1]) // 2
            dy = (img_scaled.shape[0] - image.shape[0]) // 2
image = img_scaled[dy:image.shape[0], dx:image.shape[1]]

Google AIY Voice Kitで遊んでみる

やりたいこと

音声でサーボモータやいろいろなデバイスを操作する

f:id:robonchu:20180113115837j:plain

設定

デモ

【Google AIY Voice Kit】Google Assistant APIの設定からデモプログラムの実行まで

Lチカ

Google AIY Voice Kitで電子工作~LEDライトを点灯~

日本語化

AIY Projects kitを試してみよう | スイッチサイエンス マガジン

現状、aiyライブラリの発話関数は日本語対応してなさそう

AIYスピーカーを、ほぼ日本語版Google Homeに【Google Assistant SDKアップデート】

Voice Kitなしで実行

AIY ProjectのVoice KitをVocie Kitなしでやってみた - 知的好奇心 for IoT

GCPサンプル

サンプル アプリケーション  |  Google Cloud Speech API ドキュメント  |  Google Cloud Platform

Cloud Speech API で音声をテキストに変換する

HotWord

Snowboy Hotword Detection

snowboy/examples/Python at master · Kitt-AI/snowboy · GitHub

Snowboy Hotword DetectionをRaspberry Piで動かす - Qiita

python - How to set up wake word for Google Assistant SDK on a Raspberry Pi - Stack Overflow