Introduction: Lo-Fi Telescope Pointer
Recently I got interested in astrophotography, so I decided it was time to buy an entry level telescope to use my Canon EOS 600D. This instructable is about an Arduino-controlled DC motor for the telescope equatorial mount with a VB.NET interface including a NCP (North Celestial Pole) finder grid.
Step 1: Implementing NCP Finder Interface in VB.NET
I saw this awesome idea on YouTube (on this channel http://www.youtube.com/user/astronomyshed) where a guy was building an NCP finder with a common webcam. On the same channel, but in another tutorial, he was showing how to collimate a newtonian scope with a program called "Mire de collimation". From these two smart ideas I tried to create one single tool in VisualBasic to find the NCP with my reflex live view mode on PC.
First I used Stellarium to set my DSLR sensor preview (on reflex website you can find all the parameters to fill the input mask in Stellarium). Then I took few screenshots and I edited them with Photoshop adding a circle around Polaris, a sort of cross in the NCP position and deleting the background: it's important to obtain a transparent image.
Step 2: The Telescope
First of all you'll need an equatorial mount. I've got this one from Celestron Astromaster 130 EQ-MD telescope, it comes with a DC motor for apparent sky movement compensation. You probably noticed that one does not simply to regulate the correct speed with the potentiometer, so your photos exposure can't be as long as you want. This telescope is a cheap model so at this time I'm gonna make a more accurate speed regulation with Arduino PWM.
In this step I've just soldered the motor terminals and I applied some glue to reinforce the junction.
Step 3: Make the Arduino Shield
List of materials I used:
- Arduino UNO R3
- Prototype board
- L293DNE half-h driver
- LM7806 voltage regulator
- (1x) .33 uF capacitor
- (1x) .10 uF capacitor
- (2x) 27 kOhm resistor
- (1x) 10 kOhm resistor
- Generic transistor
- SIL male connectors
- Some wires
- pin IC socket (optional but suggested)
- Bluetooth serial module (optional)
___________________________________
The L293DNE from Texas Instruments it's a quadruple half-h driver (it can handle up to 2 DC motors). It provides separately the voltage to the load and it's also possible to control the direction of the current flow on output pins, so you're able to change rotating direction.
In the "original" setup DC motor is powered by a 9 V battery and a regulation circuit keeps the voltage down to 5.6 V at maximum speed, so I supposed my DC was a 6 V motor. Unfortunately the USB 5 V isn't enough, so we have to power the motor separately. I choose the LM7806 to give 6 V from a common 9 V battery.
In this first prototype shield I didn't reach perfection: I corrected some connection errors and I realized component placing isn't optimized yet; however in the future I'd like to add a temperature sensor and draw the entire board with Fritzing to use SMD components. I hope to post a second instructable where I can show a better job...
Step 4: Add the VB.NET Serial Communication
Basically it's a simple serial interface, it's not difficult to realize and there are a lot of tutorials about this. However I want to share my own version with some explanations.
This function shows you all the available COM ports and displays them in a ComboBox. You can't use ButtonConnect until there are no available COM ports.
Sub refreshCOM() ComboBox_COM.Items.Clear() For Each sp As String In My.Computer.Ports.SerialPortNames ComboBox_COM.Items.Add(sp) Next If ComboBox_COM.Items.Count = 0 Then Else ComboBox_COM.Text = ComboBox_COM.Items.Item(0).ToString End If If ComboBox_COM.Text = "" Then ButtonConnect.Enabled = False Else ButtonConnect.Enabled = True End If End Sub
Serial port setup with DTR disabling to keep Arduino waiting until PC correctly opens the port.
Private Sub MainForm_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load refreshCOM() SerialPort1.Close() SerialPort1.DataBits = 8 SerialPort1.Parity = Parity.None SerialPort1.StopBits = StopBits.One SerialPort1.Handshake = Handshake.None SerialPort1.Encoding = System.Text.Encoding.Default SerialPort1.DtrEnable = False End Sub
Finally we can try to connect with the serial port and, if nothing goes wrong, we can enable the DTR. I've got some problems during Bluetooth communication: it seems that Arduino doesn't wait for the DTR enabling... I think it's due to a missing connection between my BT board and Linvor transceiver.
Private Sub ButtonConnect_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ButtonConnect.Click SerialPort1.Close() SerialPort1.PortName = ComboBox_COM.Text.ToString SerialPort1.BaudRate = ComboBox_BAUD.Text Try SerialPort1.Open() Catch ex As Exception MsgBox("Error during shield connection.") End Try If SerialPort1.IsOpen Then TextBox1.Clear() Label2.Enabled = True MaskedTextBox1.Enabled = True ButtonSetSpeed.Enabled = True SerialPort1.DiscardInBuffer() SerialPort1.DtrEnable = True Else Label2.Enabled = False MaskedTextBox1.Enabled = False ButtonSetSpeed.Enabled = False End If End Sub
This is serial port reading method, the the program will also refresh GUI values in the StatusStrip and will gives the raw strings in a dedicated TextBox (for outdoor quick debugging).
Private Sub SerialPort1_DataReceived(ByVal sender As System.Object, ByVal e As System.IO.Ports.SerialDataReceivedEventArgs) Handles SerialPort1.DataReceived Try Dim line As String = SerialPort1.ReadLine TextBox1.Invoke(New ReadSerialDelegate(AddressOf ReadSerial), line.ToString) Catch ex As Exception SerialPort1.Close() End Try End Sub Delegate Sub ReadSerialDelegate(ByVal s As String) Public Sub ReadSerial(ByVal s As String) TextBox1.Text += s + vbNewLine TextBox1.SelectionStart = TextBox1.Text.Length - 1 TextBox1.ScrollToCaret() If s.Contains("charge") Then Label_Battery.Text = s.Substring(s.Length - 4, 3) ElseIf s.Contains("speed") Then Label_Speed.Text = s.Substring(s.Length - 4, 3) End If End Sub
Writing method is really simple, I won't spend words with it.
Private Sub ButtonSetSpeed_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ButtonSetSpeed.Click Try SerialPort1.Write(MaskedTextBox1.Text) Label_Speed.Text = MaskedTextBox1.Text Catch ex As Exception MsgBox(vbInformation, "Unable to write at " + SerialPort1.PortName) End Try End Sub
So now we have a bare bones code to handle entire serial communication.
Step 5: Write .INO Code
Arduino must receive the speed command and send the current battery level.
Change R1 and R2 with your resistors values, I used a multimeter to find the exact values of mine. Battery voltage is calculated with 9 V supply regulated by a LM7806, so we have about 3 V of "margin" before voltage reaches the threshold of 6 V and the output of LM7806 starts to decrease.
const float R1 = 26600.0; const float R2 = 26600.0; const float VBATT = 3; const int refreshRate = 10000; int south = 1; int batteryTimeout = 0;
In Arduino pinout configuration make sure that the batteryPin is an analog type.
int batteryPin = 0; int enableCheckPin = 7; int enableMotorPin = 3; int in1Pin = 2; int in2Pin = 4;
On setup, Arduino will wait until DTR is enabled.
void setup() { pinMode(batteryPin, INPUT); pinMode(tempPin, INPUT); pinMode(enableCheckPin, OUTPUT); pinMode(in1Pin, OUTPUT); pinMode(in2Pin, OUTPUT); pinMode(enableMotorPin, OUTPUT); Serial.begin(9600); while (!Serial); delay(1000); Serial.println("-------ARDUINO-------"); }
Here there is a basic voltmeter for the battery level measure, if charge is higher than 100% it means the battery is disconnected (I added an additional 5% for noise error prevention). In my case the measure is taken every 10000 ms (10 s), but obviously you can change it. Otherwise the DC speed can be changed in "real-time" mode.
void loop() { if (batteryTimeout == 0) { batteryTimeout = refreshRate; digitalWrite(enableCheckPin, HIGH); delay(500); float Vout = (analogRead(batteryPin) * 5.0) / 1024.0; digitalWrite(enableCheckPin, LOW); float Vin = Vout / (R2 / (R1 + R2)); int charge = (Vin * 100) / VBATT; Serial.print("Current charge: 0"); if (charge > 105) { Serial.println(" - "); } else { Serial.print(charge); Serial.println("%"); } } digitalWrite(in1Pin, !south); digitalWrite(in2Pin, south); if (Serial.available()) { int speed = Serial.parseInt(); if (speed >= 0 && speed <= 255) { analogWrite(enableMotorPin, speed); Serial.print("New speed set: 00"); Serial.println(speed); } } batteryTimeout--; delay(1); }
This code need to be optimized, it's just a basic sketch to begin outdoor tests.
Step 6: Testing
On a dark night I tested entire stuff:
- Check on Stellarium an object to observe and try to memorize its position.
- Find a dark and flat area from where you can see both Polaris and the object you choose.
- Place the equatorial mount, install the DSLR on it and make sure the system is parallel to gravity force direction.
- Connect DSLR to PC, open VB.NET NCP Finder and the DSLR remote software to correctly find NCP.
- HINT: you may use a Bahtinov mask to set focus on Polaris...
Now you can power the DC motor and take some photos to calibrate speed before your night observation.
After some tests, I've found MANY bugs in this first setup:
- First of all power consumption (currently I'm going re-write the .INO code adding avr/sleep.h and avr/power.h).
- The NCP finder mask isn't correct because Polaris changes its position during a year! I must design a 365-valid mask.
- The voltage divider circuit doesn't work as well as I want: there's about 3 V fall on the BJT, don't know why it doesn't just work as a pass-transistor... I need to study electronic theory first!
I'm working on a second (improved) version of this Lo-Fi pointer, I'll post some news...
Hope this instructable will inspire you!