「神田くん、ロボットつくらない?」
2016年8月某日、私はふいに声をかけられた。
私の産業技術大学院大学における課外活動の始まりはこの声掛けから始まった。
角田さん(ITエキスパートエンジニア)、上林さん(HCD専門家)などが、こころをクスぐるロボットを作ろうと画策していたところ、目に止まったのが私らしい。
どうやら、私の自己紹介の話が印象的だったので覚えていてくれたとのこと。
※ちなみにこんな感じ大学院デビューを果たしました。「高専に入ってものづくりを学びました。鉄道会社に就職したら書類づくりに明け暮れて、ものづくりの楽しみを最近感じていません。一念発起してものづくりをするためにこの大学院に入学しました。私とものづくりをしましょう。」
かくして、私の充実しものづくりライフが始まった。
1.チーミング
高専では一人でのものづくりが主体だった。
とはいえ、卒研テーマは共同研究のような形だったが、ハードとソフトでjobdiscriptionを定めていたのでそこまでチームワークが必要ではなかった。
今回のロボットづくりは私にとって初めてのチーム作製となった。
コンセプトを掲げ
デザイン案を創り上げ
動作機構を設計・パーツの選定をし
3DCADでモデリングを行い
3DPrinterで出力し
モックアップの表面処理、塗装を行い
組み上げて駆動プログラムの作成
ネットワークから動作命令を受けるプログラムを作成
実機によるキャリブレーションをし、
テスト動作でコンセプトを表現できているかを確認する
ついにPoCの完成、学会発表にこぎつけました。
※私は主に組み込み系の駆動プログラムの作成を担当した。
これらの作業を分担し、コンセプトを共有しながらチームメンバーとインターフェースの調整やスケジュールの調整、開発を自発的に取り組めたのは良い経験になった。
特に、駆動機構の設計、モックアップの組立、ネットワークからの動作との連携は苦労した。
それでも、各インターフェースを理解して自分一人では出来ない速度で組み上がるPoCを見ていて爽快感を感じた。
2.デザインドリブン
上林さんが打ち出したコンセプトにチームメンバーが共感し、メンバーがそのコンセプトを表現してロボットづくりを進めた
スケジュール感としては学会発表はコンセプトなのでモックを作る。
その後、賞をとれば出展が考えられるのでPoCを作ろうとなった。
組込み屋さんとして、「こんな動きは出来る?」に「出来るよ!」と答えたり、逆に「このアクチュエータ使えばこんなこともできるよ」と提案したり。
今回は「てるてる坊主のような存在」だったのでそこまでダイナミックな動きは必要なく、流れるような動きにすることにした。
実際にはステッピングモータを使ったのでカクカク感が否めないが、遠目で全体を見ると流れているように見える。
波の不思議。
3.実装
実装に使える期間は1週間程度だった。
と、言っても「本番環境を使えるのが」だ。
あとの工程が詰まるのはなんとなく予想していたし、久々の組込プログラミングなので、環境構築とサーボモータいじりを前段でやっておくことにした。
Arduinoは私が卒検で使っていたAVRを乗っけたボードである。
なので、私はAVRStudioをインストールし、ISPからの書き込みを模索していた。
かんだ「たしか、昔買ったUSB⇔D-SUB9の変換ケーブルが家にあったな…」
そう、Qiitaの記事を見つけるまでは。
かんだ「え、ArudionIDEで楽々プログラミングできるだと!接続もUSBでできるの!もうレジスタの値をデータシートから引っ張ってこなくていいの!?」
時代は進む。
IDEをインストールしてからLチカ(組込界の「Hello world」)は瞬殺だった。
なんなら、割り込み処理も一瞬だった。
そして、ステッピングモータの制御やLEDの制御も一瞬だった。
(フルカラーチップLEDを使ったけどめっちゃ使いやすい!)
かんだ「こりゃ、Arduino買うわ!UX!UX!!(言いたいだけ)」
そんなこんなで、事前準備は整った。
そしてラスト一週間で実機への実装が始まった。
私の相方はYくん(仮に山田くんとしよう)だった。
彼は偏差値70ぐらいある大学出身の凄腕プログラマー(アプリケーション系)で信用できる男だった。
そんな彼が「RSNPは難解」と言っていたのでRSNPはマジで難解なんだろうなと思った。
そもそもドキュメントとかQiitaみたいなレポート少なすぎるよね☆
RSNPを介してArduinoの割り込みピンを叩きにくるののを彼に任せ、私は実装をした。
実装には4日かかった。
最初の3日は作業時間を確保するために仕事や授業のレポートを片付けた。
最後の一日、徹夜でプログラミングして、動作確認、制御量の微調整を行った。
プッシュスイッチを割込出力にみたてて試行錯誤して完成させた。
徹夜明けに、山田くんに実機を渡し、
かんだ「あとは、このピンに5v出力すると動くよ…パタorz」
と、まぁ、こんな感じで私のパートは終わったのだった。
その後、山田くんの徹夜でロボットは完成した。
山田くん!ありがとう!
4.今回得たもの
展示会(確か国際ロボット展)へのブース展示権利
私が書いたコードも載せときます。
大したことはしてませんが…
#include <Adafruit_NeoPixel.h>
// RGBLEDに出力するピン番号
#define RGBLED_OUTPIN 5
// Arduinoにぶら下がっているRGBLEDの個数
#define NUMRGBLED 9
Adafruit_NeoPixel RGBLED = Adafruit_NeoPixel(NUMRGBLED, RGBLED_OUTPIN, NEO_RGB + NEO_KHZ800);
int val;
int i;
int l=0;
int j=0;
int servoPin,servoData;
int R=0;
void setup(){
pinMode(13, INPUT);
Serial.begin(9600);
pinMode(8, OUTPUT);
pinMode(9, OUTPUT);
pinMode(10, OUTPUT);
pinMode(11, OUTPUT);
pinMode(12, OUTPUT);
RGBLED.begin() ;
}
void loop() {
if(Serial.available() > 0) {
val = Serial.read();
val=0;
if(val == 0) {
rain();
delay(1000);
}else if(val==1) {
shine();
shine();
// delay(10000);
}
}
}
void rain(void){
for(j=0;j<100;j++){
RGBLED.setPixelColor(0,j/3,j/9,j/3) ;
RGBLED.setPixelColor(1,j/3,j/9,j/3) ;
RGBLED.show();
frontservoDrive(j,10);
}
for(i=0;i<3;i++){
// 前振り上げ
for(j=100;j<700;j++){
if(j<250) R++;
if(j>250&&j<400) R--;
if(j>400&&j<550) R++;
if(j>550&&j<700) R--;
RGBLED.setPixelColor(0,j/3,j/9,j/3) ;
RGBLED.setPixelColor(1,j/3,j/9,j/3) ;
// RGBLED.setPixelColor(5,j/3,j/9,j/3) ;
RGBLED.setPixelColor(5,R,R/3,R);
RGBLED.setPixelColor(6,R,R/3,R);
RGBLED.setPixelColor(7,R,R/3,R);
RGBLED.setPixelColor(8,R,R/3,R);
RGBLED.show() ;
frontservoDrive(j,9);
}
// RGBLED.setPixelColor(1,100,0,0) ;
// RGBLED.show() ;
delay(1000);
// 前振り下げ
for(j;j>100;j--){
if(j<250) R--;
if(j>250&&j<400) R++;
if(j>400&&j<550) R--;
if(j>550&&j<700) R++;
RGBLED.setPixelColor(0,j/3,j/9,j/3) ;
RGBLED.setPixelColor(1,j/3,j/9,j/3) ;
RGBLED.setPixelColor(5,R,R/3,R);
RGBLED.setPixelColor(6,R,R/3,R);
RGBLED.setPixelColor(7,R,R/3,R);
RGBLED.setPixelColor(8,R,R/3,R);
RGBLED.show();
frontservoDrive(j,10);
}
// 前振り下げ+後ろ振り上げ
for(j;j>0;j--){
RGBLED.setPixelColor(0,j/3,j/9,j/3) ;
RGBLED.setPixelColor(1,j/3,j/9,j/3) ;
RGBLED.setPixelColor(2,100-j,33-j/3,100-j) ;
RGBLED.setPixelColor(3,100-j,33-j/3,100-j) ;
RGBLED.setPixelColor(4,100-j,33-j/3,100-j) ;
RGBLED.setPixelColor(5,180-j*1.8,60-j*0.6,180-j*1.8);
RGBLED.setPixelColor(6,180-j*1.8,60-j*0.6,180-j*1.8);
RGBLED.setPixelColor(7,180-j*1.8,60-j*0.6,180-j*1.8);
RGBLED.setPixelColor(8,180-j*1.8,60-j*0.6,180-j*1.8);
RGBLED.show() ;
// backservoDrive(200-j*2,10);
// frontservoDrive(j,10);
allservoDrive(j,200-j*2,200-j*2,200-j*2,j,10);
}
// 前振り上げ+後ろ振り下げ
for(j=0;j<100;j++){
if(i<2)RGBLED.setPixelColor(0,j/3,j/9,j/3) ;
if(i<2)RGBLED.setPixelColor(1,j/3,j/9,j/3) ;
RGBLED.setPixelColor(2,100-j,33-j/3,100-j) ;
RGBLED.setPixelColor(3,100-j,33-j/3,100-j) ;
RGBLED.setPixelColor(4,100-j,33-j/3,100-j) ;
RGBLED.setPixelColor(5,180-j*1.8,60-j*0.6,180-j*1.8);
RGBLED.setPixelColor(6,180-j*1.8,60-j*0.6,180-j*1.8);
RGBLED.setPixelColor(7,180-j*1.8,60-j*0.6,180-j*1.8);
RGBLED.setPixelColor(8,180-j*1.8,60-j*0.6,180-j*1.8);
RGBLED.show() ;
// backservoDrive(200-j*2,10);
// if(i<2) frontservoDrive(j,10);
allservoDrive(j,200-j*2,200-j*2,200-j*2,j,10);
}
}
}
void shine (){
int s1=0,s2=0,s3=0,s4=0,s5=0;
for(i=0;i<960;i++) {
if(i<180) s1++;
if(i>60&&i<240) s2++;
if(i>120&&i<300) s3++;
if(i>180&&i<360) s1--,s4++;
if(i>240&&i<420) s2--,s5++;
if(i>300&&i<480) s3--;
if(i>360&&i<540) s1++,s4--;
if(i>420&&i<600) s2++,s5--;
if(i>480&&i<660) s3++;
if(i>540&&i<720) s1--,s4++;
if(i>600&&i<780) s2--,s5++;
if(i>660&&i<840) s3--;
if(i>720&&i<900) s4--;
if(i>780&&i<960) s5--;
allservoDrive(s1*1.2,s2*1.2,s3*1.2,s4*1.2,s5*1.2,8);
RGBLED.setPixelColor(0,s1/3,s1/1.5,s1/20) ;
RGBLED.setPixelColor(4,s2/3,s2/1.5,s2/20) ;
RGBLED.setPixelColor(3,s3/3,s3/1.5,s3/20) ;
RGBLED.setPixelColor(2,s4/3,s4/1.5,s4/20) ;
RGBLED.setPixelColor(1,s5/3,s5/1.5,s5/20) ;
RGBLED.setPixelColor(5,s2/3,s2/1.5,s2/20) ;
RGBLED.setPixelColor(6,s3/3,s3/1.5,s3/20) ;
RGBLED.setPixelColor(7,s4/3,s4/1.5,s4/20) ;
RGBLED.setPixelColor(8,s5/3,s5/1.5,s5/20) ;
RGBLED.show();
}
}
void frontservoDrive(int servoData,int dtime){
digitalWrite(8,HIGH);
digitalWrite(12,HIGH);
delayMicroseconds(900+servoData);
digitalWrite(8,LOW);
// delayMicroseconds(60);
digitalWrite(12,LOW);
delay(dtime-servoData/1000);
// delayMicroseconds(20000-servoData);
}
void allservoDrive(int servoData1,int servoData2,int servoData3,int servoData4,int servoData5,int dtime){
digitalWrite(8,HIGH);
delayMicroseconds(880+servoData1);
digitalWrite(8,LOW);
digitalWrite(9,HIGH);
delayMicroseconds(950+servoData2);
digitalWrite(9,LOW);
digitalWrite(10,HIGH);
delayMicroseconds(880+servoData3);
digitalWrite(10,LOW);
digitalWrite(11,HIGH);
delayMicroseconds(960+servoData4);
digitalWrite(11,LOW);
digitalWrite(12,HIGH);
delayMicroseconds(850+servoData5);
digitalWrite(12,LOW);
delay(dtime-(servoData1+servoData2+servoData3+servoData4+servoData5)/1000);
}
コメント