| optoMDC

Loading...
Searching...
No Matches
MR-E-3 Advanced Examples

Vector Pattern Unit Trigger

    from enum import IntEnum
    import optoMDC
    from optoMDC.tools.definitions import OperationMode, UnitType

    class ExternalTrigger(IntEnum):
        DISABLED = 0
        RISING_FALLING_EDGE = 1
        RISING_EDGE = 2

    # connect to the mirror (COM port detected automatically)
    mre3 = optoMDC.connectmre3()

    x_points = 4
    y_points = 4

    matrix_vector = []

    for i in range(0, x_points):
        for j in range(0, y_points):
            matrix_vector.append([i, j])

    print("Matrix vector is: " + str(matrix_vector))

    XY_factor = 40  # division factor to represent the values in XY coordinates
    offset_x = -0.2
    offset_y = -0.2

    matrix_vector = [[x / XY_factor + offset_x, y / XY_factor + offset_y] for [x, y] in matrix_vector]

    matrix_vector.insert(0, matrix_vector[0])  # insert first point twice for constant dwell time for every point

    print("Matrix vector transposed to XY is: " + str(matrix_vector))

    vector_to_vpu_memory = []

    for i in range(2):
        for j in range(0, x_points * y_points + 1):
            vector_to_vpu_memory.append((matrix_vector[j][i]))

    print("Vector sent to VPU memory: " + str(vector_to_vpu_memory))
    # load to memory

    mre3.VectorPatternMemory.SetPattern(index=0, vector=vector_to_vpu_memory)

    # Set control mode to close loop in XY coordinates on both axes
    mre3.MiscFeatures.SetOperationMode(OperationMode.XY_CONTROL.value)

    # set calibrated closed loop PID values for both channels
    for channel in [mre3.Channel_0, mre3.Channel_1]:
        for pid in [channel.PID]:
            pid.set_register("kp", 10)
            pid.set_register("ki", 50)
            pid.set_register("kd", 0.028)

    vpu0 = mre3.Channel_0.VectorPatternUnit  # setting x-axis to vector pattern unit
    vpu1 = mre3.Channel_1.VectorPatternUnit  # setting y-axis to vector pattern unit

    vpu0.SetUnit(UnitType.XY)  # calibrated close loop for x-axis
    vpu1.SetUnit(UnitType.XY)  # calibrated close loop for y-axis

    X_Freq_sample_speed = 16  # sampling rate of vector pattern unit X axis
    Y_Freq_sample_speed = 16  # sampling rate of vector pattern unit Y axis

    # VPU setting
    vpu0.SetFreqSampleSpeed(X_Freq_sample_speed)
    vpu1.SetFreqSampleSpeed(Y_Freq_sample_speed)

    vpu0.SetCycles(1)
    vpu1.SetCycles(1)

    vpu0.SetAsInput()
    vpu1.SetAsInput()

    vpu0.SetStart(0)  # first index
    vpu0.SetEnd(x_points * y_points + 1)  # last index

    vpu1.SetStart(x_points * y_points + 1)  # first index
    vpu1.SetEnd(2 * x_points * y_points + 2)  # last index

    # trigger setting to rising edge and input
    vpu0.SetExternalTrigger(ExternalTrigger.RISING_EDGE.value)
    vpu1.SetExternalTrigger(ExternalTrigger.RISING_EDGE.value)
    vpu0.SetExtTriggerGPIO(True)
    vpu1.SetExtTriggerGPIO(True)

Check Step Response

    import optoMDC
    import numpy as np
    import time
    import matplotlib.pyplot as plt
    from optoMDC.tools.definitions import OperationMode

    # connect to the mirror (COM port detected automatically)
    mre3 = optoMDC.connectmre3()

    # Set control mode to close loop in XY coordinates on both axes
    mre3.MiscFeatures.SetOperationMode(OperationMode.XY_CONTROL.value)

    # set calibrated closed loop PID values for both channels
    for channel in [mre3.Channel_0, mre3.Channel_1]:
        for pid in [channel.PID]:
            pid.set_register("kp", 10)
            pid.set_register("ki", 50)
            pid.set_register("kd", 0.028)

    # Setup logger (See Firmware manual for register values)
    mre3.Logger.set_register('logged_register_0', 0xe802)  # current A: 0xe802
    mre3.Logger.set_register('logged_register_1', 0xe902)  # current B: 0xe902
    mre3.Logger.set_register('logged_register_2', 0x2300)  # OF A: 0x2300
    mre3.Logger.set_register('logged_register_3', 0x2301)  # OF B: 0x2301
    mre3.Logger.set_register('logged_register_4', 0x3b00)  # X: 0x3b00
    mre3.Logger.set_register('logged_register_5', 0x3b01)  # Y: 0x3b01

    logger_numDataPoints = 2000  # maximum is 5000
    logger_sampleRate = 10000  # maximum is 10000
    mre3.Logger.SetSamplingFrequency(logger_sampleRate)
    mre3.Channel_0.LinearOutput.SetCurrentLimit(1.1)  # Maximum is 1.136 A
    mre3.Channel_1.LinearOutput.SetCurrentLimit(1.1)  # Maximum is 1.136 A

    Xaxis_halfstep_dgr = 5  # used, the step response is measured in X axis
    Yaxis_halfstep_dgr = 0  # not used

    Xaxis_halfStep_xy = np.tan(Xaxis_halfstep_dgr * 2 * np.pi / 180) / np.tan(
        50 * np.pi / 180)  # conversion from mech. angle to x,y coordinate

    print("Halfstep value in XY coordinate: " + str(round(Xaxis_halfStep_xy, 3)))

    # Set control mode to close loop in XY coordinates on both axes
    mre3.MiscFeatures.SetOperationMode(OperationMode.XY_CONTROL.value)

    mre3.Channel_0.StaticInput.SetAsInput()
    mre3.Channel_1.StaticInput.SetAsInput()

    mre3.Channel_0.StaticInput.SetXY(0)
    mre3.Channel_1.StaticInput.SetXY(0)

    mre3.Channel_0.StaticInput.SetXY(-Xaxis_halfStep_xy)

    time.sleep(0.2)

    mre3.Logger.RunLogger()  # triggers data aquisition
    mre3.Channel_0.StaticInput.SetXY(Xaxis_halfStep_xy)  # change of setpoint

    time.sleep(logger_numDataPoints / logger_sampleRate + 0.1)
    mre3.Logger.StopLogger()  # stop logger after all samples are collected

    mre3.Channel_0.StaticInput.SetXY(0)

    # time will be linearly spaced at the given sampling rate
    t = np.linspace(0, logger_numDataPoints / logger_sampleRate, num=logger_numDataPoints, endpoint=False)  # in s

    # get data from MR-E-2 (takes a while to transmit over serial connection)
    cA = mre3.Logger.GetLog(0, 0, logger_numDataPoints)
    cB = mre3.Logger.GetLog(1, 0, logger_numDataPoints)
    ofA = mre3.Logger.GetLog(2, 0, logger_numDataPoints)
    ofB = mre3.Logger.GetLog(3, 0, logger_numDataPoints)
    x = mre3.Logger.GetLog(4, 0, logger_numDataPoints)
    y = mre3.Logger.GetLog(5, 0, logger_numDataPoints)

    fig, axs = plt.subplots(4, 1, figsize=(8, 8), sharex=True)

    # first subplot
    axs[0].plot(t, cA)
    axs[0].set_title('currA (A)', loc='left')
    axs[0].set_ylabel('A')

    # second
    axs[1].plot(t, cB)
    axs[1].set_title('currB (A)', loc='left')
    axs[1].set_ylabel('A')

    # third
    axs[2].plot(t, x)
    axs[2].set_title('X units', loc='left')
    axs[2].set_ylabel('X')

    # fourth
    axs[3].plot(t, y)
    axs[3].set_title('Y units', loc='left')
    axs[3].set_ylabel('Y')
    axs[3].set_xlabel('time (s)')

    # make all subplots nicer
    for ax in axs:
        ax.grid(True, alpha=0.3)

    fig.suptitle('MR-E-3 logger data', fontsize=14)
    fig.tight_layout(rect=[0, 0.03, 1, 0.95])  # leave space for main title

    plt.show()

    mre3.disconnect()

Setup Signal Generator

    import optoMDC
    import numpy as np
    import time
    import matplotlib.pyplot as plt
    from optoMDC.tools.definitions import OperationMode, UnitType, WaveformShape

    # connect to the mirror (COM port detected automatically)
    mre3 = optoMDC.connectmre3()

    # Set control mode to close loop in XY coordinates on both axes
    mre3.MiscFeatures.SetOperationMode(OperationMode.XY_CONTROL.value)

    # set calibrated closed loop PID values for both channels
    for channel in [mre3.Channel_0, mre3.Channel_1]:
        for pid in [channel.PID]:
            pid.set_register("kp", 10)
            pid.set_register("ki", 50)
            pid.set_register("kd", 0.028)

    # Setup logger (See Firmware manual for register values)
    mre3.Logger.set_register('logged_register_0', 0xe802)  # current A: 0xe802
    mre3.Logger.set_register('logged_register_1', 0xe902)  # current B: 0xe902
    mre3.Logger.set_register('logged_register_2', 0x2300)  # OF A: 0x2300
    mre3.Logger.set_register('logged_register_3', 0x2301)  # OF B: 0x2301
    mre3.Logger.set_register('logged_register_4', 0x3b00)  # X: 0x3b00
    mre3.Logger.set_register('logged_register_5', 0x3b01)  # Y: 0x3b01

    logger_numDataPoints = 5000  # maximum is 5000
    logger_sampleRate = 1000  # maximum is 10000
    mre3.Logger.SetSamplingFrequency(logger_sampleRate)

    mre3.Channel_0.LinearOutput.SetCurrentLimit(1.1)  # Maximum is 1.136 A
    mre3.Channel_1.LinearOutput.SetCurrentLimit(1.1)  # Maximum is 1.136 A

    # Signal generator waveform parameters
    Xaxis_amp_deg = 10.0
    Yaxis_amp_deg = 4.0
    Xaxis_offset_deg = 0.0
    Yaxis_offset_deg = 0.0
    Xaxis_freq = 3.0
    Yaxis_freq = 5.0

    Xaxis_amp_xy = np.tan(Xaxis_amp_deg * 2 * np.pi / 180) / np.tan(
        50 * np.pi / 180)  # conversion from mech. angle to x,y coordinate
    Yaxis_amp_xy = np.tan(Yaxis_amp_deg * 2 * np.pi / 180) / np.tan(
        50 * np.pi / 180)  # conversion from mech. angle to x,y coordinate
    Xaxis_offset_xy = np.tan(Xaxis_offset_deg * 2 * np.pi / 180) / np.tan(
        50 * np.pi / 180)  # conversion from mech. angle to x,y coordinate
    Yaxis_offset_xy = np.tan(Yaxis_offset_deg * 2 * np.pi / 180) / np.tan(
        50 * np.pi / 180)  # conversion from mech. angle to x,y coordinate

    print("X amplitude value in XY coordinate: " + str(round(Xaxis_amp_xy, 3)))
    print("Y amplitude value in XY coordinate: " + str(round(Yaxis_amp_xy, 3)))
    print("X offset value in XY coordinate: " + str(round(Xaxis_offset_xy, 3)))
    print("Y offset value in XY coordinate: " + str(round(Yaxis_offset_xy, 3)))

    # Signal generator settings
    sig_gen_0 = mre3.Channel_0.SignalGenerator
    sig_gen_1 = mre3.Channel_1.SignalGenerator

    sig_gen_0.SetAsInput()
    sig_gen_1.SetAsInput()

    sig_gen_0.SetUnit(UnitType.XY)
    sig_gen_1.SetUnit(UnitType.XY)

    sig_gen_0.SetShape(WaveformShape.TRIANGULAR)
    sig_gen_1.SetShape(WaveformShape.SINUSOIDAL)

    sig_gen_0.SetFrequency(float(Xaxis_freq))
    sig_gen_1.SetFrequency(float(Yaxis_freq))

    sig_gen_0.SetAmplitude(float(Xaxis_amp_xy))
    sig_gen_1.SetAmplitude(float(Yaxis_amp_xy))

    sig_gen_0.SetOffset(float(Xaxis_offset_xy))
    sig_gen_1.SetOffset(float(Yaxis_offset_xy))

    time.sleep(0.2)

    mre3.Logger.RunLogger()  # triggers data acquisition

    mre3.set_value([sig_gen_0.run, sig_gen_1.run], [1, 1])  # runs the signal generator

    time.sleep(logger_numDataPoints / logger_sampleRate + 0.1)
    mre3.Logger.StopLogger()  # stop logger after all samples are collected

    mre3.set_value([sig_gen_0.run, sig_gen_1.run], [0, 0])  # stops the signal generator

    # static input moves the mirror to 0 position
    mre3.Channel_0.StaticInput.SetAsInput()
    mre3.Channel_1.StaticInput.SetAsInput()

    mre3.Channel_0.StaticInput.SetXY(0)
    mre3.Channel_1.StaticInput.SetXY(0)

    # time will be linearly spaced at the given sampling rate
    t = np.linspace(0, logger_numDataPoints / logger_sampleRate, num=logger_numDataPoints, endpoint=False)  # in s

    # get data from MR-E-2 (takes a while to transmit over serial connection)
    cA = mre3.Logger.GetLog(0, 0, logger_numDataPoints)
    cB = mre3.Logger.GetLog(1, 0, logger_numDataPoints)
    ofA = mre3.Logger.GetLog(2, 0, logger_numDataPoints)
    ofB = mre3.Logger.GetLog(3, 0, logger_numDataPoints)
    x = mre3.Logger.GetLog(4, 0, logger_numDataPoints)
    y = mre3.Logger.GetLog(5, 0, logger_numDataPoints)

    fig, axs = plt.subplots(4, 1, figsize=(8, 8), sharex=True)

    # currA
    axs[0].plot(t, cA, linewidth=1.2)
    axs[0].set_title("currA (A)", loc="left")
    axs[0].set_ylabel("A")
    axs[0].grid(True, alpha=0.3)

    # currB
    axs[1].plot(t, cB, linewidth=1.2)
    axs[1].set_title("currB (A)", loc="left")
    axs[1].set_ylabel("A")
    axs[1].grid(True, alpha=0.3)

    # X units
    axs[2].plot(t, x, linewidth=1.2)
    axs[2].set_title("X units", loc="left")
    axs[2].set_ylabel("X")
    axs[2].grid(True, alpha=0.3)

    # Y units
    axs[3].plot(t, y, linewidth=1.2)
    axs[3].set_title("Y units", loc="left")
    axs[3].set_ylabel("Y")
    axs[3].set_xlabel("time (s)")
    axs[3].grid(True, alpha=0.3)

    # Hide x tick labels on upper plots (only bottom one shows time)
    for ax in axs[:-1]:
        ax.label_outer()

    fig.suptitle("MR-E-3 logger data (sine test)", fontsize=14)
    fig.tight_layout(rect=[0, 0.03, 1, 0.95])

    plt.show()

    mre3.disconnect()