Arduinoでステッピングモータ SPG20-332を回すやつの続きの続き。
Arduino側の制御プログラムが完成し、残りはベクターデータから(相対)座標を取り出してArduinoにコマンドを送るプログラムの制作のみ。
とりあえず、簡単な図形ということで、星型を描かせてみました。
始点と終点がずれているのは、ボールの回転軸が微妙にずれているため。
工作精度 or 強度の問題なので、ボールをしっかりと軸の中心に固定できるように固定具を作り直す必要がありそうです。
プログラムはこんな感じ。
鬼のようなネストなど存在しない。(エレガントに書き直す気力が無いので放置)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 | #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から返ってくる座標とペン状態を受け取ってから次のステップに移るようにする必要がある。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | 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アダプタを刺さなくても普通に動作しました。
0 件のコメント:
コメントを投稿
記事へのコメントはいつも確認している訳ではないので、お返事が遅れる場合があります。
ご質問やご意見は twitter@9SQ へお送り頂けると早くお返事できると思います。