tianyuan08 发表于 2020-4-2 23:53

再做一个简单的电调焦

本帖最后由 tianyuan08 于 2020-4-2 23:57 编辑

前一阵心热,给晶华的JE100A赤道仪自制了一个电跟,http://bbs.imufu.cn/forum.php?mo ... 2119&fromuid=340351 (出处: 牧夫天文论坛(中国最早的天文论坛,致力于天文和望远镜的科普交流平台))]http://bbs.imufu.cn/forum.php?mod=viewthread&tid=792119&fromuid=340351,乘着热度还没减,又搞了一个电调焦出来,避免调焦的抖动,和大家分享一下,技术含量比较低,大神勿笑{:3_214:}

主要的材料包括:(1) TITAN 42步进电机一个,保持力矩0.12NM;(2) 2GT同步轮,16、48齿,齿比1:3;(3)2GT同步带,154周长,支持中心距44.5左右;(4)铝合金孔6法兰联轴器一个;(5)铝合金 5mm-5mm 刚性联轴器一个;(6)5mm、6mm不锈钢轴各一个;(7)热弯的亚克力步进电机支架一个;

另外由于赤经已经有一个电机了,现在要控制两个电机,所以将上次步进电机驱动器TB6600换掉了,改成了CNC SHIELD V3数控板+2个A4988驱动器,又添了一个4*4的单片机矩阵键盘用来做控制器,程序还是烧到arduino里,赤经轴电机仍然通过TIMER1发送脉冲,调教座电机则通过键盘长按控制。

下面这张图就是控制逻辑了,红色大板是cnc shield v3,直接插在了arduino uno r3上面,装了两块a4988(带散热片的那个),能够独立控制两个步进电机,把矩阵键盘接在cnc shield v3上,其引脚实际是接在arduino上的。


安装48齿同步轮到调焦手轮上用了一个简单粗暴的办法,直接把法兰联轴器用AB胶粘在手轮上,再插入轴,装上同步轮就好了~~~


为了减轻重量,用亚克力板做了一个42步进电机支架,孔位则是按照调焦座下方顶住调焦杆的4颗螺丝位置开的,亚克力板厚度5mm~


安装的时候发现两轴距离之前算错了...同步带买长了,重新计算后,给亚克力支架上用AB胶粘了两个M6螺丝,这下就刚好了,选择TITAN 42步进电机,主要是因为轻啊,而且保持力矩0.12NM也还行,再加个1:3的齿比,绝对没问题!


实际效果:通过条线设置两个a4988都是16细分,减少电机震动。在矩阵键盘上设置了7个按键,S1控制两个电机使能开关,S2是赤经电机开关,S3是调焦电机开关,S4和S5长按后,将输出1000HZ频率的脉冲,使得调焦电机可以快速旋转,S7和S8按住,则是以100HZ的频率发送脉冲,使调焦电机微速旋转。控制赤经的脉冲通过arduino的TIMER1中断给出的,而控制电调的直接用了delay和delayMicroseconds,实际是TIMER0,由于TIMER1的中断优先级高于TIMER0,所以赤经电机是不会受到电调电机的影响。测试了一下,对焦的时候全程无抖动,很爽{:3_219:}!使用步进电机还有一个好处,可以在调焦筒伸出的时候对脉冲数计数,收回的时候,对计数值递减,当计数值为0的时候,就不再发送脉冲给电机,避免调焦筒撞到调焦座,有可能损坏电机、齿轮、皮带~~不过这部分程序还没做,有空改一改.

附上自己写的用arduino+cnc shield v3+a4988+矩阵键盘搞的控制程序,需要用到arduino的time_one和keypad附加库:

#include <Key.h>
#include <Keypad.h>
#include <TimerOne.h>

//define ena for all motors
#define ENA_PIN 8

//define motor pins
#define XDIR_PIN 5
#define YDIR_PIN 6
#define XSTEP_PIN 2
#define YSTEP_PIN 3

//define keypad rows and cols
#define ROWS 3
#define COLS 3

//define a keymap
unsigned char keys =
{
{'1', '2', '3'},
{'4', '5', '6'},
{'7', '8', '9'}
};

//row->pin, col->pin
byte rowPins = {A3, 13, 12};
byte colPins = {A2, A1, A0};

//register keymap and pins
Keypad keypad = Keypad(makeKeymap(keys), rowPins, colPins, ROWS, COLS);

//XPUL_STATE保存X电机驱动电平状态
volatile byte XPUL_STATE = LOW;

//X电机,Y电机开关
volatile byte XMOTOR_TOGGLE = LOW;
volatile byte YMOTOR_TOGGLE = LOW;

//电机使能开关
volatile byte ENA_TOGGLE = HIGH;

//Y电机状态,指示哪个键被长按
volatile unsigned char YMOTOR_STATE = 0;

void setup() {
//set pin mod
pinMode(ENA_PIN, OUTPUT);
pinMode(XDIR_PIN, OUTPUT);
pinMode(XSTEP_PIN, OUTPUT);
pinMode(YDIR_PIN, OUTPUT);
pinMode(YSTEP_PIN, OUTPUT);
//set pin value
digitalWrite(ENA_PIN, ENA_TOGGLE);
digitalWrite(XDIR_PIN, HIGH);
//设置timer1的频率为32HZ,则每31.25ms触发一次
Timer1.initialize(31250);
Timer1.attachInterrupt(timer1_ISR);
//set keypad listener
keypad.addEventListener(keypadEvent);
//set hold dealy
keypad.setHoldTime(500);
//set serail
Serial.begin(9600);
}

//timer1的触发频率为32HZ,也就是1秒触发32次高低电平转换,则1秒为16HZ的方波信号,600秒产生9600个周期
void timer1_ISR()
{
if (XMOTOR_TOGGLE == HIGH)
{
    XPUL_STATE = !XPUL_STATE;
    digitalWrite(XSTEP_PIN, XPUL_STATE);
}
}

void loop() {
//listern keypad
keypad.getKey();
//drive Y-MOTOR
switch(YMOTOR_STATE)
{
    //长按按键4、5,产生1000HZ的方波
    case '4':
    case '5':
      digitalWrite(YSTEP_PIN, HIGH);
      delayMicroseconds(500);
      digitalWrite(YSTEP_PIN, LOW);
      delayMicroseconds(500);
      break;
    //长按按键7、8,产生100HZ的方波
    case '7':
    case '8':
       digitalWrite(YSTEP_PIN, HIGH);
       delay(5);
       digitalWrite(YSTEP_PIN, LOW);
       delay(5);
      break;
}
}

void keypadEvent(KeypadEvent key)
{
switch (keypad.getState())
{
    //有按键发生时
    case PRESSED:
      switch (key)
      {
      //按键1控制电机使能
      case '1':
          ENA_TOGGLE = !ENA_TOGGLE;
          if (ENA_TOGGLE == HIGH)
          {
            XMOTOR_TOGGLE = LOW;
            YMOTOR_TOGGLE = LOW;
          }
          digitalWrite(ENA_PIN, ENA_TOGGLE);
          break;
      //按键2控制X轴电机开关
      case '2':
          if (ENA_TOGGLE == LOW)
            XMOTOR_TOGGLE = !XMOTOR_TOGGLE;
          break;
      //按键3控制Y轴电机开关
      case '3':
          if (ENA_TOGGLE == LOW)
            YMOTOR_TOGGLE = !YMOTOR_TOGGLE;
          break;
      //按下按键4、7时,控制Y轴电机转向为HIGH
      case '4':
      case '7':
          digitalWrite(YDIR_PIN, HIGH);
          break;
      //按下5、8时,控制Y轴电机转向为LOW
      case '5':
      case '8':
          digitalWrite(YDIR_PIN, LOW);
          break;
      }
      break;
    //有按键长按时
    case HOLD:
      if (YMOTOR_TOGGLE == HIGH)
      {
      if (key == '4' || key == '5' || key == '7' || key == '8')
          YMOTOR_STATE = key;
      }
      break;
    //有按键释放时
    case RELEASED:
      if (YMOTOR_TOGGLE == HIGH)
      {
      if (key == '4' || key == '5' || key == '7' || key == '8')
      {
          YMOTOR_STATE = 0;
          digitalWrite(YSTEP_PIN, LOW);
      }
      }
      break;
}
}







lveader 发表于 2020-4-3 09:38

高人!

ll1234567 发表于 2020-4-3 12:37

不错,把程序复制下来了。

tianyuan08 发表于 2020-4-4 13:36

更新了一下程序,加了一个计数器变量,arduino上电的时候,变量初始化为0,当调焦筒伸出时每个脉冲计数器+1,当计数值到达30000的时候,按键也不再发送脉冲让调焦筒伸出。收回的时候计数值每个脉冲递减1,当脉冲计数大于1000时,以2000HZ的速度收回,当计数小于1000时,开始以100HZ收回,计数值到达0时,按键不也不再发送脉冲。这样就可以保护机械部分,避免调焦筒伸出、收回的时候到达限位时继续让电机运转造成机械部件的损伤。由于使用了步进电机控制,所以完全可以用程序来保护,不用加什么限位开关之类的了。另外,30000的上限是按照我的电机调速以及调焦筒最大伸出算的,方法很简单,在调焦筒上画一条线,控制电机让调焦筒伸出到达线停止,此时查看一下用了多少个脉冲即可~

更新程序如下:
#include <Key.h>
#include <Keypad.h>
#include <TimerOne.h>

//define ena for all motors
#define ENA_PIN 8

//define motor pins
#define XDIR_PIN 5
#define YDIR_PIN 6
#define XSTEP_PIN 2
#define YSTEP_PIN 3

//define keypad rows and cols
#define ROWS 3
#define COLS 3

//define a keymap
unsigned char keys =
{
{'1', '2', '3'},
{'4', '5', '6'},
{'7', '8', '9'}
};

//row->pin, col->pin
byte rowPins = {A3, 13, 12};
byte colPins = {A2, A1, A0};

//register keymap and pins
Keypad keypad = Keypad(makeKeymap(keys), rowPins, colPins, ROWS, COLS);

//XPUL_STATE保存X电机驱动电平状态
volatile byte XPUL_STATE = LOW;

//X电机,Y电机开关
volatile byte XMOTOR_TOGGLE = LOW;
volatile byte YMOTOR_TOGGLE = LOW;

//电机使能开关
volatile byte ENA_TOGGLE = HIGH;

//Y电机状态,指示哪个键被长按
volatile unsigned char YMOTOR_STATE = 0;

//Y电机的累计脉冲数, 不受电机使能、Y电机开关置0,上电后初始化为0
volatile unsigned int YSTEP_CNT = 0;

void setup() {
//set pin mod
pinMode(ENA_PIN, OUTPUT);
pinMode(XDIR_PIN, OUTPUT);
pinMode(XSTEP_PIN, OUTPUT);
pinMode(YDIR_PIN, OUTPUT);
pinMode(YSTEP_PIN, OUTPUT);
//set pin value
digitalWrite(ENA_PIN, ENA_TOGGLE);
digitalWrite(XDIR_PIN, HIGH);
//设置timer1的频率为32HZ,则每31.25ms触发一次
Timer1.initialize(31250);
Timer1.attachInterrupt(timer1_ISR);
//set keypad listener
keypad.addEventListener(keypadEvent);
//set hold dealy
keypad.setHoldTime(500);
//set serail
Serial.begin(9600);
}

//timer1的触发频率为32HZ,也就是1秒触发32次高低电平转换,则1秒为16HZ的方波信号,600秒产生9600个周期
void timer1_ISR()
{
if (XMOTOR_TOGGLE == HIGH)
{
    XPUL_STATE = !XPUL_STATE;
    digitalWrite(XSTEP_PIN, XPUL_STATE);
}
}

void loop() {
//listern keypad
keypad.getKey();
//drive Y-MOTOR
switch (YMOTOR_STATE)
{
    //长按按键4、5,产生2000HZ的方波
    case '4':
      if(YSTEP_CNT>0)
      {
      if(YSTEP_CNT>1000)
      {
          digitalWrite(YSTEP_PIN, HIGH);
          delayMicroseconds(250);
          digitalWrite(YSTEP_PIN, LOW);
          delayMicroseconds(250);
      }
      else
      {
          digitalWrite(YSTEP_PIN, HIGH);
          delay(5);
          digitalWrite(YSTEP_PIN, LOW);
          delay(5);
      }
      YSTEP_CNT--;
      }
      break;
    case '5':
      if(YSTEP_CNT<30000)
      {
      digitalWrite(YSTEP_PIN, HIGH);
      delayMicroseconds(250);
      digitalWrite(YSTEP_PIN, LOW);
      delayMicroseconds(250);
      YSTEP_CNT++;
      }
      break;
    //长按按键7、8,产生100HZ的方波
    case '7':
      if(YSTEP_CNT>0)
      {
      digitalWrite(YSTEP_PIN, HIGH);
      delay(5);
      digitalWrite(YSTEP_PIN, LOW);
      delay(5);
      YSTEP_CNT--;
      }
      break;
    case '8':
      if(YSTEP_CNT<30000)
      {
      digitalWrite(YSTEP_PIN, HIGH);
      delay(5);
      digitalWrite(YSTEP_PIN, LOW);
      delay(5);
      YSTEP_CNT++;
      }
      break;
}
}

void keypadEvent(KeypadEvent key)
{
switch (keypad.getState())
{
    //有按键发生时
    case PRESSED:
      switch (key)
      {
      //按键1控制电机使能
      case '1':
          ENA_TOGGLE = !ENA_TOGGLE;
          if (ENA_TOGGLE == HIGH)
          {
            XMOTOR_TOGGLE = LOW;
            YMOTOR_TOGGLE = LOW;
          }
          digitalWrite(ENA_PIN, ENA_TOGGLE);
          break;
      //按键2控制X轴电机开关
      case '2':
          if (ENA_TOGGLE == LOW)
            XMOTOR_TOGGLE = !XMOTOR_TOGGLE;
          break;
      //按键3控制Y轴电机开关
      case '3':
          if (ENA_TOGGLE == LOW)
            YMOTOR_TOGGLE = !YMOTOR_TOGGLE;
          break;
      //按下按键4、7时,控制Y轴电机转向为HIGH
      case '4':
      case '7':
          digitalWrite(YDIR_PIN, HIGH);
          break;
      //按下5、8时,控制Y轴电机转向为LOW
      case '5':
      case '8':
          digitalWrite(YDIR_PIN, LOW);
          break;
      }
      break;
    //有按键长按时
    case HOLD:
      if (YMOTOR_TOGGLE == HIGH)
      {
      if (key == '4' || key == '5' || key == '7' || key == '8')
          YMOTOR_STATE = key;
      }
      break;
    //有按键释放时
    case RELEASED:
      if (YMOTOR_TOGGLE == HIGH)
      {
      if (key == '4' || key == '5' || key == '7' || key == '8')
      {
          YMOTOR_STATE = 0;
          digitalWrite(YSTEP_PIN, LOW);
      }
      }
      break;
}
}

九大行星 发表于 2020-4-5 11:23

很羡慕会编程的人!

紫气东来 发表于 2020-4-22 20:06

厉害厉害

hldcloudyou 发表于 2020-4-22 23:24

能编程的都是高手

KKKVVV 发表于 2020-4-23 09:06

能编程的都是高手

vvv64 发表于 2020-4-25 14:18

很羡慕会编程的人!

信达小黑黑 发表于 2020-4-25 18:21

大神级别的人物啊!顶一下!新手膜拜中。

folker 发表于 2020-6-25 23:43

断电以后保存不了电机位置的。每次还是要回个参考点。这玩意还是要用多圈绝对值编码器才行吧。

弹琴的人 发表于 2020-7-10 10:29

膜拜 大神。

bell.chang 发表于 2020-7-10 11:04

曾几何时,我也是单片机编程爱好者,现在,。。。, 一言难尽....
页: [1]
查看完整版本: 再做一个简单的电调焦