コード例 #1
0
def step_response(outname,
                  AB2XY,
                  kp,
                  ki=0,
                  kd=0,
                  dx=10.,
                  dy=10.,
                  originalsetpoint=None):
    """Perform a single step of (dx,dy) microns and record the PID response to a file named outname."""
    if np.isscalar(kp):
        kp = [kp, kp]
    if np.isscalar(ki):
        ki = [ki, ki]
    if np.isscalar(kd):
        kd = [kd, kd]
    with closing(DT3100('169.254.3.100')) as sensorA, closing(
            DT3100('169.254.4.100')) as sensorB, closing(MPC385()) as actuator:
        sensors = [sensorA, sensorB]
        #setting up sensors
        for sensor in sensors:
            sensor.set_averaging_type(3)
            sensor.set_averaging_number(3)
        #remember original positions of the sensors and actuator
        if originalsetpoint is None:
            originalsetpoint = np.array(
                [sensor.readOne().m for sensor in sensors])
            originalsetpoint = np.matmul(AB2XY, originalsetpoint)
        x0, y0, z0 = actuator.update_current_position()[1:]
        #setting up PID
        pids = []
        for p, i, d, s in zip(kp, ki, kd, originalsetpoint):
            pid = PID(p, i, d)
            pid.setPoint = s
            pids.append(pid)
        with open(outname, "wb") as fout:
            m = MoverPID_XY(sensors, actuator, AB2XY, pids, outputFile=fout)
            m.start()
            time.sleep(1)
            pids[0].setPoint += dx
            pids[1].setPoint += dy
            time.sleep(20)
            #stop PID
            m.go = False
            m.join()
        #move the actuator back to its original position
        actuator.move_to(x0, y0, z0)
    #read back the data and print some metrics
    meas = np.fromfile(outname)
    ts, mx, my, ox, oy = meas.reshape((meas.shape[0] // 5, 5)).T
    measures = np.column_stack([mx, my])
    rms = np.sqrt(np.sum((originalsetpoint + [dx, dy] - measures)**2, -1))
    if not np.any(rms < actuator.step2um(1)):
        print("does not converge")
    else:
        print("cverge\teRMS\t%overshoot")
        print('%g\t%g\t%g' %
              (ts[np.where(rms < actuator.step2um(1))[0][0] - 1],
               np.sqrt(np.mean(rms[np.where(ts > 2)[0][0]:]**2)),
               (100 *
                (measures - originalsetpoint - [dx, dy]) / [dx, dy]).max()))
コード例 #2
0
 def __init__(self,
              sensors,
              actuator,
              AB2XY,
              pids=[PID(), PID()],
              outputFile=False):
     """AB2XY is the transfer matrix between sensor coordinates and actuator coordinates."""
     Thread.__init__(self)
     self.sensors = sensors
     self.actuator = actuator
     self.AB2XY = AB2XY
     self.pids = pids
     if outputFile:
         self.recorder = Recorder(outputFile)
     else:
         self.recorder = False
     self.go = True
コード例 #3
0
 def __init__(self, sensor, actuator, pid=PID(), outputFile=False):
     Thread.__init__(self)
     self.sensor = sensor
     self.actuator = actuator
     self.pid = pid
     if outputFile:
         self.recorder = Recorder(outputFile)
     else:
         self.recorder = False
     self.go = True
コード例 #4
0
 def __init__(self,
              sensors,
              actuator,
              AB2XY,
              pids=[PID(), PID()],
              outputFile=False,
              delay=0):
     """AB2XY is the transfer matrix between sensor coordinates and actuator coordinates."""
     Thread.__init__(self)
     self.sensors = sensors
     self.actuator = actuator
     self.AB2XY = AB2XY
     assert len(pids) == 2, "Two PIDs are needed"
     self.pids = pids
     self.delay = delay
     if outputFile:
         self.recorder = Recorder(outputFile)
     else:
         self.recorder = False
     self.go = True
コード例 #5
0
def step_response_Y(outname, kp, ki=0, kd=0, dy=10., originalsetpoint=None):
    """Perform a single depthwise step of dy microns and record the PID response to a file named outname."""
    with closing(DT3100('169.254.3.100')) as sensor, closing(
            MPC385()) as actuator:
        #setting up sensor
        sensor.set_averaging_type(3)
        sensor.set_averaging_number(3)
        #remember original positions of the sensor and actuator
        if originalsetpoint is None:
            originalsetpoint = sensor.readOne().m
        x0, y0, z0 = actuator.update_current_position()[1:]
        #setting up PID
        pid = PID(kp, ki, kd)
        pid.setPoint = originalsetpoint
        with open(outname, "wb") as fout:
            m = MoverPID_Y(sensor, actuator, pid, outputFile=fout)
            m.start()
            time.sleep(1)
            pid.setPoint += dy
            time.sleep(20)
            #stop PID
            m.go = False
            m.join()
        #move the actuator back to its original position
        actuator.move_to(x0, y0, z0)
    #read back the data and print some metrics
    meas = np.fromfile(outname)
    ts, measured, out = meas.reshape((meas.shape[0] // 3, 3)).T
    if not np.any(
            np.abs(measured - originalsetpoint - dy) < actuator.step2um(1)):
        print("does not converge")
    else:
        print("cverge\teRMS\t%overshoot")
        print('%g\t%g\t%g' % (ts[np.where(
            np.abs(measured - originalsetpoint -
                   dy) < actuator.step2um(1))[0][0] - 1],
                              np.sqrt(
                                  np.mean((measured[np.where(ts > 2)[0][0]:] -
                                           originalsetpoint - dy)**2)), 100 *
                              (measured.max() - originalsetpoint - dy) / dy))
コード例 #6
0
def timedep_armX_positionY(ab2xy,
                           outname,
                           functions,
                           duration=None,
                           kp=0.9,
                           ki=0.0,
                           kd=0.0,
                           moveback=False,
                           state0=None):
    """Moving the absolute position of the head in depth (Y) and the arm position in Y following two
    time-dependent functions around state0.
    Need ab2xy calibration matrix.
    Duration is in seconds. If None specified, continues until stopped."""
    if not hasattr(kp, "__len__"):
        kps = [kp, kp]
    else:
        kps = kp
    if not hasattr(ki, "__len__"):
        kis = [ki, ki]
    else:
        kis = ki
    if not hasattr(kd, "__len__"):
        kds = [kd, kd]
    else:
        kds = kd
    assert len(kps) == 2
    assert len(kis) == 2
    assert len(kds) == 2
    assert len(functions) == 2
    with ExitStack() as stack:
        sensors = [
            stack.enter_context(closing(DT3100(f'169.254.{3+i}.100')))
            for i in range(3)
        ]
        actuator = stack.enter_context(closing(MPC385()))
        #setting up sensors
        for sensor in sensors:
            sensor.set_averaging_type(3)
            sensor.set_averaging_number(3)
        if state0 is None:
            #remember original positions of the sensors and actuator
            state0 = State().read(sensors, actuator, ab2xy)
        #setting up PID, in microns
        pids = []
        initialposition = [state0.arm_to_ground[0], state0.head_to_ground[1]]
        for s, kp, ki, kd in zip(initialposition, kps, kis, kds):
            pid = PID(kp, ki, kd)
            pid.setPoint = s
            pids.append(pid)
        try:
            with open(outname, "wb") as fout:
                m = moverPID.armX_position_Y_3sensors(sensors,
                                                      actuator,
                                                      ab2xy,
                                                      pids,
                                                      outputFile=fout)
                t0 = time.time()
                m.start()
                try:
                    t = time.time() - t0
                    while (duration is None) or (t < duration):
                        t = time.time() - t0
                        for pid, p0, function in zip(pids, initialposition,
                                                     functions):
                            pid.setPoint = p0 + function(t)
                        time.sleep(0.001)  #no use to update above 1kHz

                except KeyboardInterrupt:
                    pass
                finally:
                    #stop PID thread
                    m.go = False
                    m.join()
        finally:
            if moveback:
                #move the actuator back to its original position
                actuator.move_to(
                    *actuator.um2integer_step(state0.actuator_pos))
コード例 #7
0
def move_to_constant_positions(ab2xy,
                               outnames,
                               dxs,
                               dys,
                               durations,
                               kp=0.9,
                               ki=0.0,
                               kd=0.0,
                               moveback=False,
                               state0=None):
    """Moving the absolute position of the head by dy (depth) and dx (width)
    and stay at that position using PID feedback.
    Need ab2xy calibration matrix.
    Duration is in seconds. If None specified, continues until stopped."""
    if not hasattr(kp, "__len__"):
        kps = [kp, kp]
    else:
        kps = kp
    if not hasattr(ki, "__len__"):
        kis = [ki, ki]
    else:
        kis = ki
    if not hasattr(kd, "__len__"):
        kds = [kd, kd]
    else:
        kds = kd
    assert len(kps) == 2
    assert len(kis) == 2
    assert len(kds) == 2
    with ExitStack() as stack:
        sensors = [
            stack.enter_context(closing(DT3100(f'169.254.{3+i}.100')))
            for i in range(3)
        ]
        actuator = stack.enter_context(closing(MPC385()))
        #setting up sensors
        for sensor in sensors:
            sensor.set_averaging_type(3)
            sensor.set_averaging_number(3)
        if state0 is None:
            #remember original positions of the sensors and actuator
            state0 = State().read(sensors, actuator, ab2xy)
        #setting up PID, in microns
        pids = []
        initialposition = state0.head_to_ground
        for s, kp, ki, kd in zip(initialposition, kps, kis, kds):
            pid = PID(kp, ki, kd)
            pid.setPoint = s
            pids.append(pid)
        try:
            for outname, dx, dy, duration in zip(outnames, dxs, dys,
                                                 durations):
                for s, pid in zip(initialposition + np.array([dx, dy]), pids):
                    pid.setPoint = s
                with open(outname, "wb") as fout:
                    m = moverPID.constant_position_XY_3sensors(sensors,
                                                               actuator,
                                                               ab2xy,
                                                               pids,
                                                               outputFile=fout)
                    t0 = time.time()
                    m.start()
                    try:
                        while (duration is None) or (time.time() <
                                                     t0 + duration):
                            time.sleep(1)
                    except KeyboardInterrupt:
                        pass
                    finally:
                        #stop PID thread
                        m.go = False
                        m.join()
        finally:
            if moveback:
                #move the actuator back to its original position
                actuator.move_to(
                    *actuator.um2integer_step(state0.actuator_pos))
コード例 #8
0
def add_constant_deflectionX_move_to_constant_positiony(
        ab2xy,
        outnames,
        dXs,
        dys,
        durations,
        kp=0.9,
        ki=0.0,
        kd=0.0,
        moveback=False,
        maxYdispl=None,
        state0=None):
    """Considering initial deflection is (0,0),
    successively add dX to the deflection and dy to absolute position
    and stay at this constant X deflection and constant y position during duration.
    Stay at this deflection and positon using using PID feedback (constant stress and constant strain respectively).
    Iterate on next dX, duration.
    Need ab2xy calibration matrix.
    Duration is in seconds. If None specified, continues until stopped."""
    if not hasattr(kp, "__len__"):
        kps = [kp, kp]
    else:
        kps = kp
    if not hasattr(ki, "__len__"):
        kis = [ki, ki]
    else:
        kis = ki
    if not hasattr(kd, "__len__"):
        kds = [kd, kd]
    else:
        kds = kd

    #remember original positions of the sensors and actuator
    with ExitStack() as stack:
        sensors = [
            stack.enter_context(closing(DT3100(f'169.254.{3+i}.100')))
            for i in range(3)
        ]
        actuator = stack.enter_context(closing(MPC385()))
        #setting up sensors
        for sensor in sensors:
            sensor.set_averaging_type(3)
            sensor.set_averaging_number(3)
        if state0 is None:
            #remember original positions of the sensors and actuator
            state0 = State().read(sensors, actuator, ab2xy)
        #setting up PID
        pids = []
        for s, kp, ki, kd in zip(
            [state0.deflection[0], state0.head_to_ground[1]], kps, kis, kds):
            pid = PID(kp, ki, kd)
            pid.setPoint = s
            pids.append(pid)
        try:
            for outname, dX, dy, duration in zip(outnames, dXs, dys,
                                                 durations):

                ip = [state0.deflection[0] + dX, state0.head_to_ground[1] + dy]
                for s, pid in zip(ip, pids):
                    pid.setPoint = s
                with open(outname, "wb") as fout:
                    m = moverPID.constant_deflectionX_positionY_3sensors(
                        sensors, actuator, ab2xy, pids, outputFile=fout)
                    t0 = time.time()
                    m.start()
                    try:
                        while (duration is None) or (time.time() <
                                                     t0 + duration):
                            time.sleep(1)  #is it too long ?
                            x, y, z = m.xyz
                            y0 = actuator.um2integer_step(
                                state0.actuator_pos[1])
                            if maxYdispl is not None and abs(
                                    y - y0) > actuator.um2step(maxYdispl):
                                break
                    except KeyboardInterrupt:
                        pass
                    finally:
                        #stop PID thread
                        m.go = False
                        m.join()
        finally:
            if moveback:
                #move the actuator back to its original position
                actuator.move_to(
                    *actuator.um2integer_step(state0.actuator_pos))
コード例 #9
0
def add_constant_deflection(ab2xy,
                            outnames,
                            dXs,
                            dYs,
                            durations,
                            kp=0.9,
                            ki=0.0,
                            kd=0.0,
                            moveback=False,
                            delay=0,
                            state0=None):
    """Considering initial deflection is 0 in x
    and successively add dX to the deflection during duration
    and stay at this deflection using PID feedback (constant stress).
    Iterate on next dX, dY, duration.
    Need ab2xy calibration matrix.
    Duration is in seconds. If None specified, continues until stopped."""

    #remember original positions of the sensors and actuator
    if not hasattr(kp, "__len__"):
        kps = [kp, kp]
    else:
        kps = kp
    if not hasattr(ki, "__len__"):
        kis = [ki, ki]
    else:
        kis = ki
    if not hasattr(kd, "__len__"):
        kds = [kd, kd]
    else:
        kds = kd
    assert len(kps) == 2
    assert len(kis) == 2
    assert len(kds) == 2
    with ExitStack() as stack:
        sensors = [
            stack.enter_context(closing(DT3100(f'169.254.{3+i}.100')))
            for i in range(3)
        ]
        actuator = stack.enter_context(closing(MPC385()))
        #setting up sensors
        for sensor in sensors:
            sensor.set_averaging_type(3)
            sensor.set_averaging_number(3)
        if state0 is None:
            #remember original positions of the sensors and actuator
            state0 = State().read(sensors, actuator, ab2xy)
        #setting up PID, in microns
        pids = []
        initialposition = state0.deflection
        for s, kp, ki, kd in zip(initialposition, kps, kis, kds):
            pid = PID(kp, ki, kd)
            pid.setPoint = s
            pids.append(pid)
        try:
            for dX, dY, duration, outname in zip(dXs, dYs, durations,
                                                 outnames):
                for s, pid in zip(state0.deflection + np.array([dX, dY]),
                                  pids):
                    pid.setPoint = s
                with open(outname, "wb") as fout:
                    m = moverPID.constant_deflection_XY_3sensors(
                        sensors,
                        actuator,
                        ab2xy,
                        pids,
                        outputFile=fout,
                        delay=delay,
                    )
                    t0 = time.time()
                    m.start()
                    try:
                        while (duration is None) or (time.time() <
                                                     t0 + duration):
                            time.sleep(1)
                    except KeyboardInterrupt:
                        pass
                    finally:
                        #stop PID
                        m.go = False
                        m.join()
        finally:
            if moveback:
                #move the actuator back to its original position
                actuator.move_to(
                    *actuator.um2integer_step(state0.actuator_pos))