ใครยังไม่อ่าน 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 กินไฟมากให้ใช้สายไฟใหญ่ขึ้น
ไปดูใ
ทำ AutoFocuser EAF สำหรับการถ่ายภาพดาราศาสตร์ด้วย NiNa ง่ายสุดๆในจักรวาล Part 2
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 กินไฟมากให้ใช้สายไฟใหญ่ขึ้น
ไปดูใ