Pages

2012年12月14日

Raspberry PiでSPG20-1332を回す


Raspberry Piで秋月電子で売っている安いステッピングモーター(コパル製 SPG20-1332)を回す。
以前、Arduinoで二相励磁駆動させたものをRaspberry Piでやってみました。



回路は以下の様な感じで。


Raspberry PiのI/Oは3.3V系なので、トランジスタアレイ(TD62004APG)を入れてレベルシフトしています。

#include <stdio.h>

int main()
{
    int i;
    
    system("echo \"7\" > /sys/class/gpio/export");
    system("echo \"8\" > /sys/class/gpio/export");
    system("echo \"9\" > /sys/class/gpio/export");
    system("echo \"10\" > /sys/class/gpio/export");
    system("echo \"out\" > /sys/class/gpio/gpio7/direction");
    system("echo \"out\" > /sys/class/gpio/gpio8/direction");
    system("echo \"out\" > /sys/class/gpio/gpio9/direction");
    system("echo \"out\" > /sys/class/gpio/gpio10/direction");
    
    for (i=0; i<360; i++) {
            system("echo \"1\" > /sys/class/gpio/gpio7/value");
            system("echo \"1\" > /sys/class/gpio/gpio8/value");
            system("echo \"0\" > /sys/class/gpio/gpio7/value");
            system("echo \"1\" > /sys/class/gpio/gpio8/value");
            system("echo \"1\" > /sys/class/gpio/gpio9/value");
            system("echo \"0\" > /sys/class/gpio/gpio8/value");
            system("echo \"1\" > /sys/class/gpio/gpio9/value");
            system("echo \"1\" > /sys/class/gpio/gpio10/value");
            system("echo \"0\" > /sys/class/gpio/gpio9/value");
            system("echo \"1\" > /sys/class/gpio/gpio10/value");
            system("echo \"1\" > /sys/class/gpio/gpio7/value");
            system("echo \"0\" > /sys/class/gpio/gpio10/value");
    }
    
    system("echo \"7\" > /sys/class/gpio/unexport");
    system("echo \"8\" > /sys/class/gpio/unexport");
    system("echo \"9\" > /sys/class/gpio/unexport");
    system("echo \"10\" > /sys/class/gpio/unexport");
}
480ステップで1回転なので、120回ループしてあげれば1回転、上記では360回ループなので3回転します。

とりあえず動かすだけなので、system関数でシェルを呼び出す感じのへたれコード。
本格的に使うならレジスタを直で叩く方が良いと思います。(速度的に雲泥の差)

追記:PythonでRPi.GPIOを利用して上記をそっくりそのまま写すならこんな感じかな?(未検証)
import RPi.GPIO as GPIO

GPIO.setmode(GPIO.BCM)
GPIO.setup(7,GPIO.OUT)
GPIO.setup(8,GPIO.OUT)
GPIO.setup(9,GPIO.OUT)
GPIO.setup(10,GPIO.OUT)
    
for i in range(0,360):
      GPIO.output(7,GPIO.HIGH)
      GPIO.output(8,GPIO.HIGH)
      GPIO.output(7,GPIO.LOW)
      GPIO.output(8,GPIO.HIGH)
      GPIO.output(9,GPIO.HIGH)
      GPIO.output(8,GPIO.LOW)
      GPIO.output(9,GPIO.HIGH)
      GPIO.output(10,GPIO.HIGH)
      GPIO.output(9,GPIO.LOW)
      GPIO.output(10,GPIO.HIGH)
      GPIO.output(7,GPIO.HIGH)
      GPIO.output(10,GPIO.LOW)

GPIO.cleanup()
ループ部分は以前の記事に近い形で書き直せるはず。(放置)

2012年12月11日

電子工作フェスティバル2012


卓球玉に絵を描く「ピンポン玉お絵かきロボット」が電子工作コンテスト2012で学生賞とはんだづけカフェ賞を受賞したので、12月9日開催の電子工作フェスティバル2012に参加してきました。

こういうタイプの催し物は初参加で戸惑っているところ、ブースでお隣にいらっしゃった「無限音階オルガン"nanorgan"」の方に色々とサポートしてもらい助かりました...

説明に大忙しで展示ブースから離れられず、他の方々の作品はあまり見ることが出来なかったのが残念なところ。

熊本に帰ってきたら次は12/15のハードウェア・組み込み系勉強会向けの準備で忙しい(((( ;゚Д゚)))

追記
地味にアキバblogに載ってます... (記事中程)
http://blog.livedoor.jp/geek/archives/51374038.html

2012年11月7日

球面プロッタを応募してみた


7月頃に作った卓球玉に絵を描く装置(球面プロッタ)を電子工作コンテスト2012に応募してみたり。
http://elecontest.com/entrylist/043

以前の完成記事からの変更点は、回路をブレッドボードからバニラシールドに移した点、ボタンひとつでデフォルト描画パターンを単独描画(PCレス)できるようにした点の2つ。

ソースコードはこちら
pingPongBot(KumamotoNCT).ino (9299Byte)
※「熊本高専」と描画する座標データを内包

紹介動画はこちら



ちなみに動画はiMovieで作成。
普段はAfterEffectsばかり使ってるのでiMovieには慣れてなかったり...

2012年10月30日

Arduinoでピアノ階段 with GarageBand


前々から予告していた、ピアノ階段(a.k.a. GarageBand階段)プロジェクトが完成・一般公開できたので、その報告と技術的な詳細について。

まずは実際の動作映像から。



仕組みは以前書いた記事(これこれ)から殆ど変わっていませんが、踏み板スイッチの大型化と素材の特性に応じて若干の調整を加えています。

各段の横幅が1800mm奥行きが350mm程度と大きいこと、滑りにくいことなどを条件に素材を選び、最終的には厚さ2mm〜3mm程度のベニヤ板を使用。

1800x900mmサイズのベニヤ板から1800x250mmの板を3枚切り出し、これの片面にアルミ箔テープ(0.1mm厚)、厚手両面テープ(0.5mm厚)を貼る。

貼り付けたアルミ箔テープの片隅に、リード線の先端を扇状に広げたものを乗せ、上から短く切ったアルミ箔テープをしっかりと貼り付ける。


リード線、アルミ箔テープと貼った場所の上にガムテープを貼る。(リード線で盛り上がった部分同士が接触しないように)



これを2枚用意し、2枚のうち1枚のアルミ箔テープの上に「たこ糸」を渡す。(ベニヤ板の自重で常に接触することを防止する)

ここまで出来たら、アルミ箔を貼った面を向かい合わせにして慎重に貼り合わせる。


これを各段に設置、配線していきます。
タクトスイッチをArduinoで使う要領で、各段のスイッチをプルダウンで接続します。


プログラムはこんな感じ。
相変わらずの「動けば良い」コードなので、改良の余地は十分にあるはず。

#include <Bounce.h>

int pinDo = 13;
int pinRe = 12;
int pinMi = 11;
int pinFa = 10;
int pinSo = 9;
int pinLa = 8;
int pinTi = 7;
int pinDo2 = 6;
int pinRe2 = 5;
int state[9];

Bounce Do = Bounce( pinDo,20 );
Bounce Re = Bounce( pinRe,20 );
Bounce Mi = Bounce( pinMi,20 );
Bounce Fa = Bounce( pinFa,20 );
Bounce So = Bounce( pinSo,20 );
Bounce La = Bounce( pinLa,20 );
Bounce Ti = Bounce( pinTi,20 );
Bounce Do2 = Bounce( pinDo2,20 );
Bounce Re2 = Bounce( pinRe2,20 );

void setup() {
  pinMode(pinDo, INPUT);
  pinMode(pinRe, INPUT);
  pinMode(pinMi, INPUT);
  pinMode(pinFa, INPUT);
  pinMode(pinSo, INPUT);
  pinMode(pinLa, INPUT);
  pinMode(pinTi, INPUT);
  pinMode(pinDo2, INPUT);
  pinMode(pinRe2, INPUT);

  Serial.begin(31250); 
}

void loop(){

  Do.update ();
  if ((Do.read() == HIGH)&&(state[0] == 0)) {
    noteOn(144,60,127);
    state[0] = 1;
  }
  if ((Do.read() == HIGH)&&(state[0] == 1)) {
  }
  if ((Do.read() == LOW)&&(state[0] == 1)) {
    noteOn(128,60,127);
    state[0] = 0;
  }
  if ((Do.read() == LOW)&&(state[0] == 0)) {
  }

  Re.update ();
  if ((Re.read() == HIGH)&&(state[1] == 0)) {
    noteOn(144,62,127);
    state[1] = 1;
  }
  if ((Re.read() == HIGH)&&(state[1] == 1)) {
  }
  if ((Re.read() == LOW)&&(state[1] == 1)) {
    noteOn(128,62,127);
    state[1] = 0;
  }
  if ((Re.read() == LOW)&&(state[1] == 0)) {
  }

  Mi.update ();
  if ((Mi.read() == HIGH)&&(state[2] == 0)) {
    noteOn(144,64,127);
    state[2] = 1;
  }
  if ((Mi.read() == HIGH)&&(state[2] == 1)) {
  }
  if ((Mi.read() == LOW)&&(state[2] == 1)) {
    noteOn(128,64,127);
    state[2] = 0;
  }
  if ((Mi.read() == LOW)&&(state[2] == 0)) {
  }

  Fa.update ();
  if ((Fa.read() == HIGH)&&(state[3] == 0)) {
    noteOn(144,65,127);
    state[3] = 1;
  }
  if ((Fa.read() == HIGH)&&(state[3] == 1)) {
  }
  if ((Fa.read() == LOW)&&(state[3] == 1)) {
    noteOn(128,65,127);
    state[3] = 0;
  }
  if ((Fa.read() == LOW)&&(state[3] == 0)) {
  }

  So.update ();
  if ((So.read() == HIGH)&&(state[4] == 0)) {
    noteOn(144,67,127);
    state[4] = 1;
  }
  if ((So.read() == HIGH)&&(state[4] == 1)) {
  }
  if ((So.read() == LOW)&&(state[4] == 1)) {
    noteOn(128,67,127);
    state[4] = 0;
  }
  if ((So.read() == LOW)&&(state[4] == 0)) {
  }

  La.update ();
  if ((La.read() == HIGH)&&(state[5] == 0)) {
    noteOn(144,69,127);
    state[5] = 1;
  }
  if ((La.read() == HIGH)&&(state[5] == 1)) {
  }
  if ((La.read() == LOW)&&(state[5] == 1)) {
    noteOn(128,69,127);
    state[5] = 0;
  }
  if ((La.read() == LOW)&&(state[5] == 0)) {
  }

  Ti.update ();
  if ((Ti.read() == HIGH)&&(state[6] == 0)) {
    noteOn(144,71,127);
    state[6] = 1;
  }
  if ((Ti.read() == HIGH)&&(state[6] == 1)) {
  }
  if ((Ti.read() == LOW)&&(state[6] == 1)) {
    noteOn(128,71,127);
    state[6] = 0;
  }
  if ((Ti.read() == LOW)&&(state[6] == 0)) {
  }

  Do2.update ();
  if ((Do2.read() == HIGH)&&(state[7] == 0)) {
    noteOn(144,72,127);
    state[7] = 1;
  }
  if ((Do2.read() == HIGH)&&(state[7] == 1)) {
  }
  if ((Do2.read() == LOW)&&(state[7] == 1)) {
    noteOn(128,72,127);
    state[7] = 0;
  }
  if ((Do2.read() == LOW)&&(state[7] == 0)) {
  }

  Re2.update ();
  if ((Re2.read() == HIGH)&&(state[8] == 0)) {
    noteOn(144,74,127);
    state[8] = 1;
  }
  if ((Re2.read() == HIGH)&&(state[8] == 1)) {
  }
  if ((Re2.read() == LOW)&&(state[8] == 1)) {
    noteOn(128,74,127);
    state[8] = 0;
  }
  if ((Re2.read() == LOW)&&(state[8] == 0)) {
  }
}

void noteOn(int cmd, int pitch, int velocity) {
  Serial.write(cmd);
  Serial.write(pitch);
  Serial.write(velocity);
}

本来は、Serial MIDI ConverterでMIDI信号をMacに入力する予定でしたが、何故か鳴ってくれない(おそらくjavaのバージョンアップが原因)ので、ArduinoからMIDI-OUTを出し、それをUSB-MIDIケーブルでMacに入力。

あとはGarageBandを起動すれば、各段に応じた音が鳴ります。

2012年10月19日

Raspberry Piが届いた


注文していたRaspberry Piがようやく到着。
既に他のブログに掲載されているような紙箱ではなく、こんな感じのプラスチックケース入り。
教育機関などで大量購入、大量保管するときは非常に便利そう。


中は帯電防止ビニール袋に包まれたRaspberry Pi本体とクイックスタートガイド系の紙が2枚入っている。


一緒に買ったクリアケースに入れてみたところ。


クリアケースは土台と上部に分かれていて、土台に固定すると外しにくい感じ。
上部は簡単に外せる感じになっていて、普段はケース、時々GPIOで遊ぶ、なんて使い方にも優しい設計。

もう少し落ち着いたらこれで遊んでみようと思います。

2012年9月10日

Li-po Riderとかソーラーとか


9/8〜9/10まで秋葉原のワシントンホテルに滞在、電子パーツ屋さん等で色々買い物してました。

千石電商でLi-po Rider(950円)と1Wソーラーパネル(560円)とJST-XHのケーブル付きコネクタ(メス50円*2、オスメスセット80円)を購入。

aitendoでNokia3300-LCD(500円*2)とLi-poの310mAh(690円)と820mAh(850円)を購入。
このLi-poに千石電商で購入したJSTコネクタ付きのケーブルをハンダ付けで接続。


千石電商で買ったLi-po Rider、ビニールの外側には下記の様に「V1.0の(中略)コネクタはJST型(XHP)2Pです。」とあるが...


実際に入っているのはV1.1で、コネクタがJST-XH(2.5mmピッチ)からJST-PH(2mmピッチ)に変更された最新版。


以下は横に並べて撮った写真。


左のコネクタがJST-PH(2mmピッチ)で、右のコネクタ2つがJST-XH(2.5mmピッチ)。
千石電商に騙される形で買ってしまった訳ですが... せっかく買ってきたので手を加えてみる。


JST-XHコネクタ(ケーブル付き)をJST-PHコネクタの足部分に直接ハンダ付け。
XHもPHも接続できるLi-po Rider V1.1(改)が完成。


無事、充電開始されました。


ソーラーパネルからも充電できることを確認、逆にLi-poから5V出力でArduino UNO等へ給電できることも確認。

色々と遊べる幅が広がりそうな予感。

2012年8月31日

HTC EVO WiMAXにCyanogenMod9(Unofficial)をインストールする


HTC EVO 3D ISW12HTに機種変更してから、充電と放電をひたすら繰り返すだけのEVO WiMAXがあまりにも可哀想なので、とりあえず常用できそうなCyanogenMod9 Nightlyを入れた時のメモ。

大雑把な手順は、S-OFF→CWM→CM9という感じ。
今回は、全く非公式的な手段をやったことがなく、ファームウェアも最新のEVO WiMAXにインストールする場合(要するに最も手順が多い場合)の手順を書きます。

1. PCにドライバをインストール
32bit、64bitそれぞれ向けのドライバをインストールする。
HTC Syncをインストールすればドライバが自動的に適用されるが、HTC Syncを使わない場合はドライバ単体をインストールした方が良い。
HTC_Driver.zipやHTC_Driver_64.zipで検索すると出てくるはず。

2. ファームウェアのダウングレード
RUUを使って初期まで戻し、2.19.970.1までアップデートする。
(この手法を使えばS-OFFの端末をS-ONさせることも可能。修理に出す際に捗る。)
ここに詳しい手順が載ってるので参照されたし。
本来、表にでるはずのないRUUが何故かダウンロードできたりするところもある。

3. S-OFFからCWM導入まで
Revolutionaryを利用する。
ここに詳しい手順が載ってるので参照されたし。

4. CyanogenMod9を焼く
この辺を読みつつ、ここから新しめのイメージをダウンロードする。
ダウンロードしたzipは解凍しないでEVO WiMAXのSDカード直下に入れる。
ついでにCyanogenMod 9向けのGAppsをここからダウンロードして、同様にSDカード直下に入れる。
EVO WiMAXの電源を切り、ボリュームボタンの下を押しながら電源ON。
BOOTLOADERからRECOVERYを選択するとCWMが起動するので、install zip from sdcardを選択、choose zip from sdcardを選択、ダウンロードしてきたイメージのzipを選択。
画面の表示に従って適当にインストールを進め、同様にGAppsもインストール。

少々時間のかかる再起動を経て、ようこそ画面が表示されるので、言語で日本語(ただしCJKフォント)を選択する。


あとは、画面表示の指示に従って設定していけばOKです。


ここまで来て、何も分からない人がやってるとは思っていませんが一応警告
この状態の端末は、USBつないでadb shellやるとroot権限で弄れたりする。
メインの端末として利用している場合は、くれぐれも置き忘れたり置きっぱなしで席を離れたりしないように。
パターンロックやらパスコードやら設定していても無駄ですので。
あと、できればGMailやらWalletの決済情報やらが詰まったアカウントでやらないことをお勧めする。
分かってる人は分かっているなりにセキュリティ施すと思うので、くれぐれも自己責任で。

2012年8月25日

セキュリティさくら#05

8月25日開催の熊本情報セキュリティ勉強会「セキュリティさくら」#05について、参加記録と今後の為のメモ。

今回で参加5回目、皆勤賞更新中。
今回の装備は、MacBook Pro Retina、iPad3、iPhone4S、HTC EVO 3Dという感じ。
残念ながらネタ不足&準備検証の為に時間が割けないため、LTはしませんでした。

本会
・場所は前回と同じく、桜の馬場 城彩苑 2F 多目的交流室
→やはり、この会場のアクセス・利用料・許容人数が一番安定だと思われる。

・辻さん「WHAT IS ANONYMOUS」
→Nanorymousの辻さんによるAnonymousについての講演。
→今までのオペレーションやAnonymousという団体の変遷などを解説されました。

・新井さん「俺ってそんなにシェルコードばっかり見てるイメージある?それどこ情報?どこ情報よー?」
→前回もマルウェアについて講演された新井さんによるシェルコードの読み方(≒目grep)
→PDFに仕組まれているコードの解析をDEMOを交えて解説されました。
→IDA Pro、FileInsight、scSigsなどなど。

・前田さん「Stuxnet, Duqu, Flame, Gauss What is next?」(LT#01)
→第3回でも講演して頂いたカスペルスキーのチーフセキュリティエヴァンゲリストの前田さんによるマルウェアのお話。
→頭文字が「SDFG」と来たので次は「H」で確定(キー配列)
→Stuxnet以外は諜報活動が目的のように見える、初期感染・拡散手法が巧妙である。

・吉井さん「スマートフォン・プライバシー・イニシアティブ 〜読むのが面倒な人へ」(LT#02)
→総務省が8月7日に発表した提言についての概要。
→アプリやサービスが収集した情報の扱い方など、個人情報保護法と照らし合わせたお話。

・@parin1213 & @reiji1020「長崎のすゝめ」(LT#03)
→長崎県内でのイベント・勉強会などについてのアピール。

・Sn0wくん「セキュリティキャンプ2012中央大会に参加してきて」(LT#04)
→今年から「プログラミング」が消えて「セキュリティキャンプ」になったにセキュキャンついてのお話。

懇親会
・上通を抜けて並木坂のローソンから右に曲がった先にあるGRILL de GYANというお店(セキュさくら御用達)
→今回は、前回の反省点を踏まえて主菜を多くしてもらったとのことで、10代も満足できたのではないかと思います。
→二次会で大木さんが「幻の焼酎、結局1滴も残って無くて飲めなかった」とか言っておりましたが、大木さん、あなた車で来てるでしょ!!

総評
前回も書いたとおり、この位の規模の勉強会の中では理想形と言えると思います。
約1年前の初回から参加しておりますが、徐々に進化していく様子を見ることができ、とても勉強になっています。
気になる点は、セキュリティに興味が無い人たち(完全に人脈作りの為だけに来ていると思える人)の興味ゼロの態度。
セキュリティさくらは「IT系の人が集まって交流すること」自体が主目的では無いはず。
交流会をやりたい人は、別途、自分の目的を達成出来るイベントに行って欲しいと思う。
日々の激務で疲労がたまっているだろう人たちの居眠りは理解できるが、明らかに興味がないことを示す居眠りというのは失礼である。
1周年を迎え、勉強会の趣旨というものを、もう一度見直す時期に来ているのかもしれません。

告知
ハードウェア(低レイヤ・低レベル)勉強会を9月中にやりたい...やります。 →12月開催で調整中です。
とりあえず、少人数(20以下)で良いので「こういう勉強会やりました!」という実績作りから一歩を踏み出すことが必要かと。
進行状況は、KPF#x07で報告したことから全く進んでおりません。
原因は、あれもこれもそれも...という欲張りがもたらす八方塞がりでしょう。
まずは大成功でなくても良いので、興味のある人が一カ所に集まる勉強会を作ることを目指そうと思います。

2012年8月13日

AE-UM232RでATmega328PにOptibootを書き込む


基本的なことは「(番外) FTDI BitBang AVR-Writer」の内容と同じですが、参照したページのavrdude-GUIを使った手順が若干理解しづらい&ATmega328Pの場合が記載されていないので、以下まとめ。

配線やPCとAE-UM232Rの接続、ドライバの導入までは前述のページ「3.ソフトウェアの準備」までと同じ。
補足としては .NET Frameworkをインストールしていない場合、最新版の4.0に2.0は含まれていないので、3.5をインストールする必要がある。

次にヒューズビットの設定(外部クロック使用)とOptibootの書き込み。

1.avrdude-GUI.exeを起動する
2.avrdude.exe Fileにavrdude-serjtag\binaryフォルダ配下のavrdude.exeを指定する
3.Programmerに FT232R Synchronous BitBang (diecimila) を選択する
4.Deviceに ATmega328P(m328p) を選択する
5.Command Line Optionに -P ft0 -B 4800 を入力する
6.FuseをReadすると hFuse:D9、lFuse:62、eFuse07 が読み出される (新品未使用の場合)
7.Fuseを hFuse:DA、lFuse:FF、eFuse:05 と入力し、Writeする
8.Command Line Optionから-B 4800を消す (-P ft0のみ入力された状態) ← 超重要
9.Flashでoptiboot_atmega328.hexを選択し、Erase-Write-Verifyする

手順7で外部クロックを使用する設定にしたので、手順8で -B 4800 (ビットクロック指定)を外す必要がある。
※外さない場合、書き込み中にavrdude-GUIがフリーズする。

大量に書き込む時などは、以下のような感じで手順でOK

1.ATmega328Pをセット

2.コマンドラインオプション -P ft0 -B 4800 でFuseをRead

3.hFuse DA、lFuse FF、eFuse:05でFuseをWrite

4.コマンドラインオプションを -P ft0 にしてhexをFlash

5.書き込み済みATmega328Pを取り外す

繰り返し(1へ)

ちなみに、今回のヒューズビット設定は外部クロック使用時なので、内部クロック8MHzで動作させる時は hFuse:DA、lFuse:E2、eFuse:05 など適宜設定する。

2012年7月13日

球面プロッタ完成 (SPG20-332 + MP4401 その3)


Arduinoでステッピングモータ SPG20-332を回すやつの続きの続き。
Arduino側の制御プログラムが完成し、残りはベクターデータから(相対)座標を取り出してArduinoにコマンドを送るプログラムの制作のみ。

とりあえず、簡単な図形ということで、星型を描かせてみました。



始点と終点がずれているのは、ボールの回転軸が微妙にずれているため。
工作精度 or 強度の問題なので、ボールをしっかりと軸の中心に固定できるように固定具を作り直す必要がありそうです。

プログラムはこんな感じ。
鬼のようなネストなど存在しない。(エレガントに書き直す気力が無いので放置)
#include <Servo.h>

#define SERVO_PIN 3 //サーボモータの接続ピン
#define PEN_UP_ANGLE 115 //ペン上げ角度
#define PEN_DOWN_ANGLE 100 //ペン下げ角度
#define MOTOR_DELAY 7 //励磁間隔

const byte motorPen[]={
  0x09,0x0C,0x06,0x03}; //ペン軸 励磁パターン
const byte motorBall[]={
  0x30,0x60,0xC0,0x90}; //ボール軸 励磁パターン
Servo servoPen; //ペン持ち上げ用サーボを定義
char incoming[100]; //シリアルからのコマンド受け取り用
int x,y; //移動先座標と差分
int magDrivePen,magDriveBall; //現在の励磁状態を記憶

void setup(){
  DDRB |=B00001111; //ポートB出力設定
  DDRD |=B11110000; //ポートD出力設定
  servoPen.attach(SERVO_PIN); //サーボ出力ピン設定
  servoPen.write(PEN_UP_ANGLE); //ペン持ち上げ
  Serial.begin(9600); //シリアル通信9600bps
}

void getCommand(char *buf) //シリアル通信から座標を取得
{
  int i = 0;
  char c;
  while(1){
    if(Serial.available()){
      c = Serial.read();
      buf[i] = c;
      if (c == '\n') break;
      i++;
    }
  }
  buf[i] = '\0';
}

void movePenForward() //ペン前進
{
  magDrivePen++;
  if(magDrivePen>3)magDrivePen=0;
  PORTB &=0xf0;
  PORTB |= motorPen[magDrivePen];
  delay(MOTOR_DELAY);
}

void movePenBackward() //ペン後進
{
  magDrivePen--;
  if(magDrivePen<0)magDrivePen=3;
  PORTB &=0xf0;
  PORTB |= motorPen[magDrivePen];
  delay(MOTOR_DELAY); 
}

void moveBallForward() //ボール前進
{
  magDriveBall++;
  if(magDriveBall>3)magDriveBall=0;
  PORTD &=0x0f;
  PORTD |= motorBall[magDriveBall];
  delay(MOTOR_DELAY);
}

void moveBallBackward() //ボール後進
{
  magDriveBall--;
  if(magDriveBall<0)magDriveBall=3;
  PORTD &=0x0f;
  PORTD |= motorBall[magDriveBall];
  delay(MOTOR_DELAY); 
}

void writing(int dx, int dy) //座標移動(Bresenhamの線描アルゴリズム)
{
  int e = 0; //誤差蓄積用
  if(abs(dx) > abs(dy)){ //傾きが1未満の場合
    if(dx>=0){ //x軸方向が正の場合
      for (int sx = 0; sx < dx; sx++) {
        movePenForward();
        if(dy>=0){ //y軸方向が正の場合
          e += dy;
          if (e > dx){
            e -= dx;
            moveBallForward();
          }
        }
        else{ //y軸方向が負の場合
          e += abs(dy);
          if (e > dx){
            e -= dx;
            moveBallBackward();
          }
        }
      }
    }
    else{ //x軸方向が負の場合
      for (int sx = 0; sx < abs(dx); sx++) {
        movePenBackward();
        if(dy>=0){ //y軸方向が正の場合
          e += dy;
          if (e > abs(dx)){
            e -= abs(dx);
            moveBallForward();
          }
        }
        else{ //y軸方向が負の場合
          e += abs(dy);
          if (e > abs(dx)){
            e -= abs(dx);
            moveBallBackward();
          }
        }
      }
    }
  }
  else{ //傾きが1以上の場合
    if(dy>=0){ //y軸方向が正の場合
      for (int sx,sy = 0; sy < dy; sy++) {
        moveBallForward();
        if(dx>=0){ //x軸方向が正の場合
          e += dx;
          if (e > dy){
            e -= dy;
            movePenForward();
            sx++;
          }
        }
        else{ //x軸方向が負の場合
          e += abs(dx);
          if (e > dy){
            e -= dy;
            movePenBackward();
            sx++;
          }
        }
      }
    }
    else{ //y軸方向が負の場合
      for (int sx,sy = 0; sy < abs(dy); sy++) {
        moveBallBackward();
        if(dx>=0){ //x軸方向が正の場合
          e += dx;
          if (e > abs(dy)){
            e -= abs(dy);
            movePenForward();
            sx++;
          }
        }
        else{ //x軸方向が負の場合
          e += abs(dx);
          if (e > abs(dy)){
            e -= abs(dy);
            movePenBackward();
            sx++;
          }
        }
      }
    }
  }
}

void loop(){
  getCommand(incoming); //シリアルから読み込み

  char *cmdX, *cmdY, *cmdPen;
  int penUpDown;

  if(incoming){ //座標系、ペン状態別にコマンドを分離
    cmdX = strtok(incoming,",");
    cmdY = strtok(NULL,",");
    cmdPen = strtok(NULL,",");
    penUpDown = atoi(cmdPen);
  }

  if(penUpDown == 0)servoPen.write(PEN_UP_ANGLE); //ペン上げ
  if(penUpDown == 1)servoPen.write(PEN_DOWN_ANGLE); //ペン下げ
  delay(200); //サーボの動作待ち

  x=atoi(cmdX); //charからintへ変換
  y=atoi(cmdY);

  writing(x,y); //指定座標へ移動
  
  Serial.print("X:");
  Serial.print(cmdX); //ペン軸の移動量表示
  Serial.print("/Y:");
  Serial.print(cmdY); //ボール軸の移動量表示
  Serial.print("/Pen:");
  Serial.println(cmdPen); //ペンの上げ下げ状態表示
}
ポイントはブレゼンハムの線分アルゴリズム。
傾きが1以外(1より大きい or 1より小さい)の時も真っ直ぐに線を引くために使いました。

でもって、Processing側はこんな感じの雑なコード。(あくまでも動作確認用なので)
実際は、Arduinoから返ってくる座標とペン状態を受け取ってから次のステップに移るようにする必要がある。
import processing.serial.*;
Serial port;
 
void setup()
{
  size(100,100);
  port = new Serial(this, "/dev/tty.usbmodem1421", 9600);
  port.clear();
}
 
void draw() {
  for(int i=0;i<=4;i++){
  delay(1500);
  port.write("-15,43,1\n");
  delay(1500);
  port.write("38,-30,1\n");
  delay(1500);
  port.write("-45,0,1\n");
  delay(1500);
  port.write("38,30,1\n");
  delay(1500);
  port.write("-15,-43,1\n");
  delay(1500);
  port.write("-1,80,0\n");
  }
  exit();
}

余談
写真の左上にチラッと見えてるパソコンは、最近買ったMacBook Pro Retinaディスプレイモデルのフルカスタムマシン。
こいつのUSBポートから電源を取ると、Arduino UNOにACアダプタを刺さなくても普通に動作しました。

2012年7月1日

GarageBand Mac版からiOS版にプロジェクトデータを持っていく方法


今のところiOS版で作ったプロジェクトデータはMac版で展開できますが、逆にMac版のデータをiOSで展開することは出来ません。

しかし、プロジェクトデータの構造を調べてみたところ、基本的にはMac版とiOS版に違いはなく、色々試してみたところ、以下の方法でMac版のプロジェクトデータをiPadに持っていくことが出来ました。

注意点として、音声データ(リアル音源データ)が含まれるプロジェクトでは試していないので持っていけるかどうか不明。
もう一つ、iOS版に持っていくデータはiOS版GarageBandの都合上、8トラックまでに減らしておくこと。
また、iOS版GarageBandに存在しない音源で鳴らすことは出来ないため、あらかじめMac版でGrand Pianoなどにしておくことをお勧めする。

手順は以下から。

2012年6月28日

SPG20-332 + MP4401 その2


Arduinoでステッピングモータ SPG20-332を回すやつの続き。
葉山先生の華麗なるアルミ板とPOM板加工によって上の写真(左)のような状態に。
卓球のピンポン球に絵を描くということでピン球botと命名され、あとを任されました

ボールを回転させる軸とペンの向きを変える軸の2軸なので、少し接続を変更。


pin 4〜7に接続したステッピングモータをボールの軸、pin 8〜11に接続したステッピングモータをペンの軸とする。


ATmega168/328のI/OポートはB、C、Dの3つで、port Bがpin 8〜13、port Cがpin A0〜A5、port Dがpin 0〜7となっている。
ローレベルかつ高速に制御したい時は、これらのポートのコントロールレジスタを直接いじってあげれば良い。→Reference/PortManipulation
(というのも、前回の記事で載せた方式で制御しようとすると励磁する速度の問題で細かい振動が発生するっぽいので)
プログラムはこんな感じで。
#include <Servo.h>
const byte motorPen[]={0x03,0x06,0x0C,0x09}; //PortBの励磁パターン
const byte motorBall[]={0x90,0xC0,0x60,0x30}; //PortDの励磁パターン
Servo servoPen;

void setup(){
  DDRB |=B00001111; //PortB 8,9,10,11
  DDRD |=B11110000; //PortD 4,5,6,7
  servoPen.attach(3);
}

void loop(){
 for(int n=0;n<20;n++){
   servoPen.write(100);
   for(int i=0;i<4;i++){
     PORTB &=0xf0;
     PORTB |= motorPen[i];
     PORTD &=0x0f;
     PORTD |= motorBall[i];
     delay(8);
   }
 }
 for(int n=0;n<20;n++){
   servoPen.write(115);
   for(int i=3;i>=0;i--){
     PORTB &=0xf0;
     PORTB |= motorPen[i];
     PORTD &=0x0f;
     PORTD |= motorBall[i];
     delay(8);
   }
 }
}

DDRB |= B00001111でポートBの下位4ビット(pin 11,10,9,8)を出力に設定。
DDRD |= B11110000でポートDの上位4ビット(pin 7,6,5,4)を出力に設定。
PORTBとPORTDを初期化し、あらかじめ定義しておいたモータの励磁パターンを投げてあげるという仕組み。
サーボはペンの持ち上げに使用。

これで、以下の動画のように動作する。


行き(右から左)はペン先をボール表面に降ろし、帰り(左から右)はペン先を持ち上げています。

次は起動時のゼロ点補正機構と、座標指定で描いてくれるようなプログラムを作っていきます。

2012年6月24日

SPG20-332 + MP4401


Arduinoでステッピングモーター SPG20-332(≒SPG20-1332)を回す。
モータードライバーとしてMP4401を使う。
Fritzingの練習も兼ねて作ってみた接続図。
(同梱されてたステッピングモーターのSVGを弄ってSPG20-S332用にピン配置を変更しています)

Arduino     MP4401  
 pin 10 ----- pin 01
 pin 11 ----- pin 12
 pin 12 ----- pin 05
 pin 13 ----- pin 08

MP4401   SPG20-332
 pin 02 ----- pin 1
 pin 09 ----- pin 6
 pin 11 ----- pin 2
 pin 04 ----- pin 5

MP4401のpin3とpin10をVinに、pin6とpin7をGNDに接続、SPG20-332のpin3とpin4をVinに接続。
今回は2相励磁で回すのでArduinoには7.5VのACアダプタを接続しました。
(7〜9Vくらいの電源なら良いんじゃないかと)

プログラムはこんな感じでいいはず。
int pin[4] = {10,11,12,13};

void forward(int rot){
  for(int i=0;i<rot*120;i++){
    for(int i=0;i<4;i++){
       int prev = i-1;
       int next = i+1;
       if(prev < 0) prev = 3;
       if(next > 3) next = 0;
       digitalWrite(pin[prev], LOW);
       digitalWrite(pin[i], HIGH);
       digitalWrite(pin[next], HIGH);
       delay(2);
     }
   }
}
void reverse(int rot){
  for(int i=0;i<rot*120;i++){
     for(int i=3;i>=0;i--){
       int prev = i+1;
       int next = i-1;
       if(prev > 3) prev = 0;
       if(next < 0) next = 3;
       digitalWrite(pin[prev], LOW);
       digitalWrite(pin[i], HIGH);
       digitalWrite(pin[next], HIGH);
       delay(2);
     }
   }
}

void setup(){
  for(int i=0;i<4;i++){
    pinMode(pin[i], OUTPUT);
  }
}

void loop(){
  forward(1); // 1回正転
  reverse(1); // 1回逆転
  forward(3); // 3回正転
  reverse(3); // 3回逆転
  forward(5); // 5回正転
  reverse(5); // 5回逆転
}

2相励磁なのでトルクは十分。
ステッピングモーターを2個使ってプロッタとか作ってみたいなぁと思っているところです。

追記:ポートレジスタで制御する方法を書きました → SPG20-332 + MP4401 その2

2012年6月23日

セキュリティさくら#04

6月23日開催の熊本情報セキュリティ勉強会「セキュリティさくら」#04について、参加記録と今後の為のメモ。

本会
・場所は桜の馬場 城彩苑 2F 多目的交流室
→交通センターもしくは市電熊本城前電停から少し歩く必要があるが、県外参加者には熊本城が見えるところを歩いてもらえるので良いと思う。

・相戸さん「やってみよう緊急対策訓練」
→さくら開催史上初の彼女同伴講演。
→企業の情報セキュリティの裏側、実際に発生したとき動けるのか?という点、実話を軸にしたお話、凄く良かったです。聞いて良かった。

・新井さん「来ちゃった…リア充の王を追いかけてクマモンの国まで…(仮)」
→マルウェア解析界の聖書「アナライジング・マルウェア」の著者によるお話。
→各種マルウェア検体サイトの紹介は役立ちそう(contagio、KernelMode.info、OpenMalware.org)

・高倉先生「新しい攻撃手法について(追)」
→前回(#03)から4ヶ月、更に高度な標的型攻撃の現状と対策手法についてのお話。
→「入口も出口も内部も固める」「ルータ、スイッチの設定まで監視」というお話は非常に興味深かったです。

・まっちゃさん「IT勉強会カレンダーについて」
→自動かと思いきや全手動で運営中のIT勉強会カレンダーについての説明のお話。
→閲覧しやすいアプリの紹介や、カレンダーに登録する際の裏話など色々。運営お疲れ様です。

・松村君「セキュリティキャンプの紹介」
→つけ麺おんのじの紹介

・自分「ハードウェアセキュリティ(真)」
→今回は真面目すぎて面白くなかったです。反省中。
プレゼン資料は以下です。


懇親会
・上通を抜けて並木坂のローソンから右に曲がった先にあるGRILL de GYANというお店(前回と同じ)
→今回、60人近い人数にもかかわらず2Fに全員収容出来たのは凄い。
→持ち込みも可能だったので、色々と美味しく頂きました。

総評
勉強会として洗練されてきたイメージ。
ただ、気軽に参加出来る感とのトレードオフであるかもしれないと感じてしまう面もありました。
他県からの参加者にも非常に好評でした。
隣県の勉強会が「利益の出し方」を中心としているなら、さくらは「探求心」を中心としているので良いという意見も。

2012年5月6日

お手製パネルスイッチ


前回のピアノ階段(GarageBand階段)計画の続き。
ハンズマンでアルミテープと厚手両面テープを、HIヒロセで下敷き2枚を購入。

アルミテープ:厚さ0.1mm、幅50mm、長さ20m
厚手両面テープ:厚さ0.5mm、幅30mm、長さ15m
下敷き:厚さ0.7mm、B5サイズ


下敷きの長辺外側に厚手両面テープを、中央にアルミテープを貼ったものを2枚作る。
両面テープを剥がして向かい合わせに貼り合わせると完成。

単純計算だと厚手両面テープ*2で1mm、アルミテープ*2で0.2mmなので、向かい合わせになったアルミテープの間には0.8mmの隙間ができることになる。


前回と同様、プルダウン、1kΩの抵抗を使用、デジタル13ピンに接続。
スケッチも前回のまま使うので「ド(C3)」の音が割り当てられています。


実際に実行してみました。


課題としては両面テープの部分は押しても反応しない(当然)こと。
細くすると板(今回は下敷きを使用)のたわみで何もしなくても引っ付いてしまう可能性も。

実際に階段に設置する際は、踏まれることを考慮して接点の位置や素材を工夫する必要があるかも。

2012年4月22日

Arduino + GarageBand (MIDIキーボードもどき)


久しぶりの投稿にして久しぶりのArduinoネタ。

ボタンを押すとドレミファソラシドが鳴るというもので、やっていることは至って簡単。
どのタクトスイッチが押されてるか判定してSerial.printで吐き出し、Mac側でSerial MIDI Converterなるソフトを使ってIAC DriverにMIDI信号を渡し、GarageBandで読み取る。
Arduino → Serial MIDI Converter → IAC Driver → GarageBandというフロー。

ブレッドボード上のタクトスイッチはプルダウン、抵抗は1KΩを入れてある。
チャタリング除去はソフトウェア側にお任せ。(Bounceライブラリを使用)
#include <Bounce.h>

byte pins[8] = {13,12,11,10,9,8,7,6};
byte pitch[8] = {60,62,64,65,67,69,71,72};
int status[8] = {0};

Bounce button[] = {Bounce(pins[0],20),
                   Bounce(pins[1],20),
                   Bounce(pins[2],20),
                   Bounce(pins[3],20),
                   Bounce(pins[4],20),
                   Bounce(pins[5],20),
                   Bounce(pins[6],20),
                   Bounce(pins[7],20)};

void setup() {
  for (int i=0; i< 8; i++) {
    pinMode(pins[i], INPUT);
  }
  Serial.begin(57600); 
}

void loop(){
  for (int i=0; i< 8; i++) {
    button[i].update ();
    
    if ((button[i].read() == HIGH)&&(status[i] == 0)) {
      MIDI_TX(144,pitch[i],127);
      status[i] = 1;
    }if ((button[i].read() == LOW)&&(status[i] == 1)) {
      MIDI_TX(128,pitch[i],127);
      status[i] = 0;
    }if ((button[i].read() == HIGH)&&(status[i] == 1)) {

    }if ((button[i].read() == LOW)&&(status[i] == 0)) {
    
    }
  }
}

void MIDI_TX(unsigned char MESSAGE, unsigned char PITCH, unsigned char VELOCITY) 
{
  Serial.print(MESSAGE);
  Serial.print(PITCH);
  Serial.print(VELOCITY);
}
という感じ。
#相変わらずエレガントさに欠けるなぁ...

MIDIのメッセージについては、144がCh1のNote ONで128がCh1のNote OFFである。
144-128=16で分かるとおり、16チャンネル扱えることが分かる。
ピッチは鍵盤中央のドを60として半音ごとに1増減という仕様。

実際に音を鳴らしてみたり。(黒鍵はブレッドボード上に未実装なので白鍵だけ)

※画面録画です。(手元は上の写真を見てご想像ください)

あとは、このタクトスイッチを踏んでも大丈夫な別の素子に変えて階段に仕掛ける予定。
元ネタはフォルクスワーゲンのピアノ階段という動画。
前々から真似してみたかったので、今年の学園祭で学校に同様の物を仕掛けようかと画策中。

問題はArduino UNO(328)だと入力が足りないこと。
アナログをデジタルに回しても20本しかないので、1オクターブとちょっとしか対応出来ない。
Mega(2560)を使う or UNO(328)を多段にするなど考え中...
追記
シフトレジスタ(PISO)の74HC165を使って入力を増やす方法を教えてもらいました。
時間がある時に試してみます。
本家(ピアノ階段)で使ってる踏んだ時に感知する方法が気になる...
フィルムタイプの圧力センサは高いので代替できる手段を調査中。

追記
階段用スイッチの仕組みを考えました。 → お手製パネルスイッチ

追記2
GarageBand階段、完成しました。 → Arduinoでピアノ階段 with GarageBand

2012年3月30日

Final Cut Express 4をインストールするとAperture 3が起動しない件

久々にMacBook Proで動画編集でもしようかとFinal Cut Express 4をインストールしてみたら、直後からAperture 3が起動不能に。
日本のAppleサポートコミュニティはおろか米国のAppleサポートコミュニティにも対応策が無いという状態。

エラーの発生環境はMac OS X Lion (10.7.3)で、別ユーザを作成しての確認、Apertureの再インストールでは治らず。
という訳で、エラーを解析してみる。

Library not loaded: /Library/Frameworks/PluginManager.framework/Versions/B/PluginManager

とあるので、おそらく原因はPluginManagerというファイルが存在しないことだろう。
Versionsフォルダへ移動してみると、フォルダ「B」が存在しない。
現在Aperture 3が普通に起動できるMacBook AirのVersionsフォルダを覗くとフォルダBと、その中にPluginManagerが存在していた。
これをMacBook Proにコピーすると、何事も無かったのようにAperture 3が起動。

とりあえず、PluginManagerを置いておきますので、同様のエラーで困ってる人はやってみてください。

Download >> PluginManager.zip (115KB)

2012年3月29日

極小キャラクタ液晶


3/18〜21まで秋葉原駅から徒歩5分もかからない秋葉原ワシントンホテルに滞在していました。

とりあえず、予てから実物を見てみたかったaitendo(液晶工房)の極小キャラクタ液晶16x2を購入。
早速、熊本に帰って極小キャラクタ液晶を動かしてみたのが一番上の写真。
裏返して右から1〜16となっており、1番がGNDで2番がVdd(+5V)という点が普通サイズと違うところ。
バックライトは16がGNDで15が5Vで、1と16、2と15を接続、間に5Ωくらいの抵抗を入れてやれば良いらしい。
(手元に10Ω〜しか置いてなかったので、抵抗入れずに直結してるけど今のところ問題なし)

普通サイズの16x2液晶と比較
Pro miniや発売予定のleonardoあたりと一緒に使うと便利な予感。
というわけで、千石電商でArduino Pro miniとFT232RL搭載の書き込み基板も買ってきました。


とりあえず、足付けて13番ピンのLEDチカチカさせるスケッチ動かして動作確認だけ。

この書き込み基板、よく見るとシルクスクリーン印刷が間違っている稀少ロット(?)であることが判明。


この基板は5V用ですが、チップ左の出力をよく見ると3V3になっている。
(出力はちゃんと5V出てる)

裏のパターンを切ってハンダジャンパすれば3V3出力に切り替えることもできるようですが、購入したPro miniは328P 16MHz 5Vのやつなので、そのままで使います。

さて、在庫は潤沢なので何を作るか考えなければ(;゜ロ゜)