Skip to content

Commit 974cb8d

Browse files
committed
Add code for a new Arduino board for the 637nm diode laser. Tested.
1 parent 110dbb9 commit 974cb8d

File tree

3 files changed

+255
-37
lines changed

3 files changed

+255
-37
lines changed

README.md

Lines changed: 53 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,50 @@
1-
# Two projects inside one github repository:
1+
# Three projects inside one github repository:
22
* Coherent Sapphire 488mW Laser GUI written in LabView
3-
* Thorlabs LDC Arduino controller and a GUI written in LabView
3+
* Thorlabs LDC205C Arduino controller code and a LabView GUI _(ldc205c)_
4+
* Thorlabs LDC500 Arduino controller code #2 and a LabView GUI _(ldc500sh)_
45

5-
## Coherent Sapphire 488mW GUI:
6-
7-
[Our team](http://titan.physx.u-szeged.hu/~adoptim/) got a Coherent Sapphire 488nm laser with the LP USB CDRH Driver Unit. This means, it can be only controlled via RS-232. So I wrote a similar GUI as the Arduino LDC205 one, but with advanced internals (STATES). It can be used with any Coherent Lasers as far as I know, because during startup it will check for minimum and maximum laser power values.
8-
9-
### Changelog:
6+
## Changelog:
107
* Initial release with states.
118
* It searches for a config file: _Documents\LabVIEW Data\LaserControlSettings.ini_
129
* There is also a build.
10+
* Create the second arduino driver: ldc500sh
11+
12+
# Graphical User Interface in LabView 14.
13+
![](./UI.png)
14+
15+
# Coherent Sapphire 488mW GUI:
16+
[Our team](http://titan.physx.u-szeged.hu/~adoptim/) got a Coherent Sapphire 488nm laser with the LP USB CDRH Driver Unit. This means, it can be only controlled via RS-232. So I wrote a similar GUI as the Arduino LDC205 one, but with advanced internals (STATES). It can be used with any Coherent Lasers as far as I know, because during startup it will check for minimum and maximum laser power values.
1317

14-
## thorlabs-ldc-arduino the arduino code for a laser driver.
15-
* Arduino UNO R3 controller for Thorlabs LDC205, and LDC500.
18+
# LDC205C: For laser 405nm, for the PWM to LowPass filter edition board.
19+
We have a Thorlabs LDC205C which controls a Nichia 405nm laser diode. To control the diode current, an Arduino's PWM output is driven at 31kHz and RC LowPass filtered. This Arduino UNO R3 and board can be used to create diode currents below 200mA, read back the diode current, and enable/disable laser.
20+
* Arduino UNO R3 controller for [Thorlabs LDC205](http://www.thorlabs.de/newgrouppage9.cfm?objectgroup_id=10&pn=LDC205C), and LDC500.
1621
* You can split the MOD IN output to control both lasers with the same modulation. (We don't use both lasers at the same time.)
17-
* http://www.thorlabs.de/newgrouppage9.cfm?objectgroup_id=10&pn=LDC205C
1822
* Serial communication examples are used
19-
* The String->float conversion: http://forum.arduino.cc/index.php?topic=179666.msg1331654#msg1331654
20-
* LP Filter: http://sim.okawa-denshi.jp/en/PWMtool.php
21-
* PWM speedup from here: http://playground.arduino.cc/Code/PwmFrequency
22-
* DHTlib, get it from here: http://playground.arduino.cc//Main/DHTLib
23+
* [The String->float conversion](http://forum.arduino.cc/index.php?topic=179666.msg1331654#msg1331654)
24+
* [LowPass Filter Calculator](http://sim.okawa-denshi.jp/en/PWMtool.php)
25+
* [Arduino Timer PWM speedup from here](http://playground.arduino.cc/Code/PwmFrequency)
26+
* [DHTlib, get it from here](http://playground.arduino.cc//Main/DHTLib)
2327

2428
### Sort of documentation:
2529
* LabView GUI for LDC205 ver 1.0: https://gajdicookbook.wordpress.com/2016/02/07/189/
2630
* Rewritten to a Cobolt subVI free version. Updated to ver 2.0.
2731
* The Project and a build is also included.
28-
* Controller: https://gajdicookbook.wordpress.com/2015/02/16/arduino-controller-for-thorlabs-ldc200c-series/
32+
* [Controller](https://gajdicookbook.wordpress.com/2015/02/16/arduino-controller-for-thorlabs-ldc200c-series/)
33+
34+
### Start Here for the Arduino Controller LDC205C edition:
35+
1. Clone the repository to your sketchbook folder.
36+
2. Connect the BNC connectors:
37+
* LD REM to pin 13. (Same as the L Led on the board)
38+
* MOD IN to pin 11. (You can split the output.)
39+
* CTLOUT1 to pin A0. (first laser)
40+
* CTLOUT2 to pin A1. (second laser, read only mode)
41+
3. Calculate the Low-pass filter R&C values from here: http://sim.okawa-denshi.jp/en/PWMtool.php
42+
4. Burn it to your Arduino UNO.
43+
5. Optionally connect a DHT22 sensor.
44+
45+
### Currently used R&C values:
46+
* R=5k3 Ohm
47+
* C=105
2948

3049
### Changelog for the thorlabs-ldc-arduino & GUI:
3150
* Merged the DHT22 temperature code, from the branch.
@@ -34,37 +53,40 @@
3453
* De-blobbed the previous LabView GUI, and included in this repository.
3554
* It searches for a config file: _Documents\LabVIEW Data\LaserControlSettings.ini_
3655
* There is also a build.
56+
57+
## LDC500SH: For laser 637nm, for the PWM to NPN-NPN-LowPass filter edition board.
58+
Recently we installed a 637nm laser into a second laser head which is controlled by a LDC500. To control the diode current an Arduino's PWM output is driven at 31kHZ and converted to 0-10V region. This is then LowPass filtered. This Arduino UNO R3 and board can be used to create diode currents from 0mA to 400mA, read back the diode current, and control a solenoid shutter.
59+
* Arduino UNO R3 controller for [Thorlabs LDC500](https://www.thorlabs.de/thorproduct.cfm?partnumber=LDC500).
60+
* [Simulation](http://www.falstad.com/circuit/circuitjs.html?cct=$+1+0.000005+10.20027730826997+29+5+43%0Ar+0+128+48+128+0+10000%0Ar+0+32+0+128+0+10000%0Ar+-160+144+-32+144+0+10000%0Ar+80+112+144+112+0+1000%0Ar+192+112+192+208+0+10000%0Ad+-144+32+-144+80+2+default%0Ad+-128+80+-128+32+2+default%0Ad+-112+32+-112+80+2+default%0Ad+-96+80+-96+32+2+default%0Aw+-144+80+-128+80+0%0Aw+-128+32+-112+32+0%0Aw+-112+80+-96+80+0%0Aw+-96+32+0+32+0%0At+-32+144+0+144+0+1+0.5735729797720364+0.6114101312853065+160%0Ag+0+208+0+272+0%0Aw+0+160+0+192+0%0AR+-144+32+-192+32+0+0+40+12+0+0+0.5%0AR+-160+144+-192+144+4+5+1000+5+0+0+0.7822%0At+48+128+80+128+0+1+-8.636823909212664+0.037837152566076566+100%0Aw+0+32+32+32+0%0Ac+144+112+144+208+0+0.000009999999999999999+6.134599156316293%0Aw+144+112+192+112+0%0Aw+144+208+192+208+0%0Aw+80+208+0+208+0%0Aw+0+192+0+208+0%0A368+32+32+32+-32+0+0%0Aw+80+144+80+208+0%0A368+192+112+224+112+0+0%0A174+32+32+128+48+0+1000+0.5+Resistance%0Aw+80+112+80+48+0%0Aw+80+208+144+208+0%0Ao+27+64+0+4099+10+12.8+0+2+27+3%0Ao+25+64+0+4099+20+12.8+1+2+25+3%0A38+17+3+1+1000+Frequency%0A38+17+5+1+100+Duty%5CsCycle%0A)
61+
*
3762

38-
# Start Here for the Arduino Controller:
63+
### Start Here for the Arduino Controller LDC500 edition:
3964
1. Clone the repository to your sketchbook folder.
4065
2. Connect the BNC connectors:
41-
* LD REM to pin 13. (Same as the L Led on the board)
42-
* MOD IN to pin 11. (You can split the output.)
43-
* CTLOUT1 to pin A0. (first laser)
44-
* CTLOUT2 to pin A1. (second laser, read only mode)
45-
3. Calculate the Low-pass filter R&C values from here: http://sim.okawa-denshi.jp/en/PWMtool.php
46-
4. Burn it to your Arduino UNO.
47-
5. Optionally connect a DHT22 sensor.
66+
* OptoRelay for solenoid to pin 13. (Same as the L Led on the board)
67+
* MOD IN to pin 9. (You can split the output.)
68+
* CTLOUT1 to pin A5. (first laser)
69+
3. Burn it to your Arduino UNO.
4870

4971
# Communication with the Controller: 115200 8N1
5072
## Send Command: Carridge Return (\r)
5173
* l? -> GET laser status (0: disabled, 1: enabled)
52-
* l[0,1] -> DISABLE/ENABLE laser
74+
* l[0,1] -> DISABLE/ENABLE laser or shutter
5375
* i? -> GET laser current (float [mA])
5476
* p?, pa? -> GET laser power (float [W])
5577
* slc[0..100] -> SET laser current
56-
* p[0.0001..0.1] -> SET laser power
78+
* p[0.0001..0.1] -> SET laser power (only LDC205C)
5779
* hrs? -> GET uptime in minutes (float)
5880
* sn? -> GET serial (int)
59-
* ilk? -> GET interlock state (always 0)
60-
* f? -> GET operation fault state (always 0)
61-
* leds? -> GET led status (1: Power on, 7: Laser on)
81+
* ilk? -> GET interlock state (always 0) (only LDC205C)
82+
* f? -> GET operation fault state (always 0) (only LDC205C)
83+
* leds? -> GET led status (1: Power on, 7: Laser on)
6284

63-
## Second laser, just readout
85+
## Second laser, just readout (only LDC205C)
6486
* j? -> GET laser current (float [mA])
6587
* q?, qa? -> GET laser power (float [W])
6688

67-
## DHT22 Communication:
89+
## DHT22 Communication: (only LDC205C)
6890
* d? -> GET sensor status (0: error, 1: ok)
6991
* dt? -> GET temperature (float)
7092
* dh? -> GET humidity (float)
@@ -76,15 +98,9 @@
7698
* Thorlabs: https://www.thorlabs.com/thorproduct.cfm?partnumber=LDC500
7799
* Coherent: I have the Operator's Manual on paper.
78100

79-
# Currently used R&C values:
80-
* R=5k3 Ohm
81-
* C=105
82-
83101
# Issues with Arduino Leonardo:
84102
* The board does not handle SerialEvents. [FIX](http://forum.arduino.cc/index.php?topic=150558.msg1131262#msg1131262)
85103
* [The board does not have Timer2](http://provideyourown.com/2012/arduino-leonardo-versus-uno-whats-new/):
86104
* Timer4 can be used, but a different board design and pins are needed.
87105

88-
# Graphical User Interface in LabView 14.
89-
90-
![](./UI.png)
106+
# If you need help with the electronics, contact me.
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
$ 1 0.000005 10.20027730826997 29 5 43
2+
r 0 128 48 128 0 10000
3+
r 0 32 0 128 0 10000
4+
r -160 144 -32 144 0 10000
5+
r 80 32 80 112 0 1000
6+
r 80 112 144 176 0 1000
7+
r 192 176 192 208 0 10000
8+
d -144 32 -144 80 2 default
9+
d -128 80 -128 32 2 default
10+
d -112 32 -112 80 2 default
11+
d -96 80 -96 32 2 default
12+
w -144 80 -128 80 0
13+
w -128 32 -112 32 0
14+
w -112 80 -96 80 0
15+
w -96 32 0 32 0
16+
t -32 144 0 144 0 1 -5.19171905949069 1.0519171903302032e-9 160
17+
g -160 192 -160 240 0
18+
w -160 192 0 192 0
19+
w 0 160 0 192 0
20+
R -144 32 -192 32 0 0 40 12 0 0 0.5
21+
R -160 144 -192 144 4 5 1000 5 0 0 0.01
22+
t 48 128 80 128 0 1 0.5683941388822813 0.6560792559024179 100
23+
w 0 32 80 32 0
24+
c 144 176 144 208 0 0.000009999999999999999 0.12627429979979585
25+
w 144 176 192 176 0
26+
w 144 208 192 208 0
27+
w 144 208 0 208 0
28+
w 0 192 0 208 0
29+
368 80 32 128 32 0 0
30+
w 80 144 0 192 0
31+
w 192 176 272 176 0
32+
368 272 176 384 176 0 0
33+
o 30 64 0 4099 10 12.8 0 2 30 3
34+
o 27 64 0 4099 20 12.8 1 2 27 3
35+
38 19 3 1 1000 Frequency
36+
38 19 5 1 100 Duty\sCycle

ldc500sh/ldc500sh.ino

Lines changed: 166 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,166 @@
1+
/*
2+
A Controller for the Thorlabs LDC205C/LDC500 series equipment.
3+
This version needs a custom electronics after pin10 (see github readme, or sim link), and also an opto-relay for the solenoid.
4+
LDC205C: https://www.thorlabs.com/thorproduct.cfm?partnumber=LDC205C
5+
LDC500: https://www.thorlabs.com/thorproduct.cfm?partnumber=LDC500
6+
Code under GPLv2 license. Author: gajdost
7+
8+
Main Functions:
9+
* Laser Shutter -> Pin 13 + !LED
10+
* SET Laser Current -> Pin 9 (Changed to 31 kHz)
11+
* GET Laser1 Current -> A5 -> i?
12+
13+
LDC205C, LDC500 -> k=50mA/V (conversion factor when reading current)
14+
15+
Commands Cobolt Gen5 style+
16+
*/
17+
// Variables and constants fot the GUI
18+
unsigned int serialNumber = 637; // Just a check in the GUI.
19+
float versionNumber = 2.1; // Code for different laser with shutter.
20+
float time;
21+
22+
// Modulation coeff. from datasheet.
23+
float kLDC = 50.0; // mA/V
24+
25+
// Inverse Current fit: PWM = iA0*I^2 + iB0*I + iC0
26+
const float iC0 = -3.63883;
27+
const float iB0 = 0.83821;
28+
const float iA0 = -0.00063;
29+
const int pwmLimit = 170; // Hard limit, just in case.
30+
31+
// 637nm laser in the LDC500: P = pA1*I*I + pB1*I + pC1
32+
const float pA1 = -0.00082;
33+
const float pB1 = 0.97591;
34+
const float pC1 = -60.3816;
35+
36+
// Define used pins.
37+
const int laserSH = 13;
38+
const int laserMod = 9;
39+
const int laser1CTL = A5; // 637nm laser in the LDC500
40+
41+
// For serial communication.
42+
String inputString = ""; // a string to hold incoming data
43+
boolean stringComplete = false; // whether the string is complete
44+
45+
// The initial setup, that will run every time when we connect to the Arduino via serial.
46+
void setup() {
47+
Serial.begin(115200);
48+
pinMode(laserSH, OUTPUT);
49+
pinMode(laserMod, OUTPUT);
50+
digitalWrite(laserSH, LOW);
51+
// while (!Serial) {
52+
// ; // wait for serial port to connect. Needed for native USB
53+
// }
54+
// Change PWM Frequency for Timer2. f=~31kHZ
55+
// Copied the relevant part from here: http://playground.arduino.cc/Code/PwmFrequency
56+
TCCR1B = TCCR1B & 0b11111000 | 0x01;
57+
inputString.reserve(200); // reserve 200 bytes for the inputString:
58+
digitalWrite(laserSH, HIGH);
59+
}
60+
61+
void setCurrent(float i) {
62+
int iDigit = iA0*i*i + iB0*i + iC0;
63+
if (iDigit > pwmLimit) { iDigit = 170; }
64+
if (iDigit < 0) { iDigit = 0; }
65+
analogWrite(laserMod, iDigit);
66+
Serial.println("OK\r");
67+
}
68+
69+
float getVoltage() {
70+
int ctlOut = analogRead(laser1CTL);
71+
// Convert the analog reading (which goes from 0 - 1023) to a voltage (0 - 5V):
72+
return ctlOut*0.005; // voltage
73+
}
74+
75+
float getCurrent() {
76+
return getVoltage()*kLDC;
77+
}
78+
79+
float getPower() {
80+
float c = getCurrent();
81+
float p = pA1*c*c + pB1*c + pC1;
82+
if ( p > 0 ) return p; else return 0.0;
83+
}
84+
85+
float toFloat(String s) {
86+
char carray[s.length() + 1]; //determine size of the array
87+
s.toCharArray(carray, sizeof(carray)); //put readStringinto an array
88+
float floatNumber = atof(carray); //convert the array into a float
89+
return floatNumber;
90+
}
91+
92+
void loop() {
93+
// get any incoming bytes:
94+
if (stringComplete) {
95+
// Status of 4 LEDs
96+
if (inputString.startsWith("leds?")) {
97+
// POWER ON + LASER ON + LASER LOCK + ERROR = 1 + 2 + 4 + 8
98+
Serial.println(1+digitalRead(laserSH)*6);
99+
// Laser ENABLE/DISABLE/STATE (shutter actually)
100+
} else if (inputString.startsWith("l")) {
101+
if (inputString.substring(1,2) == "1") {
102+
digitalWrite(laserSH,LOW);
103+
Serial.println("Laser ON\r");
104+
} else if (inputString.substring(1,2) == "0") {
105+
digitalWrite(laserSH,HIGH);
106+
Serial.println("Laser OFF\r");
107+
} else if (inputString.substring(1,2) == "?") {
108+
Serial.println(!digitalRead(laserSH));
109+
}
110+
// Drive Current GET
111+
} else if (inputString.startsWith("i?")) {
112+
Serial.println(getCurrent());
113+
// Drive Current SET
114+
} else if (inputString.startsWith("slc")) {
115+
setCurrent(toFloat(inputString.substring(3)));
116+
} else if (inputString.startsWith("d")) {
117+
if (inputString.substring(1,2) == "?")
118+
Serial.println(analogRead(laserMod));
119+
else
120+
analogWrite(laserMod, toFloat(inputString.substring(1)));
121+
// Power GET/SET
122+
} else if (inputString.startsWith("p")) {
123+
if ((inputString.substring(1,2) == "?") || (inputString.substring(1,3) == "a?")) {
124+
Serial.println(getPower());
125+
}
126+
// Serial Number
127+
} else if (( inputString.startsWith("sn?") ) || (inputString.substring(3,6) == "sn?") ) {
128+
Serial.println(serialNumber);
129+
// Version Number
130+
} else if (inputString.startsWith("ver?")) {
131+
Serial.println(versionNumber);
132+
// Working seconds
133+
} else if (inputString.startsWith("hrs?")) {
134+
time = millis()/60000.0;
135+
Serial.println(time);
136+
// Are you there? Returns Ok (undocumented Cobolt command)
137+
} else if (inputString.startsWith("?")) {
138+
Serial.println("OK");
139+
} else {
140+
Serial.print("Syntax Error: ");
141+
Serial.println(inputString);
142+
}
143+
// clear the string:
144+
inputString = "";
145+
stringComplete = false;
146+
}
147+
}
148+
/*
149+
SerialEvent occurs whenever a new data comes in the
150+
hardware serial RX. This routine is run between each
151+
time loop() runs, so using delay inside loop can delay
152+
response. Multiple bytes of data may be available.
153+
*/
154+
void serialEvent() {
155+
while (Serial.available()) {
156+
// get the new byte:
157+
char inChar = (char)Serial.read();
158+
// add it to the inputString:
159+
inputString += inChar;
160+
// if the incoming character is a carriage return (ASCII 13),
161+
// set a flag so the main loop can do something about it:
162+
if (inChar == '\r') {
163+
stringComplete = true;
164+
}
165+
}
166+
}

0 commit comments

Comments
 (0)