SR830 Lock-in Amplifier

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
Bartolomeo85
User
Beiträge: 6
Registriert: Donnerstag 19. August 2021, 15:00

Moin zusammen,
ich bin gerade etwas am verzweifeln, ich hoffe ihr könnt mir helfen.
Ich arbeite mit einem SR830 Lock-in Amplifier von Stanford Research Systems.
Mit folgendem Code kann ich den LockIn wunderbar vom Raspberry Pi auslesen:

#####################
import serial

def toBytes(string):
return bytes(string, 'utf-8')

def make_lockin_connection(port):
return serial.Serial(port, 9600, parity=serial.PARITY_NONE, stopbits=serial.STOPBITS_ONE, bytesize=serial.EIGHTBITS, timeout = 2)

if __name__ == "__main__":
port = "/dev/ttyUSB0"
con = make_lockin_connection(port)
con.write(toBytes('OUTX0\n')) #Set Output to RS232
con.write(toBytes('*IDN?\n')) # Get the IDN of the connected LockIn
answer = con.readline().decode("utf-8")
con.close()
print(answer)
#####################

Momentan schreibe ich das Programm so um, dass ich von einem Windows Rechner den LockIn auslesen kann, der Code dafür ist folgender:


#####################
import serial

def toBytes(string):
return bytes(string, 'utf-8')

def make_lockin_connection(port):
return serial.Serial(port, 9600, parity=serial.PARITY_NONE, stopbits=serial.STOPBITS_ONE, bytesize=serial.EIGHTBITS, timeout = 2)

if __name__ == "__main__":
port = "CPM5"
con = make_lockin_connection(port)
con.write(toBytes('OUTX0')) #Set Output to RS232
con.write(toBytes('*IDN?')) # Get the IDN of the connected LockIn
answer = con.readline().decode("utf-8")
con.close()
print(answer)
#####################

Das Problem ist aber, dass ich keine Antwort bekomme. Auf dem Raspi bekomme ich die ID vom LockIn wieder, hier nichts.
Könnte ihr mir vielleicht helfen? wo ist mein Fehler? habe ich schlicht einfach noch was vergessen?

Ich freue mich auf eure Antworten!
__deets__
User
Beiträge: 14545
Registriert: Mittwoch 14. Oktober 2015, 14:29

Die fehlen die Zeilenendezeichen. Hast du von Hand abgetippt statt zu kopieren?
Bartolomeo85
User
Beiträge: 6
Registriert: Donnerstag 19. August 2021, 15:00

Hi, danke für die schnelle Antwort.
Meinst du die "\n"?
Ich habe die beim Code für Windows extra weg gelassen, soweit ich weis, sind die nur für Linux gedacht. Jedoch habe ich beide Varianten ausprobiert und ich bekomme nichts zurück. Wenn ich bei der Windows-Variante "\n" benutze, meldet mir der LockIn, am Gerät, einen Fehler.
__deets__
User
Beiträge: 14545
Registriert: Mittwoch 14. Oktober 2015, 14:29

Das hat nichts mit Linux zu tun. Sondern damit, wie dein Gerät funktioniert. Ohne die wird es nicht gehen. Steht hier https://research.ece.cmu.edu/~mems/reso ... SR830m.pdf

Zu dem Fehler kann ich nix sagen. Ich sehe ihn ja nicht.
Bartolomeo85
User
Beiträge: 6
Registriert: Donnerstag 19. August 2021, 15:00

Den Fehler sehe ich auch nicht, das einzige was ich sehe ist, das eine Lampe für Error aufleuchtet, wenn ich "\n" mit sende.
Trotzdem bekomme ich bei beiden Varianten nichts zurück.
Mich wundert halt, dass es übers Raspi geht und mit dem "selben" code, nur mit halt für windows anderen Port, funktioniert es nicht.

kann es noch an was anderem liegen?
__deets__
User
Beiträge: 14545
Registriert: Mittwoch 14. Oktober 2015, 14:29

Ich würde ein Terminal Programm benutzen & es mal damit probieren. Denn das liest auch irgendwelche Ausgaben aus. Und das verlinkte Handbuch durchlesen, ob und wie genau Fehler kommuniziert werden.

Aber um das nochmal ganz klar zu machen: ohne newline geht es nicht. Das du keinen Fehler bekommen hast, war kein Zeichen von alles super. Sondern wie eine unversandte Kündigung. Passiert halt nix.
Bartolomeo85
User
Beiträge: 6
Registriert: Donnerstag 19. August 2021, 15:00

Moin, schon etwas her, aber ich habe ein wenig rum probiert.
Hier der Code mit dem ich den SR830 wunderbar auslesen kann:

def reflectivity(COMport1, COMport2, detector_const, readouts):
ser = serial.Serial(COMport1, 9600, parity=serial.PARITY_NONE, stopbits=serial.STOPBITS_ONE, bytesize=serial.EIGHTBITS, timeout = 0.05)
ser1 = serial.Serial(COMport2, 9600, parity=serial.PARITY_NONE, stopbits=serial.STOPBITS_ONE, bytesize=serial.EIGHTBITS, timeout = 0.05)
summe = 0
summe1 = 0
ser.write('OUTX0\n'.encode('utf-8'))
ser1.write('OUTX0\n'.encode('utf-8'))
for i in range(0,readouts):
try:
ser.write('OUTP?3\n'.encode('utf-8'))
response = float(ser.readline())
summe += response
print("first try res:", response)
except ValueError:
ser.write('OUTP?3\n'.encode('utf-8'))
response = float(ser.readline())
summe += response
print("second try res:", response)
try:
ser1.write('OUTP?3\n'.encode('utf-8'))
response1 = float(ser1.readline())
summe1 += response1
print("first try res1:", response1)
except ValueError:
ser1.write('OUTP?3\n'.encode('utf-8'))
response1 = float(ser1.readline())
summe1 += response1
print("second try res1:", response1)
S1 = summe/readouts
S2 = summe1/readouts
divide = S2/S1
reflectivity = (1-divide*detector_const)/(1+divide*detector_const)
ser.close()
ser1.close()
return reflectivity

Ja ich weis, in den except's wird das Gleiche probiert wie im try's, fragt mich nicht warum, ich habe den Code aus einem fast 10 Jahre alten Programm.
Als Ergebnis bekomme ich immer:
frist try res: ....
first try res1: ....
usw.

Sobald ich die try's und except's entferne, bekomme ich bei "response1 = float(ser1.readline())" immer den Fehler, dass readline() Nichts zurück bekommt. Selbst wenn ich die Port's tausche, also die Reihenfolge, des Auslesens, der LockIn's wechsle, bekomme ich immer den Fehler bei "response1 = ...".

Hat jemand einen Hilfreichen Tipp, warum, wieso, weshalb?
__deets__
User
Beiträge: 14545
Registriert: Mittwoch 14. Oktober 2015, 14:29

Bei deinem absurd kleinen timeout ist es kein Wunder, das nix zurück kommt.

Und Code bitte in Code Tags setzen. Der ist sonst nahezu unlesbar.

Statt des permanenten "encode('UTF-8')" einfach ein b vor das Literal schreiben, dann hast du gleich Bytes.
Bartolomeo85
User
Beiträge: 6
Registriert: Donnerstag 19. August 2021, 15:00

Sry für die Unleserlichkeit.
Egal auf was ich die Timeouts ändere (außer unter 0.03), das Problem bleibt.
__deets__
User
Beiträge: 14545
Registriert: Mittwoch 14. Oktober 2015, 14:29

Warum *hast* du einen Timeout? Weisst du, was der Timeout macht, und wie es sich aeussert, dass er "zugeschlagen" hat? Und hast du meine Tipp mit dem Terminal mal ausprobiert? Was dabei ist rumgekommen?

Programmierung (und den Umgang mit System, die Programmiert sind, wie dein Geraet) ist systematische Arbeit. Nicht eine Piniata, auf der man rumkloppt, bis die Belohnung rauskommt.
__deets__
User
Beiträge: 14545
Registriert: Mittwoch 14. Oktober 2015, 14:29

Und noch eine Frage: warum ploetzlich zwei serielle Ports?
Bartolomeo85
User
Beiträge: 6
Registriert: Donnerstag 19. August 2021, 15:00

Ein Timeout legt die Zeit fest, wie lange gewartet wird, auf empfangende Daten.
Ja ich weiß, wie es aussieht, wenn er "zuschlägt". Den Tip mit dem Terminal habe ich ausprobiert und es hatte damit geklappt, also der SR830 hat mir sowohl seine ID, als auch die Werte für Ref ausgegeben.

Für das endgültige Programm benutze ich 2 SR800, um die Reflektivität von z.b. Spiegeln zu ermitteln.
__deets__
User
Beiträge: 14545
Registriert: Mittwoch 14. Oktober 2015, 14:29

Und wie sieht das aus? Denn das erklaert doch, warum du Leerstrings bekommst. Warum hast du den Timeout eingebaut? Die Frage hast du nicht beantwortet.

Dann solltest du dein Programm neu aufbauen. Man schreibt sich Funktionen oder Klassen, die mit *einem* Geraet umgehen. Und wenn man dann mehrere braucht, dann benutzt man die eben zweimal, jeweils mit anderen COM-Ports. Denn das vereinfacht den Code massiv, und verhindert dieses verschachteln, das keiner mehr durchblickt.

Zu guter Letzt wuerde ich auch auf readline erstmal verzichten, und stattdessen die Daten einfach mal so lange einlesen, bis ein "\n" kommt. Denn es koennte sein, dass der unter Windows fuer readline ein \r\n will. Nur das du das nicht bekommst.
rogerb
User
Beiträge: 878
Registriert: Dienstag 26. November 2019, 23:24

Ich habe keine Praxiserfahrung mit pySerial zwei Punkte sind mir aber aufgefallen

Code: Alles auswählen

def reflectivity(COMport1, COMport2, detector_const, readouts):
    ser = serial.Serial(COMport1, 9600, parity=serial.PARITY_NONE, stopbits=serial.STOPBITS_ONE, bytesize=serial.EIGHTBITS, timeout=0.05)
    ser1 = serial.Serial(COMport2, 9600, parity=serial.PARITY_NONE, stopbits=serial.STOPBITS_ONE, bytesize=serial.EIGHTBITS, timeout=0.05)
    summe = 0
    summe1 = 0
    ser.write("OUTX0\n".encode("utf-8"))
    ser1.write("OUTX0\n".encode("utf-8"))
    for i in range(0, readouts):
        ser.write("OUTP?3\n".encode("utf-8"))
        # ser.flush()  <-------- u.U. nötig um zu warten bis alles gesendet wurde
        response = float(ser.readline())
        summe += response
        print("first try res:", response)

        ser1.write("OUTP?3\n".encode("utf-8"))
        # ser.flush()  <-------- u.U. nötig um zu warten bis alles gesendet wurde
        response1 = float(ser1.readline())
        summe1 += response1
        print("first try res1:", response1)

        S1 = summe / readouts
        S2 = summe1 / readouts
        divide = S2 / S1
        reflectivity = (1 - divide * detector_const) / (1 + divide * detector_const)
        # ^^^^^ das ist der Funktionsname - keine gute Idee, hat aber nichts mit dem Problem zu tun
        ser.close()
        ser1.close()

    return reflectivity
__deets__
User
Beiträge: 14545
Registriert: Mittwoch 14. Oktober 2015, 14:29

Da sind noch deutlich mehr Fehler drin. Wenn das wirklich so der Code ist, dann ist natuerlich das ser.close() auf der gleichen Ebene wie der Schleifencode ein Problem. Ich wuerde das wenn so machen:

Code: Alles auswählen

def read_value(ser):
    ser.write(b"OUTX0\nOUTP?3\n")
    return float(ser.readline())


def reflectivity(amplifier_a, amplifier_b, detector_const, readouts):
    average_a = sum([read_value(amplifier_a) for _ in range(readouts)]) / readouts
    average_b = sum([read_value(amplifier_b) for _ in range(readouts)]) / readouts
    h = average_b / average_a
    return (1 - h * detector_const) / (1 + h * detector_const)
    

def main():
    amplifier_a = serial.Serial(COMport1, 9600) # das andere sollte alles der default sein
    amplifier_b = serial.Serial(COMport2, 9600) # das andere sollte alles der default sein
    print(reflectivity(amplifier_a, amplifier_b, whatever, 10))
Es gibt auch keinen Grund, andauernd die Ports wieder zu schliessen. Und wenn das wirklich so falsch eingerueckt ist beim TE, dann ist das natuerlich auch der Grund fuer Fehler beim lesen nach dem ersten mal.

Ggf. muss dbas OUTX0 nur einmal am Anfang in der main gemacht werden, dazu kenne ich das Protokoll jetzt nicht gut genug.
rogerb
User
Beiträge: 878
Registriert: Dienstag 26. November 2019, 23:24

Code: Alles auswählen

Wenn das wirklich so der Code ist, dann ist natuerlich das ser.close() auf der gleichen Ebene wie der Schleifencode ein Problem
Da der ursprüngliche Code nicht formatiert war, kann das auch meine Fehlinterpretation gewesen sein.
__deets__
User
Beiträge: 14545
Registriert: Mittwoch 14. Oktober 2015, 14:29

rogerb hat geschrieben: Freitag 27. August 2021, 15:59 Da der ursprüngliche Code nicht formatiert war, kann das auch meine Fehlinterpretation gewesen sein.
Ich habe mir den mal mit meinen "Privilegien" im Editor angeschaut, da ist es tatsaechlich richtig(er). Das ist natuerlich fast schade, weil es dann ein einfach zu behebender Fehler waere.
Benutzeravatar
__blackjack__
User
Beiträge: 14066
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Privilegien braucht man dafür doch gar nicht, einfach auf „mit Zitat antworten“ klicken, dann kommt man auch als normaler Benutzer an den Quelltext des Beitrags mit den Einrückungen wie sie eingegeben wurden.
“Vir, intelligence has nothing to do with politics!” — Londo Mollari
Antworten