マイコンボードまとめ

最近マイコンボードがたくさん出てきているので、CPUごとにまとめました。(ついでにゲーム機もまとめました) Arduinoとか、mbedとかメジャーなものはまだ記載していません。

LPC1114

IchigoJam

PIC32

OrangePico

Machikania

STM32F103C8

Blue Pill

ESP8266

ESPr Developper

KOMAINO

ESP32

ESPr Developper 32

obniz

Nefty BT

m5stack

ATSAMD21

Gamebuino META

Arduino M0 Pro

LPC11U6x

pokitto

ATTiny85

8pino

Digispark

Atmega328

nekoboard2

ちっちゃいーの

Dotsuino

TinyDuino

Gamebuino Classic

Atmega32u4

Arduboy

Beetle

Arduino Esplora

nRF51822

micro:bit

未分類

Teensy

Trinket

micro:bit

Mbed

ESP32を使ったゲーム機"o-bako"のシミュレータを開発した

ESP32を使ったゲーム機 "o-bako"

”o-bako” とは最近僕が作っているゲーム機です。

ESP32と128×128の液晶、アンプとスピーカ。十字ボタンとA,Bボタン、スタートボタンを搭載しています。

さらにPS/2キーボードが接続できるようになっています。

f:id:inajob:20180527165238p:plain

ESP32-DevKitC を利用しており、arduino-esp32を使うことで、Arduinoのようにプログラムを組むことができます。

f:id:inajob:20180527175931p:plain f:id:inajob:20180527175958p:plain

3Dプリンタで簡易的なケースも作成しました。

f:id:inajob:20180527180919p:plain

構成としては最近話題のm5stackと似たようなものです。

また、Lua言語のインタプリタを動かせるようになっており、Luaで書いたプログラムを実行することができます。

さらにWiFi機能を使ってWebサーバとしても動作します。このWebサーバにアクセスすることで、Luaプログラムを閲覧したり、編集することができます。

 

f:id:inajob:20180527174542p:plain

o-bako Simulator

 o-bakoはまだ開発中なのですが、o-bakoで動かすLuaで書かれたゲームはそれ以外の環境でも、理論的には動かすことができます。

パソコンでプログラムを書いて、o-bakoに転送し、動作を検証し、という作業を効率化するためにブラウザで動作するo-bakoのシミュレータを開発しました。

inajob.github.io

 

f:id:inajob:20180527171658p:plain

理論的にはこのシミュレータで動作するように書いたプログラムは、o-bakoでも同じように動作します。

 

いまのところo-bakoが定義している命令は下記の9個だけです。(まだ追加する予定ですが、それほど大きく増やすつもりはありません。)

tone(no, freq, vol) 音を鳴らす(no: 0-2, vol: 0-255)
spr(x,y,w,h,sx,sy[,sw,sh]) (x,y)にspriteを(sx,sy)からサイズはw,hで描画する。sw,shを設定すると拡大、縮小できる。
pset(x,y) (x,y)に1ピクセルのドットを描画
color(r,g,b) ペンの色を[r,g,b]に設定。(r: 0-255, g: 0-255, b: 0-255)
text(s,x,y) (x,y)に文字列sを描画
drawrect(x,y,w,h) (x,y)にサイズw,hの四角形の枠線を描画
fillrect(x,y,w,h) (x,y)にサイズw,hの四角形を塗りつぶす
fillcircle(x,y,r) (x,y)を中心に半径rの円を塗りつぶす
btn(n) ボタンの入力を取得 ボタンを押してからのフレーム数が返る

テキストエリアにプログラムを書き込んで「Execute」をクリックするとゲームが動作するので、試してみてください。


ゲームプラットフォームとしての"o-bako" 

最近Arduboy, Gamebuino, Pokittoなど様々なゲームプラットフォームが出てきていますが、それぞれで作ったゲームはそのゲーム機専用になってしまい、ほかのプラットフォームでは動作しません。

Luaのようなもうすこし高レベルの層を定義し、それに向けたゲームを作るようにすることで、ほかのプラットフォームでも簡単に動作するものができるのではないか?と考えています。

LuaC言語が動作する環境であれば、非常に簡単に移植することができます。(メモリ、CPUがそこそこ必要ですが・・)

 

とか書きましたが実際のところは僕が作ってみたいので作ってるだけです。生暖かく見守ってください。

 

Arduinoで掃除しないルンバを作った

これは何?

f:id:inajob:20180331231312p:plain

ロボット作りの習作ということで、Arduinoを使っていわゆるルンバみたいな部屋の中を自律的に走行するロボット(ただし掃除はしない)を作ってみました。

 

材料

  • Arduino
  • モーターとギアボックス
  • タイヤ
  • モータードライバ(TA7291P)
  • 距離センサー(HC-SR04)
  • ブレッドボード
  • 9V電池
  • 3Dプリンタとフィラメント

筐体の作成

今回は作りながら構成を考えるということで、まずはこういうユニバーサルボードを作ってみます。

穴の大きさは11mm。僕がよく作るねじの直径が10mmなので、そのねじがうまく入るような大きさにしました。

f:id:inajob:20180331224926p:plain

ギアボックスと3mmのボルトとナットでで固定します。この時点でかなりそれっぽい!

f:id:inajob:20180331224834p:plain

OpenSCADでねじを作ります。

f:id:inajob:20180331225129p:plain

Fusion360でこういうのを作ります。

Arduino固定用パーツ

f:id:inajob:20180331225232p:plain

ブレッドボード固定用パーツ

f:id:inajob:20180331225321p:plain

9V電池固定用パーツ

f:id:inajob:20180331225703p:plain

 

で、こんな風に上にArduinoを固定します。

f:id:inajob:20180331225421p:plain

9V電池はこんな風に固定する

f:id:inajob:20180331225752p:plain

回路

下の記事を参考にして、モータードライバを制御しました。今回は両輪別々に制御したかったので、同じ回路を2つ並べました。

shangtian.hatenablog.com

 

超音波センサーについては下記記事を参考に。

deviceplus.jp

 

(この後紹介するスピーカーも含めた回路図です)

f:id:inajob:20180401225137p:plain

 

 

プログラムの作成

ほとんどプログラムも前述の記事の真似です。

自立制御の部分はテキトーに作りました。

50cm先に障害物を発見すると、バックして左に少し回転してまた前進します。

const int motor1A = 2;
const int motor1B = 3;
const int motor2A = 4;
const int motor2B = 5;
const int motorPwm = 6;

const int echoPin = 8;
const int trigPin = 7;

enum Mode{modeLeft, modeRight, modeForward, modeBackward};
Mode mode = modeForward;

void back(){
  digitalWrite(motor1A, HIGH);
  digitalWrite(motor1B, LOW);

  digitalWrite(motor2A, LOW);
  digitalWrite(motor2B, HIGH);
}
void backward(){
  digitalWrite(motor1A, HIGH);
  digitalWrite(motor1B, LOW);

  digitalWrite(motor2A, LOW);
  digitalWrite(motor2B, HIGH);
}
void forward(){
  digitalWrite(motor1A, LOW);
  digitalWrite(motor1B, HIGH);

  digitalWrite(motor2A, HIGH);
  digitalWrite(motor2B, LOW);
}
void turnLeft(){
  digitalWrite(motor1A, HIGH);
  digitalWrite(motor1B, LOW);

  digitalWrite(motor2A, HIGH);
  digitalWrite(motor2B, LOW);
}
void turnRight(){
  digitalWrite(motor1A, LOW);
  digitalWrite(motor1B, HIGH);

  digitalWrite(motor2A, LOW);
  digitalWrite(motor2B, HIGH);
}

double getDistance(){
  double duration = 0;
  double distance = 0;

  digitalWrite(trigPin, LOW); 
  delayMicroseconds(2); 
  digitalWrite( trigPin, HIGH );
  delayMicroseconds( 10 );
  digitalWrite( trigPin, LOW );
  duration = pulseIn( echoPin, HIGH );
  if (duration > 0) {
    duration = duration/2;
    distance = duration*340*100/1000000;
    if(distance > 100){
      distance = 100;
    }
  }
  return distance;
}

void setup() {
  Serial.begin(9600);
  pinMode(motor1A, OUTPUT);
  pinMode(motor2A, OUTPUT);
  pinMode(motor1B, OUTPUT);
  pinMode(motor2B, OUTPUT);
  pinMode(motorPwm, OUTPUT);

  digitalWrite(motorPwm, LOW);

  pinMode( echoPin, INPUT );
  pinMode( trigPin, OUTPUT );

  forward();
}

int sp = 255;
int nearCount = 0;
int forceTurnCount = 0;
int forceBackCount = 0;

void loop() {
  switch(mode){
    case modeLeft: turnLeft(); break;
    case modeRight: turnRight(); break;
    case modeForward: forward(); break;
    case modeBackward: backward(); break;
  }

  // speed
  analogWrite(motorPwm,sp);

  double distance = getDistance();
  if(distance < 50){
    nearCount ++;
  }else{
    nearCount = 0;
  }

  if(nearCount > 10 && mode == modeForward){
    mode = modeBackward;
    forceBackCount = 100;
    Serial.println("detect object. back");
  }else if(mode == modeBackward){
    forceBackCount --;
    if(forceBackCount == 0){
      forceTurnCount = 30;
      mode = modeLeft;
    }
    Serial.println("back");
  }else if(mode == modeLeft){
    forceTurnCount --;
    if(forceTurnCount == 0){
      mode = modeForward;
    }
    Serial.println("left");
  }else{
    mode = modeForward;
    Serial.println("forward");
  }
}

 動画

感想 

3Dプリンタがあると、こういう物理的な工作が簡単にできました。

また今回は初めからすべてを設計するのではなく、ユニバーサルボード的なものを作って、後付けパーツで組み立てていくという方式にしたため、簡単に設計を試行錯誤することができました。

 

そして自律的に動くものをプログラムするのは難しいと感じました。今回はとても単純な仕組みで作りましたが、これ以上賢く作るためには、このようなルールをどんどん入れていくか、ロボットが空間を把握するような仕組みをプログラムするか、、 いずれにしても大変そうです。

また気が向いたら改良していこうと思います。

 

追記:話せるようにしてみる

ちょうど家にあったDFPlayerMiniを使って状況に応じてmp3を再生させるようにしてみました。

 おきまりのセリフをしゃべるだけだけど、これだけでかなり愛着がわくものになった気がします。

 

音声は下記サイトのものを利用しました。

soundeffect-lab.info

 

参考部品リンク

Arduino

つかったのはこちら

www.aitendo.com

 普通のならこれかな?

【永久保証付き】Arduino Uno

【永久保証付き】Arduino Uno

 

 

モーターとギアボックス

つかったのはこれ。もう欠品のようだ

www.aitendo.com

 これが同じもののように見える。タイヤも付いている。

 モータードライバ

つかったのはこれ。ディスコンらしい。

akizukidenshi.com

 Amazonにもあるが別のモータードライバを使うのがよさそう。

 距離センサー

akizukidenshi.com

 Amazonならこれかな?

HC-SR04 超音波距離センサーモジュール For Arduino

HC-SR04 超音波距離センサーモジュール For Arduino

 
DFPlayerMini

 

 

ブレッドボード 

akizukidenshi.com

 Amazonならこれかな?

月10ドルのKubernetesクラスタに無料で取得したドメインでアクセスできるようにする

概要

前回は$10/月のKubernetesクラスタを作成しました。

inajob.hatenablog.jp

ここに自分用のWebサービスなどをデプロイすれば個人サーバとして活用できるわけですが、いつまでもIPアドレスでアクセスするというのはダサいですね。 今回は無料でドメインを取得しKubernetes上のサービスをその名前でアクセスできるようにしてみます。

f:id:inajob:20180228185422p:plain

ドメインをとるのはちょっと・・・という人はcurlのオプションでヘッダをつけてアクセスすることでその挙動を確認することができます。(が今回の記事では触れません)

TKドメインの取得

トラケウのドメインである.tkは無料で取得できます。

.tk - Wikipedia

もちろんすでにドメインを持っている人はこのような怪しいドメインを取得する必要はありません

https://my.freenom.com

とれるかな、、 f:id:inajob:20180228175551p:plain いけそう! f:id:inajob:20180228175618p:plain kubernetesのmasterのIPアドレスを入れる(あとで変えるので何でもよいのですが、、) f:id:inajob:20180228175858p:plain いい感じに入力する f:id:inajob:20180228175946p:plain 下記からアクセスすると所有しているドメインの一覧が確認できる。 https://my.freenom.com/clientarea.php?action=domains

CloudFlareでワイルドカードDNSの登録

FreenomでもDNSサービスは提供しているのですが、CloudFlareのほうが操作性がよくワイルドカードDNSが利用できるのでこちらを使うことにします。

www.cloudflare.com 右上のAdd Siteからドメインを追加画面に遷移 f:id:inajob:20180228180457p:plain

一番左の無料のやつを選択 f:id:inajob:20180228180524p:plain

いったんそのままContinue f:id:inajob:20180228180615p:plain

nameserverを変えろと言われる。 f:id:inajob:20180228180653p:plain

freenomに行って指示通りにNameserverを変更する f:id:inajob:20180228180847p:plain

Cloudflareにて反映されるのを待つ f:id:inajob:20180228180930p:plain

ページを行ったり来たりしていると数分で反映された f:id:inajob:20180228181223p:plain

いまこのドメインにアクセスすると下記のようになる。 これは名前からサーバまではいけるがそのサーバの80番が開いていないということのようだ。 登録したIPが間違っていたかな? f:id:inajob:20180228181250p:plain

nghttpx-ingress-controllerがデプロイされているホストをを調べる f:id:inajob:20180228181410p:plain

worker01にデプロイされているので、そのIPに設定する(masterのIPを指定していました;) (通常のPodは10.x.xのようなクラスタ内IPが付与されますがnghttpx-ingress-controllerは.spec.hostNetwork=trueとなっているためホストのIPとなっています my-vps-kubernetes/rc-default.yaml at master · inajob/my-vps-kubernetes · GitHubf:id:inajob:20180228181657p:plain

アクセスできた! この"default backend -404" というのはKubernetes上のサービスから返却しているものです。

f:id:inajob:20180228181819p:plain

図にするとこんな感じ f:id:inajob:20180228182434p:plain

$ kubectl get pods -n kube-system
NAME                                         READY     STATUS    RESTARTS   AGE
default-http-backend-55c6c69b88-vlqcx        1/1       Running   0          1h <--- これです
etcd-kubernetes                              1/1       Running   0          1h
kube-apiserver-kubernetes                    1/1       Running   0          1h
kube-controller-manager-kubernetes           1/1       Running   0          1h
kube-dns-6f4fd4bdf-c2995                     3/3       Running   0          1h
kube-proxy-622sq                             1/1       Running   0          1h
kube-proxy-j5754                             1/1       Running   0          1h
kube-scheduler-kubernetes                    1/1       Running   0          1h
monitoring-grafana-8dd9cb57f-4ms82           1/1       Running   0          1h
nghttpx-ingress-controller-78749dc54-8wlxr   1/1       Running   0          29m
node-exporter-5294m                          1/1       Running   0          1h
prometheus-8694d8cdd8-vmw7h                  1/1       Running   0          1h
weave-net-r5jft                              2/2       Running   0          1h
weave-net-wm7sn                              2/2       Running   0          1h

Ingressを試す

ドメインの取得、DNSサーバへの登録が終わり、無事取得したドメインでKubernetesクラスタまで到達できることが確認できました。 次はIngressを試します。

Ingressを利用するとVirtualHostのようにHostヘッダの値で違うServiceにアクセスさせることができます。

nginxをデプロイして、Serviceも作成します。

$ kubectl run nginx --image=nginx
deployment "nginx" created
$ kubectl expose deployment nginx --port=80
service "nginx" exposed

Ingressはコマンドでは作れないので下記のようなテキストファイルを用意します

nginx-ingress.yaml

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: nginx-ingress
spec:
  rules:
  - host: nginx.inajob-test.tk
    http:
      paths:
      - path: /
        backend:
          serviceName: nginx
          servicePort: 80

上記をKubernetesにデプロイします。

$ kubectl apply -f nginx-ingress.yaml
ingress "nginx-ingress" created

cloudflareにAレコードを追加します f:id:inajob:20180228183320p:plain

やった!アクセスできました。 f:id:inajob:20180228183400p:plain

新しいサブドメインIngressを用意するたびにcloudflareにAレコードを追加するのが面倒なのでワイルドカードドメインを追加してみます。

丸で囲ったところに注意です。CloudFlareではCloudFlareを経由しキャッシュを返したり、SSL化したりするような機能がありますが、ワイルドカードドメインの場合はそれが使えないので明示的にOFFにしています。

f:id:inajob:20180228183707p:plain

f:id:inajob:20180228183635p:plain

これであとはIngressを用意するだけでサブドメインが増えていくようになります。

まとめ

ここまでできると月$10のクラスタでもそこそこつかえるKubernetesが構築できたのではないかと思います。

ということで、vultrでサーバを作りましょう! (この記事が役立った!という人はぜひこちらのリンクからお願いします。)

www.vultr.com

月10ドルで海外VPSでKubernetesを試してみる(kubernetes v1.9版)

VultrでのKubernetesセットアップ方法

以前書いた記事

inajob.hatenablog.jp

で反響があったのですが、今試すとずいぶんやり方が変わっているところがあるので、Kubernetes1.9のやり方をまとめました。

例によって下記からVultrに申し込んでもらうと僕に$10入ります。 (以前の記事で$10ゲットしたので、やる気が出てこの記事を書く気になりました! この記事読んで試してみたいと思った人はぜひ下記リンクからお願いします。僕へのご褒美になります)

www.vultr.com

以前の記事では1台のマシンで構築したのですが、さすがにつらかったので、今回は奮発して$10/monthで2台構成のクラスタを作成します。 この手順で作るkubernetesはアルファの機能を使っていたり、セキュリティ上まずい設定を指定しているところもあるので、このままインターネットにさらし続けるのは危険です。

今回はコマンドやmanifestをgit上にまとめました。 github.com

準備

f:id:inajob:20180228170636p:plain

サーバは上記のプランで2つ用意する。 OSはUbuntu 17.10 x64

master, worker共通のセットアップ手順

事前にパッケージは最新化しておく

# apt-get update && apt-get upgrade
#必要に応じてリブートする
# reboot
# git clone https://github.com/inajob/my-vps-kubernetes.git
# cd my-vps-kubernetes/
# sh init-scripts/setup.sh

init-scripts/setup.shの解説

#!/bin/sh

# dockerをインストール
apt-get install -y docker.io

# kubeadm kubelet kubectlのインストール
apt-get update && apt-get install -y apt-transport-https
curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | apt-key add -
cat <<EOF >/etc/apt/sources.list.d/kubernetes.list
deb http://apt.kubernetes.io/ kubernetes-xenial main
EOF
apt-get update
apt-get install -y kubelet kubeadm kubectl

# swapの設定(非推奨だが非力なマシンなので設定します)
dd if=/dev/zero of=/swapfile count=2048 bs=1M
chmod 600 /swapfile
mkswap /swapfile
swapon /swapfile
echo "/swapfile   none    swap    sw    0   0" >> /etc/fstab

#kubeletの設定ファイルを作るためにkubeadm initを実行(実際は失敗する)
kubeadm init

# kubeletの設定を変更しswapがonの状態でも起動できるようにする
sed -i 's/\/usr\/bin\/kubelet/\/usr\/bin\/kubelet --fail-swap-on=false /' /etc/systemd/system/kubelet.service.d/10-kubeadm.conf

# kubeadmのお片づけをする(これをしないとこのあとのkubeadm initが実行できない)
kubeadm reset

# kubeletの設定変更を反映する
systemctl daemon-reload
systemctl restart kubelet

masterのセットアップ手順

# kubeadm init --ignore-preflight-errors=Swap

--ignore-preflight-errors=Swapは本来Swapが有効だとこのコマンドは失敗するのだが、それを無視して進めるようするためのオプションです。

kubeadm join .... といったworker接続用の文字列が出るのでメモ帳などにコピーしておきます。

workerのセットアップ手順

さきほどコピーしたkubeadm join .... の末尾に同様に--ignore-preflight-errors=Swapをつけて実行します。

# kubeadm join ....--ignore-preflight-errors=Swap

手元のラップトップ

kubectlをインストールしておきます。

SCPでmasterサーバのadmin.confを持ってきます。

$ scp root@masterサーバのアドレス:/etc/kubernetes/admin.conf ./admin.conf

ラップトップ内にmasterサーバへのプロキシを作成します。

$ kubectl --kubeconfig=:admin.conf proxy  --port=8080 --disable-filter=true --accept-hosts='^*$' --reject-paths='^$'

nodeを確認します

$ kubectl get nodes
NAME         STATUS     ROLES     AGE       VERSION
kubernetes   NotReady   master    4m        v1.9.3
worker01     NotReady   <none>    3m        v1.9.3

CNIネットワークを指定していないのでNotReadyのままですが2台のサーバでクラスタが組めていることが確認できます。

Weaveのデプロイ

CNIネットワークプラグインであるweaveををインストールします。 ほかのネットワークプラグインを使うこともできるので気になる人は公式ページから探してみてください

Using kubeadm to Create a Cluster | Kubernetes

$ kubectl apply -f "https://cloud.weave.works/k8s/net?k8s-version=1.9"

Readyになりました。

$ kubectl get nodes
NAME         STATUS    ROLES     AGE       VERSION
kubernetes   Ready     master    6m        v1.9.3
worker01     Ready     <none>    5m        v1.9.3

kube-dnsカスタム設定のデプロイ

$ git clone https://github.com/inajob/my-vps-kubernetes.git
$ cd my-vps-kubernetes/
$ kubectl apply -f manifests/dns/
configmap "kube-dns" created

これの中身は下記です

apiVersion: v1
kind: ConfigMap
metadata:
  name: kube-dns
  namespace: kube-system
data:
  upstreamNameservers: |
    ["8.8.8.8", "8.8.4.4"]

ubuntu固有の問題らしく kube-dns copies 127.0.0.35 from host's /etc/resolv.conf, doesn't work · Issue #45828 · kubernetes/kubernetes · GitHub これを入れないとpodから外への名前解決が失敗します。

どうもUbuntuは内部にDNSサーバを持っているようで、127.0.0.53が/etc/resolv.confに書かれています。しかしPodの中からはこのIPに到達できないので、kube-dnsから外の名前を引くことができなくなるようです。 このConfigMapを入れることで外のDNSを明示的に指定しています。

ingress-controllerのデプロイ

$ kubectl apply -f manifests/ingress-controller/
deployment "default-http-backend" created
service "default-http-backend" created
serviceaccount "ingress" created
clusterrole "ingress-clusterrole" created
role "ingress-role" created
rolebinding "ingress-role-binding" created
clusterrolebinding "ingress-clusterrole-binding" created
deployment "nghttpx-ingress-controller" created
service "nginhttpx-health" created

今後のためにingress-controllerをデプロイします。

prometheus, node-exporter, grafanaのデプロイ

$ kubectl apply -f manifests/monitoring/
deployment "monitoring-grafana" created
service "monitoring-grafana" created
daemonset "node-exporter" created
configmap "prometheus-config" created
clusterrole "prometheus" created
serviceaccount "prometheus" created
clusterrolebinding "prometheus" created
deployment "prometheus" created
service "prometheus" created

負荷状況のメトリクスを取得、可視化するために追加します。

動作確認

Pod一覧

$ kubectl get pods -n kube-system
NAME                                         READY     STATUS    RESTARTS   AGE
default-http-backend-55c6c69b88-vlqcx        1/1       Running   0          1m
etcd-kubernetes                              1/1       Running   0          10m
kube-apiserver-kubernetes                    1/1       Running   0          9m
kube-controller-manager-kubernetes           1/1       Running   0          9m
kube-dns-6f4fd4bdf-c2995                     3/3       Running   0          10m
kube-proxy-622sq                             1/1       Running   0          9m
kube-proxy-j5754                             1/1       Running   0          10m
kube-scheduler-kubernetes                    1/1       Running   0          9m
monitoring-grafana-8dd9cb57f-4ms82           1/1       Running   0          43s
nghttpx-ingress-controller-78749dc54-jl4nv   1/1       Running   0          1m
node-exporter-5294m                          1/1       Running   0          43s
prometheus-8694d8cdd8-vmw7h                  1/1       Running   0          43s
weave-net-r5jft                              2/2       Running   0          4m
weave-net-wm7sn                              2/2       Running   0          4m

PrometheusのUIを確認

Prometheusは固定のポートでexposeしてあります。

http://masterまたはworkerのIPアドレス:30090/

GraphanaのUIを確認

Graphanaも固定のポートでexposeしてあります。

http://masterまたはworkerのIPアドレス:30091/

grafanaの設定方法は 月5ドルの海外VPSでKubernetesを試してみる - inajob's blog の記事のままです。参考にしてください。

f:id:inajob:20180228174920p:plain

next

このリポジトリではingress-controllerもデプロイしています。 ドメインを持っている人は、DNSの設定とIngressリソースのデプロイを行うことで、オリジナルドメインのサービスを提供することができます。

それについては次の記事に記載しています。

inajob.hatenablog.jp

ESP-WROOM-02(ESP8266)で和音を鳴らしてみた

ESP8266 Arduinoで和音を鳴らしてみた。
まだ不可解な現象がありますが、ソフトウェアPWMの特性だということにして、これ以上深堀するのはやめます。

回路

ESP8266の4番ピンにトランジスタとスピーカをつなげています。
試していないけど、イヤホンジャックなどをコンデンサ通してつなげても動くと思います。

ソフトウェア

ESP8266のArduinoを使って和音を鳴らしてみようと思います。
矩形波の場合のみうまく動くことを確認しました。(ノコギリ波にするとうまく動かないことも確認しました)

PWMを32kHz周期に設定し、timer0の割り込みを10000クロック後(160MHzの場合は16kHz周期)に設定します。
ndという変数にタイマ割り込みのたびにdd足していきます。これがオシレータです。
矩形波を作りたいのでndの16ビット目が0か1かで0か256を返すような計算式を作ります。


((nd>>15)&1 == 1)?0:256

これをAnalogWriteすることで音が鳴ります。
音階を作るには少し計算をする必要があります。
ndの16ビット目をみているのでddが1の場合は16K/2^16 Hzの音が鳴るはず(0.24414..という音にならない周波数だけど)
で、ddを変数として意図した周波数を鳴らすための数式は

f:id:inajob:20180225210000p:plain

となる。
式変形して

f:id:inajob:20180225210059p:plain

これを音階ごとに計算すればよい。こうやって計算した値をtonesという変数に用意しています。

和音が鳴らしたいので上記のような変数を4つばかり配列として作成して、足し算します。
AnalogWriteは0-1024までなのでうまくその範囲に収まるように調整します。

以上で和音が作成できます。
ソースコードはこんな感じ。

 

#include <ESP8266WiFi.h>
#include <SoftwareSerial.h>
SoftwareSerial mySerial(2, 3); // RX, TX


const unsigned int tones[] = {
0,
1802  , // A  1
1909  , // A+ 2
2023  , // B  3
2143  , // C  4
2271  , // C+ 5
2406  , // D  6
2549  , // D+ 7
2700  , // E  8
2861  , // F  9
3031  , // F+ 10
3211  , // G 11
3402  , // G+12
3604  , // A 13
3819  , // A+14
4046  , // B 15
4286  , // C 16
4541  , // C+17
4811  , // D 18
5098  , // D+19
5401  , // E 20
5722  , // F 21
6062  , // F+22
6422  , // G 23
6804  , // G+24
7209  , // A 25
7638  , // A+26
8092  , // B 27
8573  , // B+28
};

const unsigned int melody[3][16] = {
{ 4, 6, 8, 9,11,13,15,16,16,15,13,11, 9, 8, 6, 4 },
{ 8, 0,11, 0,15, 0,18, 0,13, 0, 9, 8, 0, 4, 9, 8 },
{16, 0,20, 0,23, 0, 0,28, 0,27, 0,23, 0,20, 0, 0 },
};
int pos = 0;

volatile unsigned int nd[4] = {0,0,0,0};
volatile unsigned int dd[4] = {0, 0, 0, 0};
volatile unsigned int out;

void timer0_ISR (void) {
  timer0_write(ESP.getCycleCount() + 10000L ); // 160M/16K
  nd[0] += dd[0];
  nd[1] += dd[1];
  nd[2] += dd[2];
  nd[3] += dd[3];

  out = (((nd[0] >> 16)&1 == 1)?0:256) +
        (((nd[1] >> 16)&1 == 1)?0:256) +
        (((nd[2] >> 16)&1 == 1)?0:256) +
        (((nd[3] >> 16)&1 == 1)?0:256);
  analogWrite(4, out);
}

void setup() {
  WiFi.mode(WIFI_OFF);

  analogWriteFreq(32000); // pwm 32kHz

  noInterrupts();
  timer0_isr_init();
  timer0_attachInterrupt(timer0_ISR);
  timer0_write(ESP.getCycleCount() + 10000L ); // 160M/16K
  interrupts();

  Serial.begin(115200);
}

unsigned int counter;

void loop() {
  counter ++;
  if(counter%100000 == 0){
    dd[0] = tones[melody[0][pos]];
    dd[1] = tones[melody[1][pos]];
    dd[2] = tones[melody[2][pos]];
    pos ++;
    if(pos >= 16){
      pos = 0;
    }
    Serial.println("tick");
  }

}

 

動画

 

何かおかしい

矩形波はこれでよい感じに鳴ったのだが、ノコギリ波や、ほかの波形を鳴らそうとするとなぜか音にならない。
おそらくこれはESP8266のPWMがソフトウェアで実装されていることにより、頻繁に値が変わるような波形では速度が追い付いていないのではないか?と思われる。

何か気づいたことがある人は教えてほしいです。

3Dプリンタでフリスク太鼓たたき装置を作った

これは何?

手回しオルゴールのように、ハンドルをくるくる回すとリズムよくフリスクをたたいてくれる装置です

工夫したところ

毎度のことですが設計はFusino360を使いました。

f:id:inajob:20180204112359p:plain

床と壁は、別々の部品で作り、ずぼっとはめ込むスタイルにしました。

3DプリンタはZ方向にでかいものを作るのが遅い、ということと積層方向に弱いということから、壁をXY方向に作るのがよいと考えたからです。

穴の大きさと、差し込む部品の大きさについては、今回は全く同じ寸法で作りましたが、3Dプリントすると部品は少し大きめになり、穴は少し小さめに出力されるため、ヤスリで削らないとはまりませんでした。少し大きさを変えて出してもよいのですが、あまりガバガバになってしまうと固定できないので、ヤスリで調整するくらいがちょうどよいのかなと思っています。

f:id:inajob:20180204112719p:plain

ドラムのツメは、このように斜めの面取りをしてあります。これは3Dプリンタで造形する際に、うまく積層できるようにする工夫です。これをしないと空中にプラスチックを射出してしまいうまく造形ができないと思います。

f:id:inajob:20180204112941p:plain

シャフトと回転部分はこのように四角柱のシャフトを通しています。回転する軸受けの部分は四角い穴の開いた丸いリングをはめています。四角いシャフトにすることで連動して回転することができます。

f:id:inajob:20180204114008p:plain

3Dプリンタで出力するときは、いくつかの部品をまとめて出力しました。

プリント時間はかかるけれども、待ってるだけで一気に部品が作れるので作業効率が上がります。

f:id:inajob:20180204114821p:plain

完成動画

もともとフリスクを置く予定はなかったのですが、プラスチックをたたいてもしょぼい音しか出なかったので、「よく響く缶」ということで、手元にあったフリスクのケースを使いました。

 

 

 

感想

3Dプリンタでギアを使ったものが作りたい!と思って作り始めたので、その欲求は満たすことができました。3Dプリンタで作るとき特有の工夫もある程度わかったので、次やるときはもう少しスムーズにできるかなと思います。

こういう試行錯誤をするのにFusion360は非常に使いやすかったです。