再做一个简单的电调焦
本帖最后由 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;
}
}
高人! 不错,把程序复制下来了。 更新了一下程序,加了一个计数器变量,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;
}
} 很羡慕会编程的人! 厉害厉害 能编程的都是高手 能编程的都是高手 很羡慕会编程的人! 大神级别的人物啊!顶一下!新手膜拜中。 断电以后保存不了电机位置的。每次还是要回个参考点。这玩意还是要用多圈绝对值编码器才行吧。 膜拜 大神。 曾几何时,我也是单片机编程爱好者,现在,。。。, 一言难尽....
页:
[1]