e-tipsmemo

ごった煮

歯車の検討準備

歯車を購入するにあたって、機械要素部品としての基本的な知識を調べた。
小原歯車工業(株):歯車技術資料 歯車の歯形及び寸法

Fusion 360のアドインに
平歯車を作るものがあり
f:id:katakanan:20170827120933p:plain

これに必要な最低限のもの
f:id:katakanan:20170827120650p:plain

Standard

寸法
mm単位 or inch単位

Pressure Angle

圧力角
20度が一般的(買う歯車に合わせる)

Module

ピッチ円直径をd
ギアの歯数をnとすると

歯の感覚(ピッチp)は

p = \frac{d\times\pi}{n}

両辺を\piで割ると

\frac{p}{\pi} = \frac{d}{n}

これがモジュール

Number of Teeth

歯数

Backlash

バックラッシュ/バックラッシ

Root Fillet Radius

歯底すみ肉部曲率半径

Hole Diameter

軸穴直径

L3GD20 動作テスト②

前回の続き
L3GD20が送る角加速度を見るが
そのままのデータだとノイズやなんやらの影響で
値が暴れすぎるので今のところ移動平均をとって出力させる。
平均をとるデータ数を変えてどれくらいなめらかになるか試す。

移動平均なし
f:id:katakanan:20170812221836p:plain

5回
f:id:katakanan:20170812221839p:plain

10回
f:id:katakanan:20170812221841p:plain

なんとなく飛んでいる値が減っているようだ

コード例

float dx;
float dy;
float dz;

int itr;

int16_t a[SIZE];
int16_t b[SIZE];
int16_t c[SIZE];

int32_t suma;
int32_t sumb;
int32_t sumc;

void get_deg()
{
    suma = 0;
    sumb = 0;
    sumc = 0;

    a[itr] = gyro.read_x();
    b[itr] = gyro.read_y();
    c[itr] = gyro.read_z();
    itr = (itr + 1)%SIZE;
    
    for(int i=0;i<SIZE;i++)
    {
        suma += a[i];
        sumb += b[i];
        sumc += c[i];
    }
    
    dx = (float)suma/SIZE;
    dy = (float)sumb/SIZE;
    dz = (float)sumc/SIZE;
    
    pc.printf("X%fY%fZ%f\r\n", dx,dy,dz);    
}

L3GD20 動作テスト①

急に作りたくなったものがあるので、L3GD20をmbedから使ってみる。

I2Cはちょっと面倒なのでSPIで通信する。

f:id:katakanan:20170714232309p:plain

図にするほどのものでもない図。
akizukidenshi.com
ライブラリがあるいが面白くないので自分で

のチップデータシートによるとSPIの波形は

f:id:katakanan:20170714232625p:plain
のようなタイミングで
SPI - SPIマスター | Mbed

によるとMode3
bitは8で
最初はWho am Iアドレスを読む。

#include "mbed.h"
#include "L3GD20.h"

DigitalOut myled(LED1);

Serial pc(USBTX, USBRX);
//SPI spi(p5, p6, p7); // mosi, miso, sclk
L3GD20 gyro(p5, p6, p7, p8/*, PinName interrupt1=NC, PinName interrupt2=NC*/);

int main() {
    
    pc.baud(115200);

    pc.printf("0x%02X\r\n", gyro.read_byte(0x0F));
    gyro.write_byte(0x20, 0x0F);

    while(1) {
        myled = 1;
        wait(0.5);
        myled = 0;
        wait(0.5);
        pc.printf("0x%02X\r\n", gyro.read_byte(0x0F));
    }
}
#pragma once
#include "mbed.h"

class L3GD20
{
    SPI _spi; // mosi, miso, sclk
    DigitalOut _cs;
    
    public:
    L3GD20(PinName mosi, PinName miso, PinName sclk, PinName cs):_spi(mosi, miso, sclk),_cs(cs)
    {
        _spi.format(8,3);
        _spi.frequency(10000000);
    }
    
    uint8_t write_byte(uint8_t reg, uint8_t val)
    {
        _cs = 0;
        _spi.write(reg);
        _spi.write(val);
        _cs = 1;
        return 0;
    }

    uint8_t read_byte(uint8_t reg)
    {
        _cs = 0;
        _spi.write(reg|0x80);
        uint8_t ret = _spi.write(0x00);
        _cs = 1;
        return ret;
    }
};

これで0xD4が送られてくればOK

"AXI なんとか FIFO" の雑な違い..(?)

Vivado IP の中には今(2016.4)のところ
FIFOで検索すると以下のものがヒットする。

一番目は普通のFIFOである。
最後はおいておいて、その下3つの違いについて

AXI Data FIFO

これについてあまり情報がなかった(おそらく必要となる場面があまりないからか・・)
AXI Interconnectのなかで使われているらしく。
https://www.xilinx.com/support/documentation/ip_documentation/axi_interconnect/v2_0/pg059-axi-interconnect.pdf
これのp76を読む限り、
ユーザーは必要なときにInterconnect内のFIFOをオンオフ擦ることもできるし、
直接ブロックデザインに入れることもできる。
データ幅やクロック変換によってデータレートが違うところで役に立つ。(AXI Crossbar付近)

という感じ。直接使うことはあんまりなさそうだ。

AXI-Stream FIFO

データシート
https://www.xilinx.com/support/documentation/ip_documentation/axi_fifo_mm_s/v4_1/pg080-axi-fifo-mm-s.pdf
によると、
AXI4とかAXI4-LiteをAXI Streamに変換するのにつかえる。イーサネットとかそういうたぐいのパケットコミュニケーションを使うものに良いよ、という。
ただ非同期クロックには対応していない。

使用例をみるとわかりやすい。
p37 Programming Sequence for TX and RX in Store-and-Forward Mode

送信は必要なタイミングでlengthを書き込むことで開始される。
受信はあらかじめThresholdを設定しておくことで割り込みをかけることができるようだ。

AXI4-Stream Data FIFO

https://www.xilinx.com/support/documentation/ip_documentation/axis_infrastructure_ip_suite/v1_1/pg085-axi4stream-infrastructure.pdf
によるとAXI4-Stream Infrastructure のうちの一つである。
そもそもInfrastructuresは

  • Buffering Module
  • Transform Module
  • Routing Module

に分かれており。これらはAXI4-Stream Systemを構成するのに便利なモジュール群である。
その中のBuffering Moduleの一つであるFIFO
FIFO generatorによBRAM,LUTをベースとしてFIFOを実装する。

p13からその説明で基本的なFIFOにAXI4-Streamがくっついたと捉えている。
非同期クロックに対応している。


この中で使いそうなのはAXI Stream FIFOのようだ。
FIFOに特定の情報が集まったらバーストを開始させて、目的のスレーブが処理する。

C# sscanf の代替

C#でsscanfしたいなという人が絶対にいると思っていたら
ネットにあったのでその紹介。

www.blackbeltcoder.com

これは同時に以下のTextParserというものを利用している。
(Microsoft.VisualBasic.FileIOにもTextParserクラスがあるが、それとは別)
www.blackbeltcoder.com

private void button1_Click(object sender, EventArgs e)
{
    ScanFormatted scan = new ScanFormatted();

    scan.Parse("hoge1foo2bar3", "hoge%dfoo%dbar%d");

    foreach (var item in scan.Results)
    {
        Debug.WriteLine("{0}", item);
    }

//1
//2
//3
}

のようだ。

C# serialport ReadExisting

急に作りたくなったもののためのデバッグのために
UARTでパソコンに情報を送信しているが
それを可視化したほうが分かりやすかったので寄り道。

フォームアプリケーションが
楽なのでC#を使用。
2.0あたりで適当に使ってから久しぶりに使ったきがする。

\r\nで通信を区切っているがReadLineだとエラーが出るので
ReadExistingを使う。


COMポートの列挙(comboBoxで選べるように)

private void Form1_Load(object sender, EventArgs e)
{
    string[] ports = SerialPort.GetPortNames();

    foreach (var item in ports)
    {
        comboBox1.Items.Add(item);
    }

    comboBox1.SelectedIndex = 1;
}

データの受信インベント
区切り文字(delim=\r\n or \n)があるときは必ず(?)末尾っぽいので
出力してバッファーを空にする。

private string buffer;

private void DataReceived(object sender, SerialDataReceivedEventArgs e)
{
    if (serialPort1.IsOpen == false)
    {
        return;
    }

    try {
        buffer += serialPort1.ReadExisting();
                
        if (buffer.IndexOf(delim) >= 0)
        {
            Debug.WriteLine(buffer);
            buffer = string.Empty;
            Debug.WriteLine("---------------");
        }
    }
    catch (Exception ex) {
        MessageBox.Show(ex.Message);
    }

    if (buffer.Length > 1024)
    {
        buffer = string.Empty;
    }
}

区切り文字なくてもバッファーが長くなると困るので適当にリフレッシュ。
(ココらへんは適当仕様)

あとは受信できた一行なんとかする。

BD6231F-E2動作テスト

急に作りたくなったものがあるので
秋月電子の良さそうなモータードライバ
akizukidenshi.com
の動作テスト
雑な図
f:id:katakanan:20170625205945p:plain
モータードライバー自体の電源は6Vでも
入力電圧Hレベルは2.0VなのでmbedのPWM(3.3V)でもOK。

ついでに可変抵抗でも繋いで、
AD変換した値を読み取り、
速度が変わっていることを確認する。

#include "mbed.h"

DigitalOut myled(LED1);
AnalogIn ain(p20);

PwmOut fin(p22);
PwmOut rin(p21);

int main() {
    
    fin.period(0.000010);
    rin.period(0.000010);

    rin = 0;

    while(1) {
        fin = ain;
    }
}

モーターにエンコーダーとかついていたら面白かったが
mbedにはそれをカウントするために周辺回路がない