勝手な電子工作・・

勝手なオリジナル電子工作に関する記事を書きます

オリジナル・レーザープロッター その3 回路基板など

ステッパードライバー(A4988モジュール)の温度を測りました。

この駆動方式の場合、室温28℃で長時間刻印作業をしても次のようにドライバーICの本体は40数℃どまりなので大丈夫ですね。

f:id:a-tomi:20190821093916j:plain

    (光学レンズとサーモの上下差10mmによる若干の視差は未補正です)

ブレッドボードには2つのA4988モジュールを刺してあります。左側はステッパーX、右はYをドライブしています。それぞれ小さな放熱フィンをICに付けてあります。

Y側は殆どの時間をSleepにしてあるため温度は上がりません。

X側への配線の差し込み部も結構高い温度になっています。A4988の配線も放熱を兼ねているわけなのでドライバーからの熱伝導もありますが、ブレッドボードと配線との接触抵抗によるかもしれません。それなりの電流が流れる場所なのでブレッドボード接点は長持ちしないでしょう。

この際、配線がごちゃごちゃしているのはなにかとよろしくないので、すっきり作り直します。どっちみちブレッドボードなのですぐにできます。

これまでのはこれ。

f:id:a-tomi:20190820212621j:plain

同じ回路でも、次のように配線しなおすとすっきりします。また、配線が動きにくいように下敷きをいれて各部を両面テープで固定します。

f:id:a-tomi:20190820212720j:plain

Arduino UNO(互換機)の固定には厚めの「セーフティクッション」というテープ(百均にあった)を裏に重ねています。これでメス穴の高さがブレッドボードとほぼ同じになり、短い固定長ジャンプワイヤーが使えるようになります。

レーザーのデューティ比を変更するポテンオメータ(VR)や、マイクロSDドライブなども厚めの両面テープで下敷きに貼り付けてあります。この機能を加えた最新のプログラムを下のほうに載せておきます。

ポテンシオメータ(VR)への配線をツイストしてある理由は、AD変換にノイズがのらないようにするためです(これだけでノイズはなくなります)。なにせレーザーの強弱コントロールなのでここへの雑音は危険に直結しますから。

 

さて、この試作回路で温度をしつこく再測定してみます。

f:id:a-tomi:20190820214300j:plain

すると長時間稼働しても43.1℃であることがわかります。念のために別の赤外線温度計でその場所を測定してみます。

f:id:a-tomi:20190820214652j:plain

ご覧のとおり42.8℃ですから大丈夫ですね。サーモグラフィーの正確さも分かります。

 

前の記事にも書いたように、ステッパーとドライバーの過熱防止のためには直流を流さないことが大事です。ステッパーが止まっているときはインピーダンスがR成分だけになり発熱しますから。

ここでのやりかたはステッパーを長時間(といっても数十ミリ秒以上)動かさない時に、ドライバーをSleepさせ、直流電流を完全に止めるようにしています(下に掲げるArduinoプログラムご参照)。

ここのプロッターでの使い方の場合、X側は絶えず動かしっぱなしで、Loop内では20mS以上止まることはないのでSleepしません。Y側は動くとき以外はSleepさせています。

下はためしにそれをSleepしない(Sleepをコメントにした)状態です。それだけでドライバーは発熱し、すぐに過熱に至ります。

f:id:a-tomi:20190820215103j:plain

Y側の発熱が加わり、稼働僅か1分半でドライバーが過熱し55℃を超えた(写真下側)ので、このダメ押し実験をすぐにやめました、危ない危ない!やっぱり。

 

ところで、実は目的とする新メカニズムの実験装置を作るための部品をとっくに注文してあるのですが、通関にてこずっているようで到着がずいぶん遅れています。待遠しいですが、先に基板を作っておくことにしました。

高電流箇所をブレッドボードへのジャンプワイヤーに刺すこと自体が発熱の元です。回路図を再掲すると次のものです。StepperXとYへ行く配線、MV(モーター電源電圧), MG(モーター電源グランド)などがそれです。

f:id:a-tomi:20190820220221j:plain

回路図では基板が楽になるように、つまり配線が単純でジャンパーが少なくて済むように配置してあります。

これをほぼそのまま基板にデザインします。これは基板の上側から見たままです。1/10インチピッチ。単純なのでCADなしで短時間にできます。回路図にないパスコンなどは必要箇所につけます。

以下に勝手な片面基板作成法をご紹介します。かなりスピーディにできますので。

長年の習慣で0.1ミリが1ピクセルとなるよう描きます。これまでに部品の穴の位置の元図を準備してあるので、そこからコピペするだけという感じです。また、時間節約のためランドなどはいつも勝手に省略しています(それに適したはんだごてを使えば、半田付けに特に不便はありません)。

f:id:a-tomi:20190820220418j:plain

CNCルータで切削するため、上図をプログラムで変換して次のような銅箔面の像にします。そして文字を入れたりします。(ただし文字は次に作るためのもので、行間隔の改善をいれて、今度の日曜に作る予定の2枚目の基板用に既に変更しています。できた時点で次用の改善をしておくというのが毎度の習慣です。)

f:id:a-tomi:20190820220621j:plain

1枚目の作品は次のものです。100ミリx70ミリですが、削る時間は20分もかかりません。2φ以上の大穴は手で開けます。

f:id:a-tomi:20190820220907j:plain

ランドのない基板ですから、半田付けの際に、熱のいきわたり方を想像しながら行う必要があり、次のような鏝が適します。温度調節付き50Wで底力がありますので、広い領域の過熱が速い。また、もちろん最初の立ち上がりが数秒でOK。はんだづけの時間節約に大いに助かっている優れものです。

f:id:a-tomi:20190820221423j:plain

最初に行う配線はジャンパー。これが少なくなるようにパターンをデザインしますが、片側基板ではいたしかたなし。各箇所の電流に見合う線を使います。

f:id:a-tomi:20190820222126j:plain



あとは部品を差し込んで半田付けするだけなので短時間でできあがり。ソケットの向きに注意します。

f:id:a-tomi:20190820221812j:plain

 

この後は、電源部をチェックしてからマイコンから順にパーツを少しずつ刺しては点検確認をしながら完成します。そのようにすると完成までの時間が却って早いですので。

 

まずIDEでプログラム済みのマイコン(ATmega328P)を刺して 動きを確認し問題なし。次にまいくろSDカード読み書き装置を刺して読取動作を確認。次にステッパードライバーとステッパーを刺して動きを確認。PWM出力はオシロで確認(LEDと抵抗を直列にしたものを刺しても確認できる)。

次はステッパーX回路をテスト中の様子です。

youtu.be

 

結局何も手直しなく、全て問題なく動くことが確認できました。ボードが完成です。

f:id:a-tomi:20190821215931j:plain

中央左にある赤の4ピンヘッダーは今後使うかもしれない I2Cインターフェイス(未使用)、緑の3ピン端子は今後使うであろうメカのリミッター(ストッパー)信号入力端子です。4つのリミッターをOR結合して1つにし、信号が入れば全体を止めるというシンプルなアイデアです。

 

次に最新のプログラムをつけておきます。といってもレーザーのパワー制御用ポテンシオメータを入れただけです。

 


/* *************************************************
 *  Laser cutter type XY (V00 July 28, 2019)
 *  Version 00a Aug 10, 2019 stabilized
 *  Version 00b Aug 18, 2019 added duty-rate control
 *  (c)2019 Akira Tominaga, All rights reserved.
****************************************************/
#include   // SPI.h
#include    // SD.h

// pin assignment
// *** A4988 stepper driver
#define NsleepX 14  // !sleepX
#define StepX 9     // StepX
#define DirX 8      // DirectionX
#define NsleepY 7   // !sleepY
#define StepY 6     // StepY
#define DirY 4      // DirectionY
// ***for laser
#define Pwm 5       // PWM 980Hz for Laser
#define DutyCtl 2   // Duty rate control (A2)
// *** micro SD (SPI)
// D13=SCK
// D12=MISO
// D11=MOSI
# define ChipSel 10
File mySD;          // symbol for SD file
// *** LED and tact switch for operations
#define Led 2
#define Sw 3
// *** reserved
#define Stoppers 15  // OR for limitters (A1=D15)
// constants and values
#define tmStpX 700   // stepperX phase time in μS
#define tmStpY 700   // stepperY phase time in μS
#define enlargeX 2   // enlarge-multiplier for X
#define enlargeY 2   // enlarge-multiplier for Y
int dutyOn;          // duty ratio when laser On
#define dutyOff 0    // duty ratio when laser Off
#define dutyPos 1    // duty ratio when positioning
#define burnTime 14  // burning time (milliseconds)
int sizeX;           // picture size x
int sizeY;           // picture size y
int pX = 0;          // current position X
int pY = 0;          // current position Y
int newX;            // new position X
int newY;            // new position Y
byte Byte;           // byte work area
int Value;           // value work area
int k;               // common loop counter
int loopNum = 0;     // data number of file

void setup() { // Arduino Setup *******************
  analogWrite(Pwm, dutyOff);  // laser off
  pinMode(NsleepX, OUTPUT);
  digitalWrite(NsleepX, LOW); // sleep X
  pinMode(NsleepY, OUTPUT);
  digitalWrite(NsleepY, LOW); // sleep Y
  pinMode(DirX, OUTPUT);
  pinMode(DirY, OUTPUT);
  pinMode(StepX, OUTPUT);
  digitalWrite(StepX, LOW);
  pinMode(StepY, OUTPUT);
  digitalWrite(StepY, LOW);
  pinMode(Sw, INPUT_PULLUP);
  pinMode(Led, OUTPUT);
  digitalWrite(Led, LOW);

  Serial.begin(9600);
  delay(1000);

  // ** 1) 12V power-on process
  Serial.println("Pwr 12V on");
  while (digitalRead(Sw) == HIGH) {
    bLED(1, 50, 10);           // repeat LED on while waiting
  }
  delay(500);                  // avoid double detection of Sw

  // ** 2) adjust center position
  Serial.println("Adj Center");
  while (digitalRead(Sw) == HIGH) {
    analogWrite(Pwm, dutyPos); // blink weak laser-beam
    digitalWrite(Led, HIGH);   // LED on while waiting
    delay(30);
    analogWrite(Pwm, dutyOff); // blink laser-beam 
    digitalWrite(Led, LOW);    // blink LED, too
    delay(40);
  }
  analogWrite(Pwm, dutyOff); // laser off
  delay(500);                // avoid double detection of Sw

  // ** 3) prompt to wear protection glasses
  Serial.println("Protect eyes!");
  while (digitalRead(Sw) == HIGH) {
    bLED(1, 15, 30);         // blinkking of LED
  }
  delay(500);               // avoid double detection of Sw

  // check SD card exists
  if (!SD.begin(ChipSel)) {
    Serial.println("Chk SD");  // if error, show SdEr
    while (1) {
      bLED(20, 20, 30);        // blink LED forever
    }
  }
  // read PICT.txt header
  mySD = SD.open("PICT.txt");
  Rd4();                // read 4bytes to Value
  sizeX = Value - 1000; // get sizeX
  Rdskip(1);            //skip comma

  Rd4();                // read 4bytes to Value
  sizeY = Value - 1000; // get sizeY
  Rdskip(14);           // skip PC-center + CR+LF

  newX = -sizeX / 2;
  digitalWrite(NsleepX, HIGH); // wake-up X
  delay(2);             // delay for A4988 charge-pump
  movX();               // move to new origin pX=0
  newY = -sizeY / 2;
  movY();               // move to new origin pY=0
}

void loop() {   // Arduino Loop ******************
  /* ********************************************
      1.Read SD file and get new(X,Y) data
   *  ***************************************** */
  // read PICT.text
  Rd4();                // read 4bytes to Value
  if (Value >= 9999) {
    EndProc();
  }
  newX = Value - 1000;
  Rdskip(1);            // skip comma
  Rd4();                // read 4bytes to Value
  newY = Value - 1000;  // get newY
  Rdskip(14);           // skip PC-data 12 + CRLF 2

  loopNum++;
  Serial.print("#");
  Serial.print(loopNum);     // show data number

  /* ********************************************
      2.Set duty rate when laser-on
   *  ***************************************** */
  dutyOn=250.0*analogRead(DutyCtl)/1023;
  if (dutyOn<5){
    dutyOn=1;
  }

  /* ********************************************
      3.Drive steppers and irradiate laser beam
   *  ***************************************** */
  // move Y and X
  Serial.print (" ");
  Serial.print (pX);
  Serial.print (",");
  Serial.print (pY);
  Serial.print (" to ");
  Serial.print (newX);
  Serial.print (",");
  Serial.println (newY);
  movY();         // move Y first
  movX();         // move X next
  laserBeam();    // beam on for the burning time
  pX = newX;      // set new X value to current X
  pY = newY;      // set new Y value to current Y

}                 // last line of main loop ***

/***********************************
     User defined functions
* **********************************/
// *** Read SD 4 bytes into integer Value ***
void Rd4(void) {
  Value = 0;
  for (k = 0; k < 4; k++) {
    Byte = mySD.read();
    Byte = Byte & B00001111;
    Value = Value * 10 + Byte;
  }
}

// *** Read SD and skip given bytes ***
void Rdskip(int bn) {
  for (k = 0; k < bn; k++) {
    Byte = mySD.read();
  }
}

// *** move stepperX (no sleep actions) ***
void movX(void) {
  int Delta;
  if (newX == pX) {
    return;
  }
  if (newX > pX) {
    digitalWrite(DirX, HIGH);   // X fwd
    Delta = newX - pX;
  }
  if (newX < pX) {
    digitalWrite(DirX, LOW);   // X bkwd
    Delta = pX - newX;         // set absolute value
  }
  for (int l = 0; l < Delta * enlargeX; l++) {
    for (int m = 0; m < 8; m++) { // 1 cycle for MicroStep1
      digitalWrite(StepX, HIGH);
      delayMicroseconds(tmStpX);
      digitalWrite(StepX, LOW);
      delayMicroseconds(tmStpX);
    }
  }
  delay(2);
}

// *** move stepperY (with sleep actions) ***
void movY(void) {
  int Delta;
  if (newY == pY) {
    return;
  }
  if (newY > pY) {
    digitalWrite(DirY, HIGH);   // Y fwd
    Delta = newY - pY;
  }
  if (newY < pY) {
    digitalWrite(DirY, LOW);   // Y bkwd
    Delta = pY - newY;     // and change sign
  }
  digitalWrite(NsleepY, HIGH); // wake-up Y
  delay(2);                    // for A4988 charge-pump

  for (int l = 0; l < Delta * enlargeY; l++) {
    for  (int m = 0; m < 8; m++) { // 1 cycle MicroStep1
      digitalWrite(StepY, HIGH);
      delayMicroseconds(tmStpY);
      digitalWrite(StepY, LOW);
      delayMicroseconds(tmStpY);
    }
  }
  delay(2);                   // avoid mechanical inertia
  digitalWrite(NsleepY, LOW); // sleep Y
}

// *** Laser beam-on for burnTime ***
void laserBeam(void) {
  analogWrite(Pwm, dutyOn);
  delay(burnTime);
  analogWrite(Pwm, dutyOff);
}

// *** End of File process ***
void EndProc(void) {
  newX = sizeX / 2;
  newY = sizeY / 2;
  movY();
  movX();
  delay(2);        // avoid mechanical inertia
  digitalWrite(NsleepX, LOW);  // sleep X
  Serial.println("Power-off 12V-DC");
  mySD.close();
  while (1) {}
}

// *** blink LED ***
void bLED(int nTimes, int onmS, int offmS)
{
  for (int m = 0; m < nTimes; m++) {
    digitalWrite(Led, HIGH);
    delay(onmS);
    digitalWrite(Led, LOW);
    delay(offmS);
  }
}

// end of program

(以下2019/8/29更新)目的とする新しいメカニズムでは上のプログラムに少し変更がはいりますが、使用する刻印データ仕様は同じです。

新メカニズムを作るためのパーツが、ようやく通関して到着。国際EMSなのに「配送中に壊れたので直した」と?開けてみたら箱が壊れただけで、しっかり補修されていた^^

f:id:a-tomi:20190829213143j:plain

バックラッシュの少ないウォームギアでステッパーを高比率減速するパーツですが、ネットで世界中さがしても普通のモーター付きはあれどステッパー付きはほぼないのに驚き。面倒でも作るわけです。今回入手したのは他の目的用のごつい鉄製のギアで重くて頑丈(何と1個1200g)、頑丈さは気にいったが、重さで輸送中に箱が壊れるわけだ。こういうのしかないということは、きっと誰も考えてないものだから・・(^^) ふふ。。。

そこまでは良かったのですが、入力用8ミリ径シャフトは特殊形状なので付属すると勝手に想定していたら付属してない。入手も難しい。しかたがないので、時間があるときに金属を削って作ることに。大目的である新型エングレーバー(今考えついているのは2種類)には利点が沢山あるはずなので是非完成したい。すこしずつやるのでたいへん気の長い話ではありますが。

そういうわけでこの連載の続きを書くのが少し先になりそうですがご容赦を。

その代わり、それまでの間、別の勝手な新案電子工作のどれかについて連載記事を入れておきたいと思います。PICのっくりする使い方にしようかと。。

 

では今回はこのへんで。

下の方にレーザー使用の注意を入れます。

前の記事:

a-tomi.hatenablog.com

a-tomi.hatenablog.com

a-tomi.hatenablog.com


以下、重要な注意です。レーザーは失明や傷害、火災等の危険を伴い、周囲にも危険がおよびます。関連法規と取扱い基準(http://kikakurui.com/c6/C6802-2011-01.html)などに従って、正しく管理してください。この記事をみて自作される場合も全て自己責任でお願いします。

 

©2019 Akira Tominaga, All rights reserved.