マイクロマウスのために買った部品たち

機械を習ったことがないが
マイクロマウスを始めるために何が必要か全くわからなかったので
調べた結果必要だと思われるものを色々と買った。

基本的な部品。
ホイールを自作する人もいるらしいが、
自分では精度がでないだろうし
自作の方法がわからない。

ホイールとセットで必要
ゴムの硬さが色々とあるようだがわからないので
適当なのを買った。

ミニチュアベアリングというカテゴリー
[X][Y]0ZZという型番でたくさん存在し
X(mm)が外径
Y(mm)が内径のようだ(??)
"シールド"はボールが剝き出しにならない蓋。
ゴミが入るのを防ぐ。

ナイロンナット
これでネジを固く閉められる。
普通のナットと違い、緩むのを避けたい場所で使うそう。

アルミM3テーパーカラー (ブラック) 6個入り SGE-108BK

アルミM3テーパーカラー (ブラック) 6個入り SGE-108BK

テーパーカラー
モーターマウントと車輪の間に挟むことでスムーズさを

タミヤ HOP-UP OPTIONS OP-585 φ3mmシムセット

タミヤ HOP-UP OPTIONS OP-585 φ3mmシムセット

シムリング
これも回転をスムーズに保つために必要

歯車(候補1)
ホイールの中心が8mmなので
内径8mmでモジュールが適当な値で
厚みが2mm程度で
大きさが20mm程度の大きさの歯車を必要としている。
(トルクを考えると、なるべく外側で回したほうが良さそうなので)
検索したところ、既製のものでは
この歯車ぐらいしかない・・?

M3のネジ
これらを単純に組み立てたときの想定図
f:id:katakanan:20170901211012p:plain
f:id:katakanan:20170901212245p:plain

これほどのツールが無料で使えるとはすごい時代だなぁ

歯車の検討準備

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

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;
    }
}

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

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