ทำ AutoFocuser EAF สำหรับการถ่ายภาพดาราศาสตร์ด้วย NiNa ง่ายสุดๆในจักรวาล Part 2

กระทู้สนทนา
ใครยังไม่อ่าน Part 1 ไปอ่านก่อนนะครับ เพี้ยนหลงรัก
https://ppantip.com/topic/41740858 
เพี้ยนปักหมุด

Part 2 Bi Polar Stepper Motor
ส่วนนี้จะเปลี่ยนจาก Motor Uni Polar เป็น Bi Polar แทน โดยมีความยุ่งยากมานิดหน่อย จะไม่อธิบายละเอียดมากเพราะถือว่าจะทำตรงนี้ได้ต้องมีพื้นมามั่งนิดหน่อย ไม่งั้นกลับไปทำแบบ Part 1 ข้อดีคือ
1 Motor หลากหลายแรงบิดสูง ทำให้ขับตรงแกน Focuser ได้เลย ทำให้ประหยัด Pulley และ Belt ไปหลายร้อย
2 ปรับการขับ แบบ microstep ได้
3 ทนกว่า
4 Backlash น้อยมากๆ
 ข้อเสียคือ ยุ่งยาก กินไฟ แพงขึ้นเยอะ หากไม่มีเฟืองทดจะไม่ Lock ตัวเองทำให้ไม่เหมาะกับ Focuser บางประเภท

อุปกรณ์
1 Micro Controller Arduino Nano 3.0 328P (Atmel Atmega328P) ระวัง ต้อง 328p (ไม่ใช่ 168p ซึ่งเมมน้อยกว่าราคาเท่ากัน)  ประมาณ 100 บาท มีหัว 3 แบบ Mini, Micro, Type C เลือกเอาได้


2 สาย Dupon Jumper Wire 10cm Female to Female 1 แผง 20 บาท


3 Capacitor 10uF  มากกว่า 16V ตัวละบาทสองบาท



4 Capacitor 100uF  มากกว่า 16V ตัวละบาทสองบาท
 
5 Stepper Motor  BiPolar 2 phases 150-200 บาท จะเอาแบบมีเฟืองทดหรือไม่มีก็ได้ ที่นี้จะใช้Nema17 17HS4023 แบบแบนๆเล็กๆ อย่าเอาตัวใหญ่มันหนัก ประมาณ 120-180 บาท

6 Motor Driver TMC2208 ตัวละ 80-100 บาท


7 Flexible Couple (ถ้าจะใช้ Timing Pulley ก็ทำตาม Part 1) ใช้ต่อตรง อย่าใช้แบบ Rigid  ก่อนซื้อต้องวัดแกน Motor กับแกน หมุน Focuser ก่อนว่ามีขนาดเท่าไร ส่วนใหญ่ Nema Motor จะ 5mm และ Focuser กล้องดูดาวจะ 6mm ก็ซื้อแบบ 5x6 แต่เอาแน่ๆวัดเอาดีกว่า 



8 หลอด LED และ R1K เป็น Option มีก็ได้ไม่มีก็ได้
9 Jack DC ถ้าเชื่อมได้ 

ถ้าเชื่อมไม่ได้ก็ใช้แบบนี้

ส่วนกล่องใส่ Bracket ลองออกแบบเอาเองนะครับ เลียนแบบ ZWO ยัดใส่กล่องเดียวก็ได้

ลง Firmware
นำ Arduino Nano มาลง Firmware เหมือน Part 1 แต่ใช้ Code นี้แทน 

เพี้ยนมองบน
Code ผมไม่ได้เขียนเองนะ แต่เอามาแก้บางส่วน ผมไม่แน่ใจว่ามาจากไหนผมเอามาจากพี่อีกท่านมาโมต่อ น่าจะ Link ใน Code ขออภัยผู้พัฒนาด้วยครับที่ไม่ได้ลง Link Credit ไว้ให้
เพี้ยนสายแล้ว

//-------------------------------------------------------------------------------
// Moonlite-compatible stepper controller
//
// Uses AccelStepper (http://www.airspayce.com/mikem/arduino/AccelStepper/)
//
// Inspired by (http://orlygoingthirty.blogspot.co.nz/2014/04/arduino-based-motor-focuser-controller.html)
// orly.andico@gmail.com, 13 April 2014
//
// Modified for indilib, easydriver by Cees Lensink
// Added sleep function by Daniel Franzén
 
// Driver is TMC2208
#include <AccelStepper.h>
//int EnPin = 19;
 
int powerPin = 12;//En
int MS1 = 11;
int MS2 = 10;
int MS3 = 9;
 
int stepperPin = 6;
int dirPin = 5;
boolean useSleep = true; // true= use sleep pin, false = use enable pin
int ledPin = 2;
//int BuzzerPin = 16;
// maximum speed is 160pps which should be OK for most
// tin can steppers
#define MAXSPEED 250
#define SPEEDMULT 3
const int activeTimePeriod = 3000;//default 30000
 
AccelStepper stepper(1, stepperPin, dirPin);
 
#define MAXCOMMAND 8
 
char inChar;
char cmd[MAXCOMMAND];
char param[MAXCOMMAND];
char line[MAXCOMMAND];
long pos;
int eoc = 0;
int idx = 0;
boolean isRunning = false;
boolean powerIsOn = false;
long timerStartTime = 0;
 
//Define the period to wait before turning power off (in milliseconds)
 
 
char tempString[10];
 
 
void setup()
{
  Serial.begin(9600);
  pinMode(powerPin, OUTPUT);
  pinMode(MS1, OUTPUT);
  pinMode(MS2, OUTPUT);
  pinMode(MS3, OUTPUT);
 
  digitalWrite(MS1, HIGH);
  digitalWrite(MS2, HIGH);
  digitalWrite(MS3, LOW);
  // pinMode(EnPin,OUTPUT);
  // digitalWrite(EnPin,LOW);
  //pinMode(BuzzerPin,OUTPUT);
  pinMode(ledPin, OUTPUT);
  // we ignore the Moonlite speed setting because Accelstepper implements
  // ramping, making variable speeds un-necessary
  stepper.setSpeed(MAXSPEED);
  stepper.setMaxSpeed(MAXSPEED);
  stepper.setAcceleration(50);
  turnOff();
  memset(line, 0, MAXCOMMAND);
}
 
 
//
 
//
 
 
void loop() {
  if (isRunning) { // only have to do this is stepper is on
    stepper.run();
    if (stepper.distanceToGo() == 0) {
      //start timer to decide when to power off the board.
      timerStartTime = millis();
      isRunning = false;
    }
  }
  else if (powerIsOn)
  {
    //Turn power off if active time period has passed.
    if (millis() - timerStartTime > activeTimePeriod)
    {
      turnOff();
    }
  }
 
  // read the command until the terminating # character
  while (Serial.available() && !eoc) {
    inChar = Serial.read();
    if (inChar != '#' && inChar != ':') {
      line[idx++] = inChar;
      if (idx >= MAXCOMMAND) {
        idx = MAXCOMMAND - 1;
      }
    }
    else {
      if (inChar == '#') {
        eoc = 1;
      }
    }
  } // end while Serial.available()
  // we may not have a complete command yet but there is no character coming in for now and might as well loop in case stepper needs updating
  // eoc will flag if a full command is there to act upon
 
  // process the command we got
  if (eoc) {
    memset(cmd, 0, MAXCOMMAND);
    memset(param, 0, MAXCOMMAND);
 
    int len = strlen(line);
    if (len >= 2) {
      strncpy(cmd, line, 2);
    }
 
    if (len > 2) {
      strncpy(param, line + 2, len - 2);
    }
 
    memset(line, 0, MAXCOMMAND);
    eoc = 0;
    idx = 0;
 
    //now execute the command
 
    //Immediately stop any focus motor movement. returns nothing
    //code from Quickstop example. This is blocking
    if (!strcasecmp(cmd, "FQ")) {
      if (!isRunning)
      {
        turnOn();
      }
      stepper.stop(); // Stop as fast as possible: sets new target
      stepper.runToPosition();
      // Now stopped after quickstop
    }
 
    //Go to the new position as set by the ":SNYYYY#" command. returns nothing    // initiate a move
    //turn stepper on and flag it is running
    // is this the only command that should actually make the stepper run ?
    if (!strcasecmp(cmd, "FG")) {
      if (!isRunning)
      {
        turnOn();
      }
    }
 
    //Returns the temperature coefficient where XX is a two-digit signed (2’s complement) hex number.
    //hardcoded
    if (!strcasecmp(cmd, "GC")) {
      Serial.print("02#");
    }
 
    //Returns the current stepping delay where XX is a two-digit unsigned hex number. See the :SD# command for a list of possible return values.
    //hardcoded for now
    // might turn this into AccelStepper acceleration at some point
    if (!strcasecmp(cmd, "GD")) {
      Serial.print("02#");
    }
 
    //Returns "FF#" if the focus motor is half-stepped otherwise return "00#"
    //hardcoded
    if (!strcasecmp(cmd, "GH")) {
      Serial.print("00#");
    }
 
    //Returns "00#" if the focus motor is not moving, otherwise return "01#",
    //AccelStepper returns Positive as clockwise
    if (!strcasecmp(cmd, "GI")) {
      if (stepper.distanceToGo() == 0) {
        Serial.print("00#");
      }
      else {
        Serial.print("01#");
      }
    }
 
    //Returns the new position previously set by a ":SNYYYY" command where YYYY is a four-digit unsigned hex number.
    if (!strcasecmp(cmd, "GN")) {
      pos = stepper.targetPosition();
      sprintf(tempString, "X", pos);
      Serial.print(tempString);
      Serial.print("#");
    }
//Returns the current position where YYYY is a four-digit unsigned hex number.
    if (!strcasecmp(cmd, "GP")) {
      pos = stepper.currentPosition();
      sprintf(tempString, "X", pos);
      Serial.print(tempString);
      Serial.print("#");
    }
 
    //Returns the current temperature where YYYY is a four-digit signed (2’s complement) hex number.
    if (!strcasecmp(cmd, "GT")) {
      Serial.print("0020#");
    }
 
    //Get the version of the firmware as a two-digit decimal number where the first digit is the major version number, and the second digit is the minor version number.
    //hardcoded
    if (!strcasecmp(cmd, "GV")) {
      Serial.print("10#");
    }
 
    //Set the new temperature coefficient where XX is a two-digit, signed (2’s complement) hex number.
    if (!strcasecmp(cmd, "SC")) {
      //do nothing yet
    }
 
    //Set the new stepping delay where XX is a two-digit,unsigned hex number.
    if (!strcasecmp(cmd, "SD")) {
      //do nothing yet
    }
 
    //Set full-step mode.
    if (!strcasecmp(cmd, "SF")) {
      //do nothing yet
    }
 
    //Set half-step mode.
    if (!strcasecmp(cmd, "SH")) {
      //do nothing yet
    }
 
    //Set the new position where YYYY is a four-digit
    if (!strcasecmp(cmd, "SN")) {
      pos = hexstr2long(param);
      // stepper.enableOutputs(); // turn the motor on here ??
      if (!isRunning)
      {
        turnOn();
      }
      stepper.moveTo(pos);
    }
 
    //Set the current position where YYYY is a four-digit unsigned hex number.
    if (!strcasecmp(cmd, "SP")) {
      pos = hexstr2long(param);
      stepper.setCurrentPosition(pos);
    }
 
  }// end if(eoc)
 
 
} // end loop
 
long hexstr2long(char *line) {
  long ret = 0;
 
  ret = strtol(line, NULL, 16);
  return (ret);
}
 
void turnOn() {
  if (useSleep) {
    digitalWrite(powerPin, LOW);
  } else {
    digitalWrite(powerPin, HIGH);
  }
  digitalWrite(ledPin, HIGH);
  // digitalWrite(BuzzerPin, HIGH);
  delay(100);
  // digitalWrite(BuzzerPin, LOW);
  isRunning = true;
  powerIsOn = true;
}
void turnOff() {
  if (useSleep) {
    digitalWrite(powerPin, HIGH);
  } else {
    digitalWrite(powerPin, LOW);
  }
  digitalWrite(ledPin, LOW);
  //  digitalWrite(BuzzerPin, HIGH);
  delay(100);
  //digitalWrite(BuzzerPin, LOW);
  isRunning = false;
  powerIsOn = false;
}

เพี้ยนเย้
การต่อวงจร
การต่อให้ต่อให้ใช้สาย Dupont แบบนี้เลย ยกเว้นหาก Motor กินไฟมากให้ใช้สายไฟใหญ่ขึ้น
ไปดูใ
แก้ไขข้อความเมื่อ
แสดงความคิดเห็น
โปรดศึกษาและยอมรับนโยบายข้อมูลส่วนบุคคลก่อนเริ่มใช้งาน อ่านเพิ่มเติมได้ที่นี่