制造商零件编号 K001-V26
ESP32 BASIC CORE IOT V2.6 DEVKIT
M5Stack Technology Co., Ltd.
License: General Public License Arduino ESP32 M5Stack
* Thanks for the source code and project information provided by @vany5921
I was able to control the focus adjustment of the telescope MAK127SP by the stepper motor which is connected to M5Stack. The motor driver is LV8548MC. The stepper motor is attached to the telescope with a 3D printed mount.
Overview:
The focusing knob of telescope MAK127SP is rotated by a stepper motor that is controlled by M5Stack. The motor driver is LV8548MC. The stepper motor mount is made by 3D printing.
Feature:
Focusing on a telescope can be very frustrating. Touching the knob to focus will cause the telescope to shake. Therefore, I created a mechanism that allows you to adjust the focus as much as possible without touching the telescope. Vibration free adjustment is very nice for focusing.
The resolution of stepper control is a little bit rough, I felt. I may need to replace a drive IC or motor itself. Also, when the direction is changed, there is a brief delay.
Finding the peak of focus is an additional feature. If it is difficult to find the peak of focus, I usually mark the boundaries where the focus points are out of focus. Then define the center of the mark points on the two knobs as the peak of focus. This program helps it.
Anyway, this system improves the experience of controlling my telescope. I plan on improving this system further.
MAK127SP stepper focuser with M5Stack. Project for PlatformIO
3D Printer Data:
https://www.tinkercad.com/things/64dMHyw7Xuu
https://www.tinkercad.com/things/92R7x5C4mbl
Code
mak127focuserC/C++
/*
Description: This exmpale can display the encoder gear reading of the PLUS Module and the state of the keys.
*/
#include <Arduino.h>
#include <Ticker.h>
#include <M5Stack.h>
const int IN1 = 16;
const int IN2 = 17;
const int IN3 = 21;
const int IN4 = 22;
const int ECA = 35;
const int ECB = 36;
const int DISP_W = 320;
const int DISP_H = 240;
const int CIR_R = 195 / 2;
const int V_STEP = 32;
const int H_OFST = 115;
const int H_OFS = 70;
const int V_OFS = 83;
const int V_BASE = 80;
uint8_t full_step_table [] = {
0b0101, // 0
0b1001, // 1
0b1010, // 2
0b0110, // 3
};
uint8_t half_step_table [] = {
0b0101, // 0
0b0001, // 1
0b1001, // 2
0b1000, // 3
0b1010, // 4
0b0010, // 5
0b0110, // 6
0b0100, // 7
};
enum {DIR_NONE, DIR_FW, DIR_BW};
enum {MODE_NULL, MODE_FULL, MODE_HALF};
enum {LOOP_FULL = 4, LOOP_HALF = 8};
Ticker seq_tick;
const float toggle_period_sec = 0.3;
volatile bool step_run_flg = false;
volatile int step_run_cnt = 0;
int step_run_dir = DIR_FW;
volatile int tgl_c = 1;
uint8_t *step_table;
int mark1 = 0;
int mark2 = 0;
int cur_pos = 0;
int last_pos = 0;
int step_round = 48;
float step_angle = 360.0 / step_round;
int color_fg = TFT_RED;
int color_bg = TFT_BLACK;
uint8_t step_phase = 0;
uint8_t l_step_phase = 0;
uint8_t step_loop = LOOP_FULL;
uint8_t step_dir = DIR_FW;
uint8_t last_step_dir = DIR_FW;
uint8_t cur_mode = MODE_FULL;
uint8_t ec, last_ec;
void setNextPhase(uint8_t dir)
{
step_dir = dir;
l_step_phase = step_phase;
last_pos = cur_pos;
if (dir == DIR_FW) {
step_phase--;
cur_pos--;
} else {
step_phase++;
cur_pos++;
}
if (cur_pos < 0) {
cur_pos = step_round - 1;
}
step_phase = step_phase % step_loop;
cur_pos = cur_pos % step_round;
}
void setStepIN()
{
int val;
if (cur_mode == MODE_FULL) {
val = full_step_table[step_phase];
} else {
val = half_step_table[step_phase];
}
int in1 = ((val & (0x10 >> 1)) == 0) ? LOW : HIGH;
int in2 = ((val & (0x10 >> 2)) == 0) ? LOW : HIGH;
int in3 = ((val & (0x10 >> 3)) == 0) ? LOW : HIGH;
int in4 = ((val & (0x10 >> 4)) == 0) ? LOW : HIGH;
Serial.printf("%d: %d %d %d %d\n", step_phase, in1, in2, in3, in4);
digitalWrite(IN1, in1);
digitalWrite(IN2, in2);
digitalWrite(IN3, in3);
digitalWrite(IN4, in4);
}
void drawVal(int ofs, float val)
{
M5.Lcd.fillRect(DISP_W - H_OFS - 5, V_OFS + ofs, 70, 24, color_bg);
M5.Lcd.setTextSize(2);
M5.Lcd.setTextColor(color_fg);
M5.Lcd.setCursor(DISP_W - H_OFS - 5, V_OFS + ofs);
M5.Lcd.printf("%.02f", val);
}
void setStepMode(uint8_t mode)
{
if (cur_mode != mode) {
if (mode == MODE_FULL) {
step_table = full_step_table;
step_round = 48;
step_loop = LOOP_FULL;
step_phase /= 2;
step_angle = 360.0 / step_round;
cur_pos /= 2;
Serial.println("FULL step");
} else {
step_table = half_step_table;
step_round = 48 * 2;
step_loop = LOOP_HALF;
step_phase *= 2;
step_angle = 360.0 / step_round;
cur_pos *= 2;
Serial.println("HALF step");
}
cur_mode = mode;
}
drawVal(0, step_angle);
setStepIN();
}
uint8_t readEC()
{
uint8_t a, b;
a = digitalRead(ECA);
b = digitalRead(ECB);
delay(1);
a ^= digitalRead(ECA);
b ^= digitalRead(ECB);
delay(1);
a ^= digitalRead(ECA);
b ^= digitalRead(ECB);
last_ec = ec;
ec = a | b << 1;
if (last_ec == 0b10 && ec == 0b11) {
Serial.println("EC->FW");
return DIR_FW;
} else if (last_ec == 0b11 && ec == 0b10) {
Serial.println("EC->BW");
return DIR_BW;
}
return DIR_NONE;
}
void drawPos(int pos, int color, int fill)
{
int center_x = CIR_R;
int center_y = CIR_R - 2;
float angle = pos * step_angle;
float sx0 = cos((angle - 90) * 0.0174532925);
float sy0 = sin((angle - 90) * 0.0174532925);
float sx1 = cos((angle + 175 - 90) * 0.0174532925);
float sy1 = sin((angle + 175 - 90) * 0.0174532925);
float sx2 = cos((angle + 185 - 90) * 0.0174532925);
float sy2 = sin((angle + 185 - 90) * 0.0174532925);
int x0 = sx0 * (CIR_R - 25) + center_x;
int y0 = sy0 * (CIR_R - 25) + center_y;
int x1 = sx1 * (CIR_R - 25) + center_x;
int y1 = sy1 * (CIR_R - 25) + center_y;
int x2 = sx2 * (CIR_R - 25) + center_x;
int y2 = sy2 * (CIR_R - 25) + center_y;
if (fill) {
M5.Lcd.fillTriangle(x0, y0, x1, y1, x2, y2, color);
} else {
M5.Lcd.drawTriangle(x0, y0, x1, y1, x2, y2, color);
}
drawVal(V_STEP, step_angle * cur_pos);
// Serial.printf("LINE %d, %d\n", pos, color);
}
void drawCircle(int clr)
{
int center_x = CIR_R;
int center_y = CIR_R - 2;
if (clr == 0) {
M5.Lcd.fillCircle(center_x, center_y, CIR_R - 1, color_fg);
}
M5.Lcd.fillCircle(center_x, center_y, CIR_R - 9, color_bg);
for (int i = 0; i < 360; i += 30) {
float sx = cos((i - 90) * 0.0174532925);
float sy = sin((i - 90) * 0.0174532925);
int x0 = sx * (CIR_R - 6) + center_x;
int y0 = sy * (CIR_R - 6) + center_y;
int x1 = sx * (CIR_R - 20) + center_x;
int y1 = sy * (CIR_R - 20) + center_y;
M5.Lcd.drawLine(x0, y0, x1, y1, color_fg);
}
for (int i = 0; i < step_round; i++) {
float deg = i * step_angle;
float sx = cos((deg - 90) * 0.0174532925);
float sy = sin((deg - 90) * 0.0174532925);
int x0 = sx * (CIR_R - 18) + center_x;
int y0 = sy * (CIR_R - 18) + center_y;
// Draw minute markers
M5.Lcd.drawPixel(x0, y0, color_fg);
}
float deg = mark1 * step_angle;
float sx = cos((deg - 90) * 0.0174532925);
float sy = sin((deg - 90) * 0.0174532925);
int x0 = sx * (CIR_R - 13) + center_x;
int y0 = sy * (CIR_R - 13) + center_y;
M5.Lcd.fillCircle(x0, y0, 3, color_fg);
drawPos(cur_pos, color_fg, 1);
}
void countDownSeq()
{
if (step_run_cnt <= 0) {
return;
}
step_run_cnt--;
step_run_flg = true;
if (step_run_cnt == 0) {
seq_tick.detach();
}
}
int blinkCenter(int flg)
{
int next_flg;
M5.Lcd.setTextSize(2);
M5.Lcd.setCursor(80 * 1 + 42, DISP_H - 30);
if (flg == 0) {
M5.Lcd.fillRect(80 * 1 + 38, DISP_H - 33, 77, 20, color_bg);
M5.Lcd.setTextColor(color_fg);
next_flg = 1;
} else {
M5.Lcd.fillRect(80 * 1 + 38, DISP_H - 33, 77, 20, color_fg);
M5.Lcd.setTextColor(color_bg);
next_flg = 0;
}
M5.Lcd.print("Center");
return next_flg;
}
void setup() {
M5.begin();
// M5.Power.begin();
dacWrite(25, 0); // STOP SP
digitalWrite(IN1, 0);
digitalWrite(IN2, 0);
digitalWrite(IN3, 0);
digitalWrite(IN4, 0);
pinMode(IN1, OUTPUT);
pinMode(IN2, OUTPUT);
pinMode(IN3, OUTPUT);
pinMode(IN4, OUTPUT);
pinMode(ECA, INPUT);
pinMode(ECB, INPUT);
readEC();
M5.Lcd.setTextColor(color_fg);
M5.Lcd.setTextSize(1);
M5.Lcd.setCursor(DISP_W - H_OFST, V_BASE);
M5.Lcd.print("Step");
M5.Lcd.setCursor(DISP_W - H_OFST, V_BASE + 12);
M5.Lcd.print("Angle");
setStepMode(MODE_FULL);
drawCircle(0);
M5.Lcd.fillRect(DISP_W - H_OFST - 8, 2, 124, 35, color_fg);
M5.Lcd.setTextColor(color_bg);
M5.Lcd.setTextSize(2);
M5.Lcd.setCursor(DISP_W - H_OFST - 5, 5);
M5.Lcd.print("Focus");
M5.Lcd.setCursor(DISP_W - H_OFST - 5, 20);
M5.Lcd.print("controller");
M5.Lcd.setCursor(DISP_W - H_OFST - 4, 5);
M5.Lcd.print("Focus");
M5.Lcd.setCursor(DISP_W - H_OFST - 4, 20);
M5.Lcd.print("controller");
M5.Lcd.setTextColor(color_fg);
M5.Lcd.setTextSize(1);
M5.Lcd.setCursor(DISP_W - H_OFST, V_BASE + V_STEP);
M5.Lcd.print("Cur");
M5.Lcd.setCursor(DISP_W - H_OFST, V_BASE + V_STEP + 12);
M5.Lcd.print("Pos");
M5.Lcd.setTextSize(1);
M5.Lcd.setCursor(DISP_W - H_OFST, V_BASE + V_STEP * 2 + 6);
M5.Lcd.print("Mark");
drawVal(V_STEP * 2, step_angle * mark1);
M5.Lcd.setTextSize(2);
M5.Lcd.setTextColor(color_fg);
M5.Lcd.setCursor(80 * 0 + 42, DISP_H - 30);
M5.Lcd.print("Mark");
M5.Lcd.setCursor(80 * 2 + 67, DISP_H - 30);
M5.Lcd.print("Step");
// M5.Lcd.setCursor(80 * 1 + 42, DISP_H - 30);
// M5.Lcd.print("Center");
blinkCenter(0);
}
void loop() {
if (step_run_cnt > 0 || step_run_flg) {
if (step_run_flg) {
setNextPhase(step_run_dir);
drawPos(last_pos, color_bg, 1);
drawPos(cur_pos, color_fg, 1);
setStepIN();
tgl_c = blinkCenter(tgl_c);
step_run_flg = false;
}
if (step_run_cnt == 0) {
blinkCenter(0);
}
delay(10);
} else {
M5.update();
if (M5.BtnA.wasPressed()) {
Serial.println("Mark");
mark1 = cur_pos;
drawVal(V_STEP * 2, step_angle * mark1);
drawCircle(1);
} else if (M5.BtnB.wasPressed()) {
int pos_diff;
if (cur_pos >= mark1) {
pos_diff = cur_pos - mark1;
step_run_dir = DIR_FW;
} else {
pos_diff = mark1 - cur_pos;
step_run_dir = DIR_BW;
}
if (pos_diff > step_round / 2) {
pos_diff = step_round - pos_diff;
step_run_dir = (step_run_dir == DIR_FW) ? DIR_BW : DIR_FW;
}
step_run_cnt = pos_diff / 2;
Serial.printf("Center: diff %d %d", step_run_cnt, step_run_dir);
tgl_c = 1;
seq_tick.attach(toggle_period_sec, countDownSeq);
} else if (M5.BtnC.wasPressed()) {
Serial.print('C');
int next_mode = (cur_mode == MODE_FULL) ? MODE_HALF : MODE_FULL;
setStepMode(next_mode);
drawCircle(1);
}
uint8_t ec_dir = readEC();
if (ec_dir != DIR_NONE) {
setNextPhase(ec_dir);
drawPos(last_pos, color_bg, 1);
drawPos(cur_pos, color_fg, 1);
setStepIN();
}
}
}