2019年4月8日月曜日

SonyのNeural Network Libraries(NNabla)でGPUを使ってみる


 マウスの進捗は何も出ていないのに、パーツ代で貯金が吹き飛んで行っている中の人です。今回はNNablaでGPUを使う話です。

 前回まででCPU上での学習及び推論ができるようになりました。ですが学習などは結構時間がかかることが多いですよね(18コア36スレとかでやればまた違うのかもしれませんが)。そこで、どこのご家庭にも転がっているであろうNvidiaのGPUをNNablaで使い、高速化してみようというのが今回の主題。

 NNablaでGPUを使う場合、CUDA及びcuDNNのインストールが必要になります。ここで注意したいのがCUDA及びcuDNNのバージョンで、ここを確認しておきましょう。

 次にNNablaからCUDA/cuDNNを利用するためのライブラリのインストールですが、

pip install nnabla-ext-cudaxx

で終了(cudaxxはCUDA/cuDNNのバージョンで変わる。ここを参照)。

 最後にコードの変更については(コードは前々回を参照)、ライブラリの追加とデフォルトの環境を設定するコードのみになります。ライブラリは

環境設定は

となります。一応これだけで動くはずです...。

参考:20171212 Sony Neural Network Libraries and Console for GTC Japan 2017

p.s.
突然GPUが読めなくなる(カーネルモジュールのロードがうまくいかなくなる)ことがあったんですが、どうやらセキュアブートが有効になっている環境ではロードさせないようになっているようです(回避すればいいのですが)。

©2018 shts All Right Reserved.

2019年3月27日水曜日

SonyのNeural Network Libraries(NNabla)でFCNもどきを動かす



 いろいろなことを同時に走らせて、全部中途半端になっている中の人です。マウスの設計とFPGA入門、バイトの教材開発を同時に進めるのはやめておきましょう。前回に引き続き今回もNeural Network Libraries(NNabla)でFCNを動かす話です。
 今回は実装編ですが学習編と結構似たコードになるので、学習用のコードから流用できます。やったぜ。  とりあえず必要なライブラリ群を読み込みます。
#-*-coding:utf-8-*-

import nnabla as nn
import nnabla.functions as F
import nnabla.parametric_functions as PF

import os
import sys
import cv2
import numpy as np

 学習ではsolversやinitializer、データセットを載せるためのdata_iteratorをimportしていましたが、今回は不要なので削除。データセット(npz)の読み込みはこの前と同じものを使用します。学習時になかったものとしては各ピクセルに割り当てられたラベルを画像に変換する関数を実装しました。(もっと頭良く組めるはずなんですが、僕には難しいです。)

def label2img(label):
    """
    * 1 | road        | blue 
    * 2 | out of road | green
    * 3 | line        | red
    * 4 | backgrownd  | black
    * 5 | object      | yellow
    * 6 | other rane  | white
    *
    * out   : 3-dimensional numpy array([ch][y][x])
    * buff  : 3-dimensional numpy array([1][y][x])
    * label : 4-dimensional numpy array([1][6][y][x])
    * color : [[B,G,R]]
    """
    color = np.array([[255,0,0],[0,255,0],[0,0,255],[0,0,0],[0,255,255],[255,255,255]])
    buff = np.argmax(label, axis = 1)
    out = np.zeros((3,buff.shape[1],buff.shape[2]))
    
    for i in range(len(color)):
        out[0][buff[0] == i] = color[i][0]
        out[1][buff[0] == i] = color[i][1]
        out[2][buff[0] == i] = color[i][2]

    return out.astype(np.uint8)

 ネットワークは学習時と同じものを使用してください。ここまでで必要な関数がそろいました。では実際に推論を走らせるコードに移ります。


try:
    #Loading Dataset
    train, teach = load_data(NPZ,"img","img_test")
    
    #Set Params to network
    nn.clear_parameters()
    x = nn.Variable(train[0:1].shape)
    y = network(x, test=True)
    t = nn.Variable(teach[0:1].shape)
    print("x:",x.shape, "y:", y.shape, "t:", t.shape)

    #Search if Params file or not
    if os.path.exists(param_file) == True:
        nn.load_parameters(param_file)
    else:
        print("Parameter file was not found!!!")
        sys.exit()

    #Test
    for i in range(train.shape[0]):
        x.d, t.d = train[i:i+1], teach[i:i+1]
        y.forward()

        input_img = x.d[0].transpose(1,2,0).astype(np.uint8)

        predict_img = y.d
        predict_img = label2img(predict_img).transpose(1,2,0)
        
        ground_truth_img = t.d
        ground_truth_img = label2img(ground_truth_img).transpose(1,2,0)
        
        show_img = np.concatenate((input_img, 
                                   predict_img, 
                                   ground_truth_img,
                                   ),axis=1)
        cv2.imshow("imshow", show_img[::-1,:,:])
        
        cv2.waitKey(1)

except:
    import traceback
    traceback.print_exc()

finally:
    input(">>")
    cv2.destroyAllWindows()

 load_data関数で推論させるデータを取り込みます。今回は入力画像、推論結果に加えて教師画像も載せたいので、ついでに取り込みます。
 その後パラメータの読み込みまでは学習時とほぼ同じです。学習済みパラメータの読み込み部のみ、パラメータがなかったらプログラムを終了できるように変えてあります。
 for分の中では実際に推論をしています。t.dに教師画像を入れてありますが、推論のみを行うのであれば不要になります。
 また推論自体はy.forward()で行われ、y.dに推論結果が入っています。あとの部分はcv2での画像表示に関する部分です。そこまで難しくはないはずですが、cv2で画像を表示させる場合、データ構造がNNabla側の(1, color, row, col)から(row, col, color)に代わるのでそれをimg2label関数とnp.transposeで変換しています。

 ここまでで推論部分が完成しました。学習部分さえできればその応用で推論ができるのは結構楽ですね(Chainerも似てるけど)。あとはおまけでGPUあたりのお話ができればいいかなぁ。
©2018 shts All Right Reserved.

2019年3月9日土曜日

SonyのNeural Network Libraries(NNabla)でFCNもどきを学習させる







 研究室配属も無事終了した中の人です。研究室の本格始動は4月からなので、3月中はマウスの設計やFPGA、NNablaと戯れたいと思います。さて、前の投稿ではNeural Network Libraries(NNabla)でnumpy-arrayの読み込みを行いました。そこで今回は読み込んだデータを使用して、FCNもどきの学習を行いたいと思います。

今回のコードもこちらのサイトを参考に実装していきます。

NNabla(Neural Network Libraries)のシンプルチュートリアルをPython3.5でやってみる。

NNablaで学習を行う場合、
  • データセットの読み込み
  • モデルの構築
  • 損失関数の定義
  • 学習部の実装
が必要になります(この辺はほかのライブラリとあまり変わらない)。まずはデータセットの読み込み、と見せかけて必要なライブラリ群のimportとデータセットを入れたファイル名、パラメータファイルから

import nnabla as nn
import nnabla.functions as F
import nnabla.parametric_functions as PF
import nnabla.solvers as S
import nnabla.initializer as I
from nnabla.utils.data_iterator import data_iterator_simple

import os
import numpy as np

NPZ = "data/img2train_data_test.npz"
param_file = "nnabla_parameters.h5"

 データセットの読み込みはこんな感じで実装
#Read .npz File
def load_data(npz, input="img", teacher="img_test"):
    print("loading dataset for training")
    #loading data from NPZ file
    with np.load(npz) as data:
        tmp_train = data[input]
        tmp_train_label = data[teacher]
    
    print(tmp_train.shape)
    print(tmp_train_label.shape)

    return tmp_train, tmp_train_label

#Loading Data
def data_iterator_my_dateset(train, teach, batch_size=8, shuffle=False, rng=None):
    def load_func(index):
         """Loading an image and its label"""
         img = train[index]
         label = teach[index]
         return img, label
    return data_iterator_simple(load_func, train.shape[0], batch_size, shuffle, rng, with_file_cache=False)

 .npzでデータセットを保持している関係で、それを読み込む関数を実装しました。下のデータセットの取り込みは前回と同じ。
 モデルはこんな感じの奴。
#Define network
def network(x):
    with nn.parameter_scope("cnn"):
        with nn.parameter_scope("conv0"):
            h = F.relu(PF.convolution(x, 6, (2,2)))
        with nn.parameter_scope("deconv0"):
            h = F.relu(PF.deconvolution(h, 3, (2,2)))
        with nn.parameter_scope("conv1"):
            h = F.relu(PF.convolution(x, 6, (4,8), stride=(2,4)))
        with nn.parameter_scope("conv2"):
            h = F.relu(PF.convolution(h, 16, (9,9), stride=(3,3)))
        with nn.parameter_scope("deconv2"):
            h = F.relu(PF.deconvolution(h, 16, (9,9), stride=(3,3)))
        with nn.parameter_scope("deconv1"):
            h = PF.deconvolution(h, 6, (4,8), stride=(2,4))
    return h

 Raspberry Piでそこそこ速く動かそうと思うと、こうなりました。ここはもっと手を入れる予定。損失関数はSigmoid Cross Entropyを使用。

#Define Loss Function
def loss_func(y, t):
    loss_f = F.sigmoid_cross_entropy(y, t)
    return loss_f
実の話をすると損失関数に最初はSoftmax Cross Entropyを使っていたのですが、要素(今回はピクセル)ごとのクラス分類がうまくいきませんでした。(ここで1週間溶ける)
 そこで公式のDCGAN実装を見たところ Sigmoid Cross Entropyを使っていたので、使ってみたところうまく学習できました。やったね!
(1つのピクセルが各ラベルに属するかどうかを見ているのでこれでもよいってだけで、Softmax Cross Entropyでも原理的にはできるはず)(参考:損失関数の紹介 - renom.jp)
 学習部はこんな感じ。
#Define Training Function
def training(xt,tt,data,loss,steps):
     solver = S.Adam()
     solver.set_parameters(nn.get_parameters()) # Set parameter variables to be updatd.
         
     for i in range(steps):
         xt.d, tt.d = data.next()
         solver.zero_grad() # Initialize gradients of all parameters to zero.
         loss.forward()
         loss.backward()
         solver.update()
         if i % 100 == 0: # Print for each 10 iterations
              print(str(i) +":" + str(np.mean(loss.d)))


 教師データ読み込み→とりあえず勾配を初期化→推論する→誤差逆伝播→パラメータを更新、を繰り返す感じ。後はこれらを実行していく形になります。

try:
    #Loading Dataset
    train, teach = load_data(NPZ,"img","img_test")
    data = data_iterator_my_dateset(train, teach, batch_size=30, shuffle=True)

    #Set Params to network
    nn.clear_parameters()
    img, label = data.next()

    x = nn.Variable(img.shape)
    y = network(x)
    t = nn.Variable(label.shape)
    loss = loss_func(y, t)

    #Search if Params file or not
    if os.path.exists(param_file) == True:
        yn = input("parameter is exist! use this? y/n : ")
        if yn == "Y" or yn == "y":
            nn.load_parameters(param_file)

    #Training
    training(x,t,data,loss,500)
    
except:
    import traceback
    traceback.print_exc()

finally:
    #Save Params
    nn.save_parameters(param_file)
    input(">>")

パラメータのクリアをモデル構築前にするのを忘れなければうまく動くはず...です。次回は実装になるはず。この記事長すぎるのでは?
©2018 shts All Right Reserved.

2019年3月1日金曜日

SonyのNeural Network Libraries(NNabla)でnumpy_arrayの読み込み



研究室がいまだ決まってない(後数時間なんですけどね)中の人です。前に投稿したSTM32でduty比をDMAで転送する話でも少し触れた、SonyのNeural Network Libraries(NNabla)を使って、Fully Convolutional Networksをやってみようと思います。



 NNablaは元々Sony内部で使われていたライブラリを公開したものらしいです。(詳しくはここを見てくれ)実の話をすると、本来はNeural Network Console(NNC)を使いたかったのですが(GUIでネットワークを記述するとか面白そう)、npzファイルで保存されている手持ちのChainer向けデータセットを転用したかったので今回はNNablaを使ってみることにしました。
 NNablaは組込み向けを意識しているのか、量子化に関するレイヤーが標準で実装されているので、今までChainerでやってきたやつを転用しようと考えた次第です。

 とりあえずチュートリアルと先人たちの解説を読みあさりつつ、サンプルをやってみました。今回はPython3.6のIDLEを使用しているので、公式チュートリアルコピペだと動かないことがありましたが、IDLEで実行している人がいました。ラッキー


NNabla(Neural Network Libraries)のシンプルチュートリアルをPython3.5でやってみる。


 このコードを参考にしてtiny_digitsによる学習はできたのですが、今度は独自のデータセットに対応させる必要があります。
いろいろ考えても進まないので、このサンプルコードで使用されているtiny_digitsのデータ構造を見ていきます。...といっても実態はnumpy-ndarrayなので、shapeで配列の各次元の要素数を確認しました。(参考:The Digit Dataset)

入力(image):(1797,8,8)
出力(target):(1797,)

ここで、オレオレデータセットのフォーマットを確認すると、

入力:((データ数),3,32,64)
出力:((データ数),6,32,64)

おっ、これだったらオレオレデータセットも読み込めそう...なのか?次元数違うけど大丈夫か...?というわけで、NNablaの公式リファレンスに飛び込んでみる。すると、

nnabla.utils.data_iterator.data_iterator_simple

の欄にload_funcの例が載っており、それが(ch, h, w)の画像の読み出しになっていました。これはオレオレデータセットの構造とほぼ同じなのでいけそうです。
 とりあえずそれを参考にしつつデータ読み込みの関数を書いてみました。

def data_iterator_my_dateset(train, teach, batch_size=8, shuffle=False, rng=None):
    def load_func(index):
         """Loading an image and its label"""
         img = train[index]
         label = teach[index]
         return img, label
    return data_iterator_simple(load_func, train.shape[0], batch_size, shuffle, rng, with_file_cache=False)

とりあえずデータ読み込みはこれでできました。やったぜ。この辺の話をやっている人をインターネッツでは見かけなかったので、結構苦労しました。(これだけで3h吹き飛んでる)
 多分今度の話は学習部分(というよりも使い方がよくわからなかったsoftmax_cross_entropy)になりそうです。


©2018 shts All Right Reserved.

2019年2月21日木曜日

PWMのduty比設定をDMAで行う(STM32F4)



 絶賛ひきこもり生活中の中の人です。ひきこもっている間何してたかといえばGT6、Twitter巡回、Youtube再生業といった時間の浪費とてもアクティブなことです。はい。まあ、それ以外だとSTM32をいじったり、nnablaってライブラリを触ってました。今回はSTM32の話です。(nnablaはそのうちブログ書くかも)


 STM32で複数のPWMを出そうとする時(唐突)、大体は
 
if (HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_1) != HAL_OK) {
    Error_Handler();
}

if (HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_2) != HAL_OK) {
    Error_Handler();
}

if (HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_3) != HAL_OK) {
    Error_Handler();
}

while (1) {
     for (i = 0; i < 100; i++) {
         __HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_1, i);
         __HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_2, 100 - i);
         __HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_1, i);
         __HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_2, 100 - i);
    }
}

みたいにTIMの初期設定→PWMのduty比をテキトーに変えていく感じになりますよね。
まあこれでもいいんですが、CubeMXで設定欄を見ていたら

?

何なんだと、こいつもDMA設定あるのかよ...。
というわけで本題。(今までの前振りの時間を返せ!)
DMAを使ってPWMを吐き出してみましょう。まずはCubeMX側の設定で、TIM本体の設定は同じ。今回はTIM1を使用します。



TIM1のDMA設定。この辺よくわかってないんで、ワタシエスティーエムチョットデキル方がいたら教えてくだせぇ。
次はプログラム側での話。どうやらdutyを設定する関数がなくて、PWMスタートとduty比設定が一緒って感じです。(求ム、有識者。コノ辺、ワカラン。)

while (1) {
    for (i = 0; i < 100; i += 2) {
        HAL_TIM_PWM_Start_DMA(&htim1, TIM_CHANNEL_1, (uint32_t *) &i, 1);
        htim1.State = HAL_TIM_STATE_READY;
        HAL_TIM_PWM_Start_DMA(&htim1, TIM_CHANNEL_2, (uint32_t *) &j, 1);
        htim1.State = HAL_TIM_STATE_READY;
        HAL_TIM_PWM_Start_DMA(&htim1, TIM_CHANNEL_3, (uint32_t *) &j, 1);
        htim1.State = HAL_TIM_STATE_READY;
    }
}

TIM1のStateをいじっているのは、duty比設定用の関数がHAL_TIM_STATE_READYの時のみduty比のセットを行えるため...らしい。イーノック、こんな解説で大丈夫か?
これで動くはず...です...。少なくとも僕のNucleoは動いたんだ...。





おまけ:
CeleronG3900 + 4GB RAM + GTX1060(6GB)って変態構成の自作PCをどうにかしたい(後赤く光るファンを追加したい)


©2018 shts All Right Reserved.

2019年2月15日金曜日

STM32F411でDMAを使ってSPI通信する話(MPU9250使用)



 卒論発表を偵察しに行ったら、他学部の学生がずっと質問している修羅場場面に遭遇した中の人です。
 前回はポーリングでMPU9250とSPIでお話ししていました。実はHALでは割り込みとDMAによるSPI通信が実装されており、今回はDMAを使ってみたいと思います。

 DMAを使ったSPI通信に関して基本的にポーリングの時と同じですが、細々とした設定があるので注意が必要です。

1.CubeMXの設定


 CubeMXでは、SPI通信をDMAで使うための設定が必要です。SPIのDMA SettingsにSPIx_RXとSPIx_TXを登録しておきましょう。

2.コード

基本的にポーリングと同じなのですが、お話しに使う関数が

        HAL_SPI_Transmit_DMA()
        HAL_SPI_Receive_DMA()

になります。関数名がhoge_DMA()となるのでわかりやすいです。
 MPU9250でお話しする場合、読み込みたい(書き込みたい)レジスタを送り、そのあとでデータを読みだす(書き出す)形になるので、書き込みx1と読み込みx1の組み合わせまたは書き込みx2を行う必要があります。ポーリングの場合読み出しを行う時は
 
uint8_t read_MPU9250(uint8_t addr) {
 uint8_t reg, val;
 reg = addr | 0x80;

 HAL_GPIO_WritePin(GPIOB, GPIO_PIN_2, GPIO_PIN_RESET);//CS
 HAL_SPI_Transmit(&hspi2, &reg, 1, 100);//Select reg
 HAL_SPI_Receive(&hspi2, &val, 1, 100);//Read data
 HAL_GPIO_WritePin(GPIOB, GPIO_PIN_2, GPIO_PIN_SET);//CS

 return val;
}

みたいな書き方になります。これをDMAを使ったものにすると、
 
uint8_t read_MPU9250_DMA(uint8_t addr) {
 uint8_t reg, val;
 reg = addr | 0x80;

 HAL_GPIO_WritePin(GPIOB, GPIO_PIN_2, GPIO_PIN_RESET);//CS
    HAL_SPI_Transmit_DMA(&hspi2, &reg, 1);//Select reg
 while (HAL_SPI_GetState(&hspi2) != HAL_SPI_STATE_READY);
 HAL_SPI_Receive_DMA(&hspi2, &val, 1);//Read data
 while (HAL_SPI_GetState(&hspi2) != HAL_SPI_STATE_READY);
 HAL_GPIO_WritePin(GPIOB, GPIO_PIN_2, GPIO_PIN_SET);//CS
 return val;
}

となります。...なんか追加されてますね。

HAL_SPI_GetState(&hspi2)

はSPIの使用状況を確認する関数で、これを入れることでSPIの通信待ちをしています。
頭悪い実装ですね。
 ポーリングの時とは異なり、完了待ちを入れておかないと読み出し先のレジスタを指定しながらデータを受信することになります。MPU9250の場合、先にレジスタを指定しないといけないので、正常な読み出しを行うことができません。

ここまで書けば大体動く...はずです。はい。動かなかったら教えてくだせぇ

3.その他

SPI通信が終了するとコールバック関数が呼ばれます。

HAL_SPI_RxCpltCallback()
HAL_SPI_TxCpltCallback()

これらのコールバック関数は弱参照されているので、別のファイルで別途中身を定義するのが望ましいです。こいつらにグローバル変数を仕込んで、終了フラグにしてもいいと思います。(別に使わなくても動きます。)
©2018 shts All Right Reserved.

2019年2月12日火曜日

STM32F411REでMPU9250を動かす(SPI)



学校に行こうとしても体がついていかず、結局ひきこもる生活をしてる中の人です。STM32の勉強用としてお家に生えてた落ちてたMPU9250をいじりだしたのですが、MPU9250をSPIで使った例がなかったのでかきかきしてみようかと思います。

今回はSTM32F411RE(Nucleo)とMPU9250(中華拡張ボードなんで詳細不明)を使っていきます。MPU9250を動かす流れは、大まかにこんな感じ。
  • WHO_AM_Iの読み出し
  • 起動
  • 出力設定
  • ジャイロ・加速度の設定
  • 角速度、加速度の読み出し
MPU9250は3軸加速度・3軸ジャイロのMPU6500と3軸地磁気のAK8963がセットになった9軸IMUなので、MPU6500と同じような使い方ができます(レジスタとかが違う)。

MPU9250をSPIで使うとき気を付けたいのはボーレートで、レジスタの読み取りのみであれば20MHzまで行けるようですが、書き込みまで行う場合、1MHz程度が限界となっています。

今回使ったNucleoボードの場合、

 hspi2.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_32;

と設定することで(CubeMXであればSPIのプリスケーラを32にする)ことで大体1.3MHzになります。(これでも一応動くけど、値の読み出しに失敗することがありそう)
この設定が終わったらread関数とwrite関数を実装するのですが、それはここを参考にしてください。

で、ここまで出来たら次はWHO_AM_Iを読み出す作業です。MPU9250は0x75のレジスタを読みに行くと、0x71が返ってくるはずです。

ここまでできれば、データの読出しはもうすぐです。とりあえずこの後の流れをまとめると、
0x6B(PWR_MGMT_1)のレジスタに0x00を書き込む

0x1A(CONFIG)のレジスタに0x00を書き込む

0x1B()のレジスタに0x18を書き込む(フルレンジを2000dpsに設定)

0x1C()のレジスタに0x18を書き込む(フルレンジを16gに設定)

 参考:MPU9250 Register Map
    9軸加速度センサー MPU9250をArduinoで制御する その1(I2C)
ここまでで設定が終了して、実際にデータの読み出しとなります。
データの読出しは、上位8bitのデータが入っているレジスタと下位8bitのデータが入っているレジスタの両方を読み出すことで完了します。read関数を2回実行し、上位8bitをシフトして下位8bitとのorを取ることで16bit分のデータが取得できます。やったね。


©2018 shts All Right Reserved.

2019年2月8日金曜日

Raspberry Pi向け拡張基板を作った(n回目)







 マウスそっちのけでいろいろやってる中の人です。突然ですが、Raspberry Piでモータを回したりLEDをPWM点灯させたいと思ったことがある人は僕だけではないはず(ないと思いたい)。RPiから高精度のPWMを出すのも結構大変ですよね(最近ではRPiのGPIOすべてから高精度のPWMを吐き出せるライブラリもあるみたいですが)。ADCとかモタドラとなるともはや拡張しないとだめですよね。
 そこで今回はI2Cで制御できるモータドライバICやLEDドライバ、おまけでADCをまとめて載せたてんこ盛り拡張ボードを作成してみました。(n=1の時の奴はこちら)
今回作成したのは、こんなやつ


裏面はこんな感じ


この拡張ボードに載せた(載せる予定の)ICはこんな感じ
すべてのICがI2C対応のICでRPiでの動作例が結構あることから今回これらを選びました。あとADC用のADS1015以外はアキバで手に入るやつなのではんだ付けに失敗しても大丈夫だったのが良かった点ですね。(ADS1015はアキバだとブレークアウトボードでしか手に入らない...)
 回路図はこんな感じ


 今回はPCA9685の動作確認用にAdafruitのライブラリを使い、DRV8830はI2Cライブラリ(python-smbus)を使ってデータを投げてます。DRV8830はもしかしたら自作ライブラリにするかも。









 P.S.:IKEAのサメさんみたいにまとまった休みが欲しい


©2018 shts All Right Reserved.

2019年1月26日土曜日

USB PD対応バッテリー(CYGNETT ChargeUp Pro 20000 PD)でXPS13(9360)を充電する話


期末テストも終わったはずなのに(主にバイトの案件で)胃がキリキリしている中の人です。さて今回はいつもとは異なり、クソでかモバイルバッテリーのレビューみたいな話です。


※このバッテリーはPSE認証を受けているか不明です。
 (PSEマークは確認できていません)

※このバッテリーを使用したことで発生した損害等に関する責任は負いません。

※参考程度にお願いします。


 そもそもこの話の発端はメイン機であるXPS13(9360)にUSB PD対応のUSB-Cポートがついていたことでした。このモデルには一応ACアダプタと充電専用端子が付属しており、最初はそれで充電していました。その後諸般の事情によりUSB-C対応の充電アダプタを使用するようになり、充電速度などの問題がないことが確認できたのでどんどんUSB-Cを活用していこうと考えました。

 このマシンは電源に接続していなくてもそこそこバッテリーだけで連続稼働してくれるのですが、前日充電し忘れて電車の中で使えない事態などがよく発生していました。(さすがに24h連続稼働は難しい)
 そこで考えたのがモバイルバッテリーで充電できないかという、一昔前では考えられないことでした。"まあUSBって名前ついてるしなんかあるでしょ"なんて思ってないんだからネ。
 ここでXPS13を充電するのに必要なスペックを考えると

  • USB-C対応
  • USB PD対応
  • 45W(20V 2.25A)出力以上
となります。結構えぐい仕様だな。容量に関しては補助電源としての使用を前提にしていたのでそこまで考えていませんでした。
 で、こんなバッテリーが売っているわけもなく早数か月、とある日に某倉庫店に行ったら見つけたのがこいつ
\6750は魅力的すぎでした。(当時秋葉でもこのコスパの奴は見たことがなかった)。一応XPS13は対応機種に入ったのですが、モデルまでは不明でした。で、早速買ってきて(\3000引きだったのは想定外)試してみました...
充電できてるじゃん...なんだこいつ...
何度か使用してみて、XPSの場合大体10%から80%ぐらいまで充電できる感じでした。(正確な測定ではない)
とりあえず出先でのバッテリー切れは解決できそうです。


©2018 shts All Right Reserved.

2018年12月31日月曜日

2018年を振り返ると見せかけて2019年にやりたいことをチラ見せ


2018年の後半からの記憶があいまいな中の人です。2018年も残すところ数時間となりました。いかがお過ごしでしょうか?


 振り返ると2018年もいろいろありました。クラシックマウスが完走したり、手書きれぽーよから解放されたり、夏のインターンで某S社に行ったり、TOEICで点数下がったり、実験棟に人が登ってるのを眺めたり、ルンバ君導入したりと様々なことがありました。 また、いろいろな方々に会う機会が得られたのもよかったなぁと思います。
というわけで振り返りもそこそこに2019年に放棄する完成するであろうモノの一部をテキトーに上げておきます。
EV3のネタもそのうち披露できるかもです。(バイトとの兼ね合いがぁ)
マイクロマウスはハーフを作成予定
趣味はテキトーに作成予定です。
それでは皆さん、Happy Holidays!
©2018 shts All Right Reserved.

2018年12月11日火曜日

MatplotlibにGUI(Tkinter)を組み合わせる話




 本記事はMice Advent Calendar 2018の11日目の記事です.昨日の記事はNse先輩のブラウザ上で動く無償3D-CAD「Onshape」を使おうでした.データの引継ぎをしなくてもいいのはなかなか魅力的ですね.しゅごい.

 紹介遅れました,全日本終わったのにブログすら書いていなかった中の人です.ステッパーマウスで40位という順位をどう見るかは人によって変わるかと思いますが,5本中4本完走したんでまあ悪くはないかなって感じです.



 さてさて本題に戻りまして,Matplotlibのそこそこ楽な描画機能があるのでシミュレータとして扱うのは楽なのですが,GUI機能が限られているためボタンを追加して再描画するといったことはMatplotlibだけでは出来ません.
 そこでMatplotlibの拡張機能を使用してPythonのGUIライブラリであるTkinterと連携し自分でGUI機能を追加しようというのがテーマです.連携もなにもMatplotlibがTkinter使ってるんだからできるに決まってるなんて思うんじゃないゾ

一応本記事中のコードはGitHubに上がっているので参考にしてください.

1.基本となるコード


 この記事ではこのコードを基本にやっていきます.

#-*-coding:utf-8-*-
"""
参考 http://b4rracud4.hatenadiary.jp/entry/20181207/1544129263
"""

import numpy as np
import matplotlib.pyplot as plt

gridSize = 2 #マスの数を指定

if __name__ == "__main__":
    try:
        plt.gca().set_aspect('equal', adjustable='box')
        gridSize = (gridSize * 2 + 1) #半区画の区切りを算出t


        #区画の描画
        for i in np.array(range(gridSize)) * 90.0:
            plt.plot(np.array([i, i]), np.array([0.0, (gridSize - 1) * 90]), color="gray", linestyle="dashed")
            plt.plot(np.array([0.0, (gridSize - 1) * 90]), np.array([i, i]), color="gray", linestyle="dashed")

            #斜めの線の描画
            if (i / 90.0) % 2 == 1:
                plt.plot(np.array([0.0, i]), np.array([(gridSize - 1) * 90 - i, (gridSize - 1) * 90]), color="gray", linestyle="dashed")
                plt.plot(np.array([(gridSize - 1) * 90 - i, (gridSize - 1) * 90]), np.array([0.0, i]), color="gray", linestyle="dashed")

                plt.plot(np.array([(gridSize - 1) * 90, i]), np.array([i, (gridSize - 1) * 90]), color="gray", linestyle="dashed")
                plt.plot(np.array([i, 0.0]), np.array([0.0, i]), color="gray", linestyle="dashed")
       
        plt.show()
    except:
        import traceback
        traceback.print_exc()
    finally:
        input(">>")#エラー吐き出したときの表示待ち

このコード自体はMice Advent Calendar 2018の7日目の記事の迷路の描画をnマス対応にしたものです.今回はこの"nマス"をGUIから指定して描画できるようにします.(わからなかったらリンク先を見よう!)

2.Tkinterにグラフを載せる


 まずはグラフをTkinterの描画機能で表示させます.Matplotlibの開発元が公開しているコードに従っていじっていきます.流れとして,TkinterのGUIクラス(つまりGUIの部品を載せる台みたいなやつ)を作成してその上に描画したいグラフを載せる感じです.
 先ほどのコードにライブラリを追加していきます.必要なものは

import numpy as np
import tkinter
import matplotlib.pyplot as plt
from matplotlib.backends.backend_tkagg  import FigureCanvasTkAgg

です.先ほど使用していたnumpyとmatplotlibにTkinterと連携用のライブラリを追加しました.次にtry文の中にGUIに関する諸々の設定を書いていきます.まずはGUIの要素を載せる"台"改めウィンドウを宣言します.

if __name__ == "__main__":
    try:
        #GUIの生成
        root = tkinter.Tk()
        root.title("にゃーん")

はい,たったこれだけです.最初の2行はただのおまじないGUIの生成には関係ない部分なので下2行がGUIの生成に関与しています.titleはウィンドウの名前になります.


次にグラフの設定を行います.これは先ほどと同じです.

        #グラフの設定
        fig,ax = plt.subplots()
        fig.gca().set_aspect('equal', adjustable='box')#グラフ領域の調整
        gridSize = (gridSize * 2 + 1) #半区画の区切りを算出t

そしてこのグラフを台に乗るような部品へ変換するための設定を行います.

        #キャンバスの生成
        Canvas = FigureCanvasTkAgg(fig, master=root)
        Canvas.get_tk_widget().grid(row=0, column=0, rowspan=10)

FigureCanvasTkAggによってGUIの部品へ変換し,その下の行でウィンドウ内の位置を決めています.そうしたら線を引いていきましょう.

        #区画の線を引く
        for i in np.array(range(gridSize)) * 90.0:
            ax.plot(np.array([i, i]), np.array([0.0, (gridSize - 1) * 90]), color="gray", linestyle="dashed")
            ax.plot(np.array([0.0, (gridSize - 1) * 90]), np.array([i, i]), color="gray", linestyle="dashed")

            #斜めの線を引く
            if (i / 90.0) % 2 == 1:
                ax.plot(np.array([0.0, i]), np.array([(gridSize - 1) * 90 - i, (gridSize - 1) * 90]), color="gray", linestyle="dashed")
                ax.plot(np.array([(gridSize - 1) * 90 - i, (gridSize - 1) * 90]), np.array([0.0, i]), color="gray", linestyle="dashed")

                ax.plot(np.array([(gridSize - 1) * 90, i]), np.array([i, (gridSize - 1) * 90]), color="gray", linestyle="dashed")
                ax.plot(np.array([i, 0.0]), np.array([0.0, i]), color="gray", linestyle="dashed")
        
        Canvas.draw()  #キャンバスの描画
        root.mainloop()#描画し続ける

ここで重要なのが最後の2行で,Matplotlibにおいてグラフの描画はplt.show()で行っていたかと思いますが,Tkinterを使用した場合はGUIの部品へ変換したものにある.draw()を実行して描画を行ってください.また最後の行がないと一瞬でGUIの表示が消えます.
 後は諸々の処理を付け加えれば完成です.

#-*-coding:utf-8-*-
"""
参考
    http://b4rracud4.hatenadiary.jp/entry/20181207/1544129263
    https://matplotlib.org/gallery/user_interfaces/embedding_in_tk_sgskip.html
"""

import numpy as np
import tkinter
import matplotlib.pyplot as plt
from matplotlib.backends.backend_tkagg  import FigureCanvasTkAgg

gridSize = 2 #マスの数を指定

if __name__ == "__main__":
    try:
        #GUIの生成
        root = tkinter.Tk()
        root.title("にゃーん")

        #グラフの設定
        fig,ax = plt.subplots()
        fig.gca().set_aspect('equal', adjustable='box')#グラフ領域の調整
        gridSize = (gridSize * 2 + 1) #半区画の区切りを算出

        #キャンバスの生成
        Canvas = FigureCanvasTkAgg(fig, master=root)
        Canvas.get_tk_widget().grid(row=0, column=0, rowspan=10)

        #区画の線を引く
        for i in np.array(range(gridSize)) * 90.0:
            ax.plot(np.array([i, i]), np.array([0.0, (gridSize - 1) * 90]), color="gray", linestyle="dashed")
            ax.plot(np.array([0.0, (gridSize - 1) * 90]), np.array([i, i]), color="gray", linestyle="dashed")

            #斜めの線を引く
            if (i / 90.0) % 2 == 1:
                ax.plot(np.array([0.0, i]), np.array([(gridSize - 1) * 90 - i, (gridSize - 1) * 90]), color="gray", linestyle="dashed")
                ax.plot(np.array([(gridSize - 1) * 90 - i, (gridSize - 1) * 90]), np.array([0.0, i]), color="gray", linestyle="dashed")

                ax.plot(np.array([(gridSize - 1) * 90, i]), np.array([i, (gridSize - 1) * 90]), color="gray", linestyle="dashed")
                ax.plot(np.array([i, 0.0]), np.array([0.0, i]), color="gray", linestyle="dashed")
        
        Canvas.draw()  #キャンバスの描画
        root.mainloop()#描画し続ける
    except:
        import traceback
        traceback.print_exc()
    finally:
        input(">>")#エラー吐き出したときの表示待ち

 とりあえずTkinter上で表示できたかと思います.(Matplotlibとの違いは下のボタンとウィンドウの名前ぐらいかと思いますが)
ただ×ボタンを押しても消えない症状が出ました.(Ctrl+Cもうまく動かないのなんだろ)

3.終了ボタンとかをつける



 ここまでやってきて強制終了しかできないのは悲しいです.というわけで終了ボタンを付けましょう....といきたかったのですが,説明するのだるいぉ.実は実装を大きく変えたためコードの説明に追加で1記事ぐらい費やしそうなのです.(とはいえコピペして改変するだけなので解読は可能かと思います)とりあえずコードだけ置いときます.

#-*-coding:utf-8-*-
"""
参考
    http://b4rracud4.hatenadiary.jp/entry/20181207/1544129263
    https://matplotlib.org/gallery/user_interfaces/embedding_in_tk_sgskip.html
    https://pg-chain.com/python-tkinter-entry
"""
import numpy as np

import tkinter
import tkinter.messagebox as tkmsg

import matplotlib.pyplot as plt
from matplotlib.backends.backend_tkagg  import FigureCanvasTkAgg

from functools import partial

def Quit():
       root.quit()
       root.destroy()

def DrawCanvas(canvas, ax, colors = "gray"):
    value = EditBox.get()
    if value != '':
        EditBox.delete(0, tkinter.END)
        ax.cla()#前の描画データの消去
        gridSize = int(value)
        gridSize = (gridSize * 2 + 1) #半区画の区切りを算出
        
        #区画の線を引く
        for i in np.array(range(gridSize)) * 90.0:
            ax.plot(np.array([i, i]), np.array([0.0, (gridSize - 1) * 90]), color=colors, linestyle="dashed")
            ax.plot(np.array([0.0, (gridSize - 1) * 90]), np.array([i, i]), color=colors, linestyle="dashed")

            #斜めの線を引く
            if (i / 90.0) % 2 == 1:
                ax.plot(np.array([0.0, i]), np.array([(gridSize - 1) * 90 - i, (gridSize - 1) * 90]), color=colors, linestyle="dashed")
                ax.plot(np.array([(gridSize - 1) * 90 - i, (gridSize - 1) * 90]), np.array([0.0, i]), color=colors, linestyle="dashed")

                ax.plot(np.array([(gridSize - 1) * 90, i]), np.array([i, (gridSize - 1) * 90]), color=colors, linestyle="dashed")
                ax.plot(np.array([i, 0.0]), np.array([0.0, i]), color=colors, linestyle="dashed")
           
        canvas.draw()  #キャンバスの描画

if __name__ == "__main__":
    try:
        #GUIの生成
        root = tkinter.Tk()
        root.title("あー、てすてす")

        #グラフの設定
        fig,ax1 = plt.subplots()
        fig.gca().set_aspect('equal', adjustable='box')#グラフ領域の調整

        #キャンバスの生成
        Canvas = FigureCanvasTkAgg(fig, master=root)
        Canvas.get_tk_widget().grid(row=0, column=0, rowspan=10)

        #テキストボックスに関する諸々の設定
        EditBox = tkinter.Entry(width=5)#テキストボックスの生成
        EditBox.grid(row=1, column=2)

        #ラベルに関する諸々の設定
        GridLabel = tkinter.Label(text="ますめ")
        GridLabel.grid(row=1, column=1)

        #ボタンに関する諸々の設定
        ReDrawButton = tkinter.Button(text="こうしん", width=15, command=partial(DrawCanvas, Canvas, ax1))#ボタンの生成
        ReDrawButton.grid(row=2, column=1, columnspan=2)#描画位置(テキトー)

        QuitButton = tkinter.Button(text="やめる", width=15, command=Quit)#ボタンの生成
        QuitButton.grid(row=7, column=1, columnspan=2)#描画位置(テキトー)
        
        DrawCanvas(Canvas,ax1)
        root.mainloop()#描画し続ける
    except:
        import traceback
        traceback.print_exc()
    finally:
        input(">>")#エラー吐き出したときの表示待ち


追加した部分はボタン周りやテキストボックスなどです.ボタンによるアクションは先に関数として宣言したうえで各ボタンに登録しておきます(コールバック関数).引数等の問題はfunctoolsライブラリのpartialを引っ張てきて解決しました.×ボタンに関してはQuitButtonのコールバック関数としてQuit()を登録しておきました.

 まあいろいろいじって自分好みにカスタムしてみてください.次回はnorthernfox2先輩の「今年のマウスと教訓」です.そういえば今年の反省してなかったなぁ(れぽーよしか思い浮かばない...).
©2018 shts All Right Reserved.

2018年10月21日日曜日

OpenCV(Python版)で作るペイントツール



全日本学生完走した後マウス君とほとんど戯れていない中の人です。 今回はFCN用のデータセット作成ツールをPython-OpenCVで作ったのでその解説。 FCNに関してはこちらをみてください。
1.データのフォーマット
FCNの訓練データはこんな感じのものを使用しています。(オレオレデータセットってやつです)

入力画像はそのまま使用しますが、出力画像はこんな感じで変換しています。

入力画像からエッジを検出したのち、領域にタグをつける(≒色ぬりぬり)作業を行って出力画像を得ます。 で、この色ぬりぬり作業が相当めんどくさいんです。
エッジを得る段階で、適切なエッジを得られない、不必要なエッジが含まれる、領域が閉じていないなど様々な問題が出てくるので、実際には入力画像と見比べて手作業で補正します。この補正がずれまくる...。

ということでこの手作業をそこそこ楽にするツールを作成しました。...といってもトレース台みたいなツールです。
機能としては
・透かし
・点を書く
・塗りつぶし
です。とりあえず次回から機能の解説をしていきたいと思います。
ちなみに,コードはこちらから
©2018 shts All Right Reserved.

2018年9月16日日曜日

SH7125の割り込み優先度について



夏休みが終わって虚無感に襲われてる中の人です。
私事ではございますが、東日本大会をなぜか完走したため晴れてクラシックマウサーになってしまいました。よく完走したな

東日本が終了しインターンシップの関係で1週間気絶した後、かねてより懸案だったマウス君の速度があってない問題の解決を図ったのでその時のメモ。


1.どんな問題だったか
私のマウス君はステッピングモータを使用しているのですが、指定したモータ速ではない、より低い速度(100mm/sぐらい低い)で速度が上がらなくなる症状が発生していました。目標速設定周り、パルス周波数導出式にはバグはないようだったので何か別の部分に原因がありそうでした。

2.原因(と思しきもの)
速度導出系・速度代入系に異常がなかったので、割り込み周りの設定を確認しました。
まずはCMTやMTU2の割り込み内部で処理落ちしていないかどうかを確認しましたが、問題はなさそうでした。
そこでCMTやMTU2の設定を見直すことにしました。そしてMTU2の割り込み優先度をCMTのそれより上げた結果、目標回転速に達することが判明しました。

SH7125の場合、割り込み優先度の処理は以下の手順を踏んでいるようです。

・事前に設定された割り込み優先度に応じて処理を始める(割り込み優先度の設定レジスタは分かれているが、すべての割り込みの優先度を一括で決めている)
 ↓
・設定された割り込み優先度が同じとき、元々の優先度(データシート参照)に応じて割り込み処理を行う

また、割り込み実行時に別の優先度が低い割り込みが入ろうとしたときの挙動は調査中ですが、今回の問題から恐らく、あとから来た割り込みは破棄されるか待ちぼうけを食わされるようです。

つまりCMTの割り込みが走っている状態で優先度が低いMTU2が割り込もうとして失敗したため、MTU側の出力パルスの周期が長くなり、結果としてモータが遅く回ることになったと考えられます。

マイコン難しすぎ...にゃーん


©2018 shts All Right Reserved.

2018年7月4日水曜日

FP16とFP32で重みの型を変えた話



実験がツラい中の人です.

今回は前々から組んでいたFCNの高速化に関するネタ.
Chainerで何も設定せずにモデルを作成すると重みやバイアスのデータはfloat32で作られるのですが,設定を変更することで重みやバイアスのデータ型をfloat16に変更することができます.今回はデータ型を変更した時の推論にかかる時間への影響について考えてみます.





FP16 : 0.096[sec]
FP32 : 0.069[sec]
(30回平均)
あれ,FP16のほうが遅い...
FP16とFP32が同じぐらい時間がかかるなら,SIMDとかやらずに単純に計算しただけって解釈できるのですが,FP16が遅いってことは...

高速化もされていないなら...命令セット周りか...
どうやらFP16から型変換して演算→結果をFP16に直すってことらしい.

..FP16サポートしてよ...

おまけ モデルのサイズ
Chainerではモデルの保存ができますが,この時のデータサイズを比較すると...
FP32 : 12KB
FP16 : 7KB
こちらは至極当然といった感じ.
(NPZ形式での値,モデルの構成を変えるといろいろ変わると思われます.)



2018年6月20日水曜日

Matplotlibで明朝体を使えるか

はい,中の人です.
今回はMatplotlibの軸ラベルに明朝体を使おうとした話です.



0.今回使うグラフ
今回は以下のコードを改造しながら進めていきます.(詳しい説明はmatplotlibを紹介しているページへ)

import numpy as np
import matplotlib.pyplot as plt

t = np.linspace(-2 * np.pi,2 * np.pi,num=101)
y = np.sin(t)
plt.plot(t,y)

plt.xlabel(u"時間$t$")
plt.ylabel(u"変位$y$")

plt.show()




1.概要
Matplotlibでは軸ラベルの設定ができますが,初期設定のフォントでは日本語を入れると変な文字が出てくるはずです.
そこでこの"変な文字"を回避するため,日本語対応フォントを導入して日本語を表示させてみましょう.

2.やってみた
Matplotlibだとフォント変更は以下の二通りがあります.
①rcParamsでフォントを変える
②font_managerで"なんとか.ttc"を直接参照する

①rcParamsを使ってフォントを変える.
rcParamsを使う場合,最初のコードは以下のようになります.


#-*-coding:utf-8-*-
import matplotlib.pyplot as plt
import numpy as np

plt.rcParams["font.family"] = "Yu Mincho"
plt.rcParams["mathtext.fontset"] = "cm"

t = np.linspace(-2 * np.pi,2 * np.pi,num=101)
y = np.sin(t)
plt.plot(t,y)

plt.xlabel(u"時間$t$")
plt.ylabel(u"変位$y$")

plt.show()

これはmatplotlibの設定ファイル(matplotlibrc)を書き換えることでフォントを読み込ませる方式です.この場合,数式フォントと普通の文字のフォントを別々に設定できます.
しかし設定できるフォントに限りがあり,以下のコードで調べられます.


#-*-coding:utf-8-*-
import matplotlib.font_manager as fm

fonts = fm.findSystemFonts()
for f in fonts:
    font = fm.FontProperties(fname=f)
    print(font.get_name())
input(">")


②font_managerで"なんとか.ttc"を直接参照する
font_managerを使う場合は以下のようになります.


#-*-coding:utf-8-*-
import matplotlib.pyplot as plt
import matplotlib.font_manager
import numpy as np

fp = matplotlib.font_manager.FontProperties(fname="C:\Windows\Fonts\msmincho.ttc")

t = np.linspace(-2 * np.pi,2 * np.pi,num=101)
y = np.sin(t)
plt.plot(t,y)

plt.xlabel(u"時間$t$", fontproperties=fp)
plt.ylabel(u"変位$y$", fontproperties=fp)

plt.show()

この場合,"なんとか.ttc"さえ参照できればフォントを適用できることができます..ttcファイルであればフォントの制限もありませんが,数式はデフォルトのフォントが当てられます.

3.完走した感想
もう英語でいいや




©2018 shts All Right Reserved.

2018年6月10日日曜日

Raspberry Pi 向けモータ制御基板を作ってみた


レポートに発狂しながら生きている中の人です。

少し前にラズパイ向け(というよりArduino Pro Micro向け)の拡張ボード的なものを作ったのですが、その紹介。






1.そもそもの作成理由
Raspberry Piで生成できるPWMの精度があまり良くなかったので、よりきれいなPWMが作れお手軽にコードが書けそうなArduinoを使ってサーボとかモータードライバとかの制御をやってみたかった。
ついでにプリント基板化もしておこうと思った次第です。

2.設計
今回、ArduinoとRaspberry Piの通信部分はUSB経由のUARTにしたので、そこの配線は不要でした。(というよりArduino Pro MicroのUARTピンがうまく使いこなせなかったOTL。)
モータードライバは、i2Cでモータの電流が制御できるDRV8830を二つ使用しました。秋月で取り扱っているのもよかったですね。モータドライバを二つ乗せたのは、今後別のことにも転用できるようにするためです。

RaspberryPiからはi2cで使えるキャラクタ液晶とUARTのピンを引き出しています。液晶はIPアドレス確認用で、UARTはSSHがうまくいかないときのバックアップとしてPCとの通信に使います。

電源ボードはAdafruitのPowerBoost 1000 basicを使用し、1SのLi-poから5Vに昇圧しています。5V1Aぐらいあっても、モータの駆動は若干厳しいです。
電源回りでいえば、Raspberry Piの電源も一緒にしたかったのですが、電源が足りなくなるのとGPIOからの給電がうまくいかなかった関係で別系統にしました。

3.作成

今回もE社に投げ込みました。DRV8830のパッド-パッド間が12milより狭かったので、怒られるのではないかと思っていましたが、難なく仕上げてきました。(恐ろしい)
初めてヒートパッドのついたICのはんだをしたのですが、
①パッドにスルーホールを設けておく。
②パッドが薄くはんだでコーティングされる程度にパッドと穴にはんだを流し込む。(穴は埋める)
③パッドにフラックスを塗り、ICの位置を決め、マスキングテープで固定。
④裏返しにしてスルーホールにはんだごてをあて、固定する。
⑤固定されたら再度ひっくり返して、マスキングを外し、フラックスをICの足に塗る。
⑥ICの足をはんだ付けする。
ってやったら一応ついたようでした。(正しい手順が知りたい)

4.動作確認
正常に動いたので一安心です。

5.改善点
とりあえずヒートパッドの裏の穴はもっと小さくてよかったことと、DRV8830だったらRaspberry Piからi2Cを使って叩けるので、i2CかSPIのPWM生成ICかなんかがあればArduinoが不要なる点でしょうかね。
Arduinoを使うなら、アナログピンやデジタルピンを引き出して、センサなどをさらに追加できたらよりよかったですね。
あっ,i2C線にプルダウン抵抗入れ忘れてました...OTL

6.まとめ
ソフト、ハードともに基礎研究は終了したので、今度は実際に組立てて走らせ、データ収集とデータ加工をしないといけないですね...
©2018 shts All Right Reserved.

2018年5月27日日曜日

Arduinoのシリアル通信で、カンマ区切りの文字列を読ませる

突然ですが、今回はArduinoのシリアル通信でカンマ区切りの文字列を扱う話です。

パラメータの送信とかで使いたくなるカンマ区切りのデータですが、意外とお手軽に実装できたので紹介したいと思います。





1.解読の流れ
解読の流れとしてはこんな感じ
①シリアル入力をバッファに突っ込む
②strtok関数でトークンに分解して、各変数に読み込む
③atoi関数で数値に変換


2.実装
int angle = 0, mot_sta = 0, power = 0, i = 0;
char buff[30];

void setup() {
  Serial.begin(9600);
}

void loop() {
  if (Serial.available() > 0) {
    buff[i] = Serial.read();
    if (buff[i] == 'e') {
      buff[i] == '\0';
      angle = atoi(strtok(buff, ","));
      mot_sta = atoi(strtok(NULL, ","));
      power = atoi(strtok(NULL, ","));

      Serial.println(angle);
      Serial.println(mot_sta);
      Serial.println(power);
      i = 0;
    } else {
      i += 1;
    }
  }
}

今回のプログラムはangle、mot_sta、powerの3つの変数に値を代入するモノです。
Arduino側に送られてくるフォーマットはこんな感じ

10,20,30,e

末尾の"e"はデータの終端を表す信号で、こいつが出るまでバッファに送られてきたデータを書き出します。
そのあと、strtok関数でバッファの中身を解読します。この関数は一回文字列に対して実行するごとに1つずつトークン(のポインタ)を返します。また2回目以降は対象の文字列を"NULL"にしてあげる必要があります。
それと並行してトークン(のポインタ)をatoi関数に入れることでint型の数値が得られます。atofを使えばfloat型として数値が得られるようです。



今回はここを参考にしました。
http://www9.plala.or.jp/sgwr-t/lib/strtok.html


©2018 shts All Right Reserved.

2018年5月23日水曜日

draw.ioで数式を打ち込む

れぽーよ地獄にサヨナラしたい中の人です。
今回はれぽーよで図を描くときによく使っているdraw.ioの話。

2018/5/23 22時 追記





0.draw.ioとは
多種多様な図を書くことができるオンライン上のツールです。
(e.g.回路図、フローチャート、家の図面的なもの)

1.何がしたいか
今回のれぽーよ課題で図を描いたのですが、同時に数式を入れないといけなくなりました。というわけで、draw.io内での数式の書き方を書いていきます。

2.やり方
1)draw.ioを開く
    とりあえず、ここからdraw.ioを開きましょう。

    最初にこんな画面が出ると思うので、"新規ファイルを作成する"を選択。

    次にこの画面になるはずです。いくつかのテンプレートが用意されていますが、
    今回は"白紙ファイル"で行きます。
    名前はここで決めても、後からxmlファイルで出力するときに決めてもよいので、
    とりあえず"名称未設定ファイル"行きます。
    そして、右下の作成するボタンを押してください。

2)数式入力を有効にする

    多分こんな画面になったはずです。
    そうしたらどこでもいいので右クリックしてメニューを出しましょう。

    メニューの一番下のオプションから数式組版にチェックを入れることで数式入力ができるようになります。

3)数式を書く
    実際に数式を書いてみます。上の"図形"のボタンをクリックするとテキストボックスがあるのでそれを使います。

    draw.ioで数式を書くには、数式を"`"(バッククオート)で囲む必要があります。
    また書き方はTeXと同じものを使用します。


    そしてこんな感じになるはずです。
4)追記:保存方法
    draw.ioで作ったものはxml形式のほか種々の画像ファイルなどで保存できます。
 
    この画像の左上のほう、"ダイアグラム"をクリックするとこんなのが出てくるはず。
    ここで"保存"を選ぶと、xmlファイルで保存できます。
    このxmlがあればdraw.ioから開いて修正などもできます。
    "形式を指定してエクスポート"を選ぶと、pngなどの各種ファイルで出力できます。



©2018 shts All Right Reserved.