예제 #1
0
    def execute(self, userdata):
        rospy.loginfo("EL State ResetLEDPanels()")
        self.timePrev = rospy.Time.now()
        self.experimentparamsChoices = copy.deepcopy(userdata.experimentparamsChoicesIn)
        #self.paramsIn = 



        rv = 'disabled'
        if (userdata.experimentparamsChoicesIn.pre.ledpanels.enabled):
            rv = 'success'
            msgPanelsCommand = MsgPanelsCommand(command='stop')
            self.pubLEDPanelsCommand.publish (msgPanelsCommand)


            # Choose one of the choices.
            experimentparams = ExperimentLib.Chooser().GetChoice(userdata.experimentparamsChoicesIn)
            paramsIn = experimentparams.pre 
            
            
            # Publish the LED commands.
            msgPanelsCommand = MsgPanelsCommand(command='set_pattern_id', 
                                                arg1=paramsIn.ledpanels.idPattern)
            self.pubLEDPanelsCommand.publish (msgPanelsCommand)

            msgPanelsCommand = MsgPanelsCommand(command='set_position', 
                                                arg1=paramsIn.ledpanels.origin.x, 
                                                arg2=paramsIn.ledpanels.origin.y)  # Set (x,y) position for the experiment.
            self.pubLEDPanelsCommand.publish (msgPanelsCommand)
        else:
            msgPanelsCommand = MsgPanelsCommand(command='all_off')
            self.pubLEDPanelsCommand.publish (msgPanelsCommand)
            

        return rv
예제 #2
0
    def StartExperiment_callback(self, userdata):
        # Set the LED pattern to the origin.
        msgPanelsCommand = MsgPanelsCommand(command='stop')
        self.pubLEDPanels.publish (msgPanelsCommand)

        msgPanelsCommand = MsgPanelsCommand(command='set_pattern_id', arg1=1) # Assumes preprogrammed to the three-section pattern from Reiser paper. 
        self.pubLEDPanels.publish (msgPanelsCommand)

        msgPanelsCommand = MsgPanelsCommand(command='set_position', arg1=0, arg2=0)
        self.pubLEDPanels.publish (msgPanelsCommand)
        return 'success'
예제 #3
0
 def run(self):
     rospy.spin()
     self.pubPanelsCommand.publish(
         MsgPanelsCommand(command='all_off',
                          arg1=0,
                          arg2=0,
                          arg3=0,
                          arg4=0,
                          arg5=0,
                          arg6=0))
예제 #4
0
    def EndTrial_callback(self, userdata):
        
        # Create a rotation matrix R for an angle of +90 or -90, chosen at random.
        plusorminusone = (np.random.random()>=0.5) * 2 - 1       # -1 means +90 (CCW), +1 means -90 (CW).
        R = np.array([[0,plusorminusone],[-plusorminusone,0]])
        
        
        # Rotate the pattern on the LED panels.
        self.xPanelPattern += plusorminusone * 48 # 48 = 1/4 of the pixel width of the 24 panels.  192 pixels all the way around.  24 panels * 8 pixels per panel = 192.
        self.xPanelPattern %= 192
        self.yPanelPattern = 0
        msgPanelsCommand = MsgPanelsCommand(command='set_position', arg1=self.xPanelPattern, arg2=self.yPanelPattern)
        self.pubLEDPanels.publish (msgPanelsCommand)
         
        
        # Rotate the points in the statefilter strings by R.  (Convert string to dict, rotate, then convert dict back to string).
        statefilterHi_list = []
        statefilterLo_list = []
        for iFilter in range(len(userdata.experimentparamsIn.lasergalvos.statefilterLo_list)):
            # Convert strings to dicts.
            statefilterHi_dict = eval(userdata.experimentparamsIn.lasergalvos.statefilterHi_list[iFilter])
            statefilterLo_dict = eval(userdata.experimentparamsIn.lasergalvos.statefilterLo_list[iFilter])

            # Rotate
            if 'pose' in statefilterLo_dict:
                if 'position' in statefilterLo_dict['pose']:
                    x = statefilterHi_dict['pose']['position']['x']
                    y = statefilterHi_dict['pose']['position']['y']
                    pt = np.array([x,y])
                    [xRotA,yRotA] = np.dot(R,pt)

                    x = statefilterLo_dict['pose']['position']['x']
                    y = statefilterLo_dict['pose']['position']['y']
                    pt = np.array([x,y])
                    [xRotB,yRotB] = np.dot(R,pt)

                    # Rotated hi/lo are now not necessarily in the same order.
                    statefilterHi_dict['pose']['position']['x'] = max(xRotA,xRotB)
                    statefilterHi_dict['pose']['position']['y'] = max(yRotA,yRotB)
                    statefilterLo_dict['pose']['position']['x'] = min(xRotA,xRotB)
                    statefilterLo_dict['pose']['position']['y'] = min(yRotA,yRotB)

            statefilterLo_list.append(str(statefilterLo_dict))
            statefilterHi_list.append(str(statefilterHi_dict))


        # Save the results into the output.            
        experimentparamsOut = userdata.experimentparamsIn
        experimentparamsOut.lasergalvos.statefilterLo_list = statefilterLo_list
        experimentparamsOut.lasergalvos.statefilterHi_list = statefilterHi_list
        userdata.experimentparamsOut = experimentparamsOut
        
        return 'success'
예제 #5
0
    def create_msgpanels_vel(self, flystate):
        leftMajor = flystate.left.angles[0] if (
            0 < len(flystate.left.angles)) else 0.0
        leftMinor = flystate.left.angles[1] if (
            1 < len(flystate.left.angles)) else 0.0
        rightMajor = flystate.right.angles[0] if (
            0 < len(flystate.right.angles)) else 0.0
        rightMinor = flystate.right.angles[1] if (
            1 < len(flystate.right.angles)) else 0.0

        angleHead = flystate.head.angles[0] if (
            0 < len(flystate.head.angles)) else 0.0
        radiusHead = flystate.head.radii[0] if (
            0 < len(flystate.head.radii)) else 0.0
        angleAbdomen = flystate.abdomen.angles[0] if (
            0 < len(flystate.abdomen.angles)) else 0.0
        radiusAbdomen = flystate.abdomen.radii[0] if (
            0 < len(flystate.abdomen.radii)) else 0.0

        state = np.array([
            1.0, leftMajor, leftMinor, rightMajor, rightMinor, angleHead,
            radiusHead, angleAbdomen, radiusAbdomen, flystate.aux.intensity
        ],
                         dtype=np.float32)

        vel = np.dot(self.a, state)

        # gain, bias are in frames per sec, times ten, i.e. 10=1.0, 127=12.7
        gain_x = (int(vel[0]) + 128) % 256 - 128
        bias_x = 0
        gain_y = (int(vel[1]) +
                  128) % 256 - 128  # As if y were on a sphere, not a cylinder.
        bias_y = 0

        msgVel = MsgPanelsCommand(command='send_gain_bias',
                                  arg1=gain_x,
                                  arg2=bias_x,
                                  arg3=gain_y,
                                  arg4=bias_y,
                                  arg5=0,
                                  arg6=0)

        return msgVel
예제 #6
0
    def create_msgpanels_pos(self, flystate):
        leftMajor = flystate.left.angles[0] if (
            0 < len(flystate.left.angles)) else 0.0
        leftMinor = flystate.left.angles[1] if (
            1 < len(flystate.left.angles)) else 0.0
        rightMajor = flystate.right.angles[0] if (
            0 < len(flystate.right.angles)) else 0.0
        rightMinor = flystate.right.angles[1] if (
            1 < len(flystate.right.angles)) else 0.0

        angleHead = flystate.head.angles[0] if (
            0 < len(flystate.head.angles)) else 0.0
        radiusHead = flystate.head.radii[0] if (
            0 < len(flystate.head.radii)) else 0.0
        angleAbdomen = flystate.abdomen.angles[0] if (
            0 < len(flystate.abdomen.angles)) else 0.0
        radiusAbdomen = flystate.abdomen.radii[0] if (
            0 < len(flystate.abdomen.radii)) else 0.0

        state = np.array([
            1.0, leftMajor, leftMinor, rightMajor, rightMinor, angleHead,
            radiusHead, angleAbdomen, radiusAbdomen, flystate.aux.intensity
        ],
                         dtype=np.float32)

        pos = np.dot(self.a, state)

        # index is in frames.
        index_x = int(pos[0])
        index_y = int(pos[1])

        msgPos = MsgPanelsCommand(command='set_position',
                                  arg1=index_x,
                                  arg2=index_y,
                                  arg3=0,
                                  arg4=0,
                                  arg5=0,
                                  arg6=0)

        return msgPos
예제 #7
0
    def command_callback(self, command):
        self.command = command.data

        if (self.command == 'exit'):
            self.pubPanelsCommand.publish(
                MsgPanelsCommand(command='stop',
                                 arg1=0,
                                 arg2=0,
                                 arg3=0,
                                 arg4=0,
                                 arg5=0,
                                 arg6=0))
            self.bRunning = False
            rospy.signal_shutdown('User requested exit.')

        if (self.command == 'stop'):
            self.pubPanelsCommand.publish(
                MsgPanelsCommand(command='stop',
                                 arg1=0,
                                 arg2=0,
                                 arg3=0,
                                 arg4=0,
                                 arg5=0,
                                 arg6=0))
            self.pubPanelsCommand.publish(
                MsgPanelsCommand(command='all_off',
                                 arg1=0,
                                 arg2=0,
                                 arg3=0,
                                 arg4=0,
                                 arg5=0,
                                 arg6=0))
            self.bRunning = False

        if (self.command == 'start'):
            self.pubPanelsCommand.publish(
                MsgPanelsCommand(command='set_pattern_id',
                                 arg1=self.params['pattern_id'],
                                 arg2=0,
                                 arg3=0,
                                 arg4=0,
                                 arg5=0,
                                 arg6=0))
            self.pubPanelsCommand.publish(
                MsgPanelsCommand(command='start',
                                 arg1=0,
                                 arg2=0,
                                 arg3=0,
                                 arg4=0,
                                 arg5=0,
                                 arg6=0))
            self.bRunning = True

        if (self.command == 'help'):
            rospy.logwarn(
                'The %s/command topic accepts the following string commands:' %
                self.nodename.rstrip('/'))
            rospy.logwarn('  help                 This message.')
            rospy.logwarn('  stop                 Stop the ledpanels.')
            rospy.logwarn('  start                Start the ledpanels.')
            rospy.logwarn('  exit                 Exit the program.')
            rospy.logwarn('')
            rospy.logwarn(
                'You can send the above commands at the shell prompt via:')
            rospy.logwarn(
                'rostopic pub -1 %s/command std_msgs/String commandtext' %
                self.nodename.rstrip('/'))
            rospy.logwarn('')
            rospy.logwarn('Parameters are settable as launch-time parameters.')
            rospy.logwarn('')
예제 #8
0
    def __init__(self):
        self.bInitialized = False
        self.bRunning = False

        # initialize
        self.name = 'Flystate2ledpanels'
        rospy.init_node(self.name, anonymous=True)
        self.nodename = rospy.get_name()
        self.namespace = rospy.get_namespace()

        # Load the parameters.
        self.params = rospy.get_param('%s' % self.nodename.rstrip('/'), {})
        self.defaults = {'method': 'voltage', # 'voltage' or 'usb';        How we communicate with the panel controller.
                         'pattern_id': 1,
                         'mode': 'velocity',  # 'velocity' or 'position';  Fly is controlling vel or pos.
                         'axis': 'x',         # 'x' or 'y';               The axis on which the frames move.
                         'coeff_voltage':{
                             'adc0':1,  # When using voltage method, coefficients adc0-3 and funcx,y determine how the panels controller interprets its input voltage(s).
                             'adc1':0,  # e.g. xvel = adc0*bnc0 + adc1*bnc1 + adc2*bnc2 + adc3*bnc3 + funcx*f(x) + funcy*f(y); valid on [-128,+127], and 10 corresponds to 1.0.
                             'adc2':0,
                             'adc3':0,
                             'funcx':0,
                             'funcy':0,
                             },
                         'coeff_usb':{  # When using usb method, coefficients x0,xl1,xl2, ... ,yaa,yar,yxi determine the pos or vel command sent to the controller over USB.
                             'x0': 0.0,
                             'xl1':1.0,
                             'xl2':0.0,
                             'xr1':-1.0,
                             'xr2':0.0,
                             'xha':0.0,
                             'xhr':0.0,
                             'xaa':0.0,
                             'xar':0.0,
                             'xxi':0.0,
                             'y0': 0.0,
                             'yl1':0.0,
                             'yl2':0.0,
                             'yr1':0.0,
                             'yr2':0.0,
                             'yha':0.0,
                             'yhr':0.0,
                             'yaa':0.0,
                             'yar':0.0,
                             'yxi':0.0,
                             }
                         }
        SetDict().set_dict_with_preserve(self.params, self.defaults)
        self.update_coefficients_from_params()
        rospy.set_param('%s' % self.nodename.rstrip('/'), self.params)

        self.msgpanels = MsgPanelsCommand(command='all_off',
                                          arg1=0,
                                          arg2=0,
                                          arg3=0,
                                          arg4=0,
                                          arg5=0,
                                          arg6=0)

        # Publishers.
        self.pubPanelsCommand = rospy.Publisher('/ledpanels/command',
                                                MsgPanelsCommand)

        # Subscriptions.
        self.subFlystate = rospy.Subscriber('%s/flystate' %
                                            self.namespace.rstrip('/'),
                                            MsgFlystate,
                                            self.flystate_callback,
                                            queue_size=1000)
        self.subCommand = rospy.Subscriber('%s/command' %
                                           self.nodename.rstrip('/'),
                                           String,
                                           self.command_callback,
                                           queue_size=1000)
        rospy.sleep(1)  # Time to connect publishers & subscribers.

        self.pubPanelsCommand.publish(
            MsgPanelsCommand(command='set_posfunc_id',
                             arg1=1,
                             arg2=0,
                             arg3=0,
                             arg4=0,
                             arg5=0,
                             arg6=0))  # Set default function ch1.
        self.pubPanelsCommand.publish(
            MsgPanelsCommand(command='set_posfunc_id',
                             arg1=2,
                             arg2=0,
                             arg3=0,
                             arg4=0,
                             arg5=0,
                             arg6=0))  # Set default function ch2.
        self.pubPanelsCommand.publish(
            MsgPanelsCommand(command='set_pattern_id',
                             arg1=self.params['pattern_id'],
                             arg2=0,
                             arg3=0,
                             arg4=0,
                             arg5=0,
                             arg6=0))
        self.pubPanelsCommand.publish(
            MsgPanelsCommand(command='set_mode',
                             arg1=0,
                             arg2=0,
                             arg3=0,
                             arg4=0,
                             arg5=0,
                             arg6=0))  # xvel=funcx, yvel=funcy
        self.pubPanelsCommand.publish(
            MsgPanelsCommand(command='set_position',
                             arg1=0,
                             arg2=0,
                             arg3=0,
                             arg4=0,
                             arg5=0,
                             arg6=0))  # Set position to 0
        self.pubPanelsCommand.publish(
            MsgPanelsCommand(command='send_gain_bias',
                             arg1=0,
                             arg2=0,
                             arg3=0,
                             arg4=0,
                             arg5=0,
                             arg6=0))  # Set vel to 0
        self.pubPanelsCommand.publish(
            MsgPanelsCommand(command='stop',
                             arg1=0,
                             arg2=0,
                             arg3=0,
                             arg4=0,
                             arg5=0,
                             arg6=0))
        self.pubPanelsCommand.publish(
            MsgPanelsCommand(command='all_off',
                             arg1=0,
                             arg2=0,
                             arg3=0,
                             arg4=0,
                             arg5=0,
                             arg6=0))

        if (self.params['method'] == 'voltage'):
            # Assemble a command:  set_mode_(pos|vel)_custom_(x|y)
            cmd = 'set_mode'
            if (self.params['mode'] == 'velocity'):
                cmd += '_vel'
            elif (self.params['mode'] == 'position'):
                cmd += '_pos'
            else:
                rospy.logwarn('%s: mode must be '
                              'velocity'
                              ' or '
                              'position'
                              '.' % self.name)

            if (self.params['axis'] == 'x'):
                cmd += '_custom_x'
            elif (self.params['axis'] == 'y'):
                cmd += '_custom_y'
            else:
                rospy.logwarn('%s: axis must be '
                              'x'
                              ' or '
                              'y'
                              '.' % self.name)

            # Set the panels controller to the custom mode, with the specified coefficients.
            self.pubPanelsCommand.publish(
                MsgPanelsCommand(command=cmd,
                                 arg1=self.params['coeff_voltage']['adc0'],
                                 arg2=self.params['coeff_voltage']['adc1'],
                                 arg3=self.params['coeff_voltage']['adc2'],
                                 arg4=self.params['coeff_voltage']['adc3'],
                                 arg5=self.params['coeff_voltage']['funcx'],
                                 arg6=self.params['coeff_voltage']['funcy']))

        self.bInitialized = True
예제 #9
0
 def Main(self):
     panelcommand = MsgPanelsCommand(command='all_off')
     self.PanelsCommand_callback(panelcommand)
     rospy.spin()
예제 #10
0
    def execute(self, userdata):
        self.experimentparams = copy.deepcopy(userdata.experimentparamsIn)
        self.timePrev = rospy.Time.now()

        if self.mode == 'pre':
            self.paramsIn = self.experimentparams.pre
        if self.mode == 'trial':
            self.paramsIn = self.experimentparams.trial


        # Create the panels command.
        command = MsgPanelsCommand(command='all_off', arg1=0, arg2=0, arg3=0, arg4=0)

        if self.paramsIn.ledpanels.enabled:
            self.timeStart = rospy.Time.now()
            rv = 'aborted'
            xmax = self.xpanels * 8 # pixels per panel.
    
            # Determine if we're operating only for certain states.
            if len(self.paramsIn.ledpanels.statefilterHi) > 0:
                isStatefiltered = True
            else:
                isStatefiltered = False

            # Initialize statefilter vars.                
            bInStatefilterRangePrev = True
            bInStatefilterRange     = True

                             
            # Set the panels pattern.
            command.command = 'set_pattern_id'
            command.arg1 = self.paramsIn.ledpanels.idPattern
            self.pubLEDPanelsCommand.publish(command)
    
    
            # Loop sending commands to the panels, until preempt or timeout.        
            while not rospy.is_shutdown():
                self.step_time_elapsed()
                
                # If possible, take the pose &/or velocity &/or speed from arenastate, else use transform via ROS.
                pose = None
                velocity = None     
                speed = None   
                if self.arenastate is not None:
                    if ('Robot' in self.paramsIn.ledpanels.frame_id):
                        #pose = self.arenastate.robot.pose  # For consistency w/ galvodirector, we'll get pose via transform.
                        velocity = self.arenastate.robot.velocity
                        speed = self.arenastate.robot.speed
                        
                    elif ('Fly' in self.paramsIn.ledpanels.frame_id):
                        for iFly in range(len(self.arenastate.flies)):
                            if (self.arenastate.flies[iFly].name in self.paramsIn.ledpanels.frame_id):
                                #pose = self.arenastate.flies[iFly].pose  # For consistency w/ galvodirector, we'll get pose via transform.
                                velocity = self.arenastate.flies[iFly].velocity
                                speed = self.arenastate.flies[iFly].speed
                                break

                # Get the timestamp for transforms.
                stamp=None
                if (pose is None) or (velocity is None):
                    try:
                        stamp = self.tfrx.getLatestCommonTime('Arena', self.paramsIn.ledpanels.frame_id)
                    except tf.Exception:
                        pass

                    
                # If we still need the pose (i.e. the frame wasn't in arenastate), then get it from ROS.
                if (pose is None) and (stamp is not None) and self.tfrx.canTransform('Arena', self.paramsIn.ledpanels.frame_id, stamp):
                    try:
                        poseStamped = self.tfrx.transformPose('Arena', PoseStamped(header=Header(stamp=stamp,
                                                                                              frame_id=self.paramsIn.ledpanels.frame_id),
                                                                                pose=Pose(position=Point(0,0,0),
                                                                                          orientation=Quaternion(0,0,0,1)
                                                                                          )
                                                                                )
                                                           )
                        pose = poseStamped.pose
                    except tf.Exception:
                        pose = None

                        
                # If we still need the velocity, then get it from ROS.
                if (velocity is None) and (stamp is not None) and self.tfrx.canTransform('Arena', self.paramsIn.ledpanels.frame_id, stamp):
                    try:
                        velocity_tuple = self.tfrx.lookupTwist('Arena', self.paramsIn.ledpanels.frame_id, stamp, self.dtVelocity)
                    except tf.Exception:
                        velocity = None
                    else:
                        velocity = Twist(linear=Point(x=velocity_tuple[0][0],
                                                      y=velocity_tuple[0][1],
                                                      z=velocity_tuple[0][2]), 
                                         angular=Point(x=velocity_tuple[1][0],
                                                       y=velocity_tuple[1][1],
                                                       z=velocity_tuple[1][2]))

                # If we still need the speed, then get it from velocity.
                if (speed is None) and (velocity is not None):
                    speed = np.linalg.norm([velocity.linear.x, velocity.linear.y, velocity.linear.z])

                                                    
                # See if the state is in range of the filter.
                if isStatefiltered:
                    # Check if any filterstates have changed.
                    bFilterStateChanged = False

                    # Convert filter string to dict.
                    statefilterLo_dict = eval(self.paramsIn.ledpanels.statefilterLo)
                    statefilterHi_dict = eval(self.paramsIn.ledpanels.statefilterHi)
                    statefilterCriteria = self.paramsIn.ledpanels.statefilterCriteria
            
                    if (pose is not None) and (velocity is not None) and (speed is not None):
                        state = MsgFrameState(pose = pose, 
                                              velocity = velocity,
                                              speed = speed)

                        bInStatefilterRangePrev = bInStatefilterRange
                        bInStatefilterRange = self.Statefilter.InRange(state, statefilterLo_dict, statefilterHi_dict, statefilterCriteria)
                        self.Statefilter.PublishMarkers (state, statefilterLo_dict, statefilterHi_dict, statefilterCriteria)
                        
                    # Check if the filter state has changed.
                    if bInStatefilterRangePrev != bInStatefilterRange:
                        bFilterStateChanged = True
                        
                # end if isStatefiltered

                    
                # If in range of the statefilter, then publish the new command                    
                if bInStatefilterRange and (pose is not None) and (velocity is not None) and (speed is not None):
                    bValidCommand = False
                    if self.paramsIn.ledpanels.command == 'fixed':
                        command.command = 'set_position'
                        command.arg1 = self.paramsIn.ledpanels.origin.x
                        command.arg2 = self.paramsIn.ledpanels.origin.y
                        bValidCommand = True

                    elif self.paramsIn.ledpanels.command == 'trackposition':
                        angle = (2.0*np.pi) - np.arctan2(pose.position.y, pose.position.x) % (2.0*np.pi)
                        if np.isfinite(angle):
                            x = xmax * angle / (2.0*np.pi)
                            y = 0
                            command.command = 'set_position'
                            command.arg1 = int(x)
                            command.arg2 = int(y)
                            bValidCommand = True

                    elif self.paramsIn.ledpanels.command == 'trackview':
                        r = rospy.get_param('ledpanels/radius', 120) # Radius of the panels.
                        xp = pose.position.x
                        yp = pose.position.y
                        q = pose.orientation
                        rpy = tf.transformations.euler_from_quaternion((q.x, q.y, q.z, q.w))
                        theta = -rpy[2] % (2.0 * np.pi)
                        tantheta = np.tan(theta)
                        
                        # Points on the circle intersecting with the fly's axis.
                        x1=(1+tantheta**2)**(-1)*((-1)*yp*tantheta+xp*tantheta**2 + (-1)*(r**2+(-1)*yp**2+2*xp*yp*tantheta+r**2*tantheta**2+(-1)*xp**2*tantheta**2)**(1/2))
                        y1=yp+(-1)*xp*tantheta+tantheta*(1+tantheta**2)**(-1)*((-1)*yp*tantheta+xp*tantheta**2+(-1)*(r**2+(-1)*yp**2+2*xp*yp*tantheta+r**2*tantheta**2+(-1)*xp**2*tantheta**2)**(1/2));
                        x2=(1+tantheta**2)**(-1)*((-1)*yp*tantheta+xp*tantheta**2 + (r**2+(-1)*yp**2+2*xp*yp*tantheta+r**2*tantheta**2+(-1)*xp**2*tantheta**2)**(1/2))
                        y2=yp+(-1)*xp*tantheta+tantheta*(1+tantheta**2)**(-1)*((-1)*yp*tantheta+xp*tantheta**2+(r**2+(-1)*yp**2+2*xp*yp*tantheta+r**2*tantheta**2+(-1)*xp**2*tantheta**2)**(1/2))                        
                        
                        
                        # Choose between the two intersection points by moving forward 1mm, and seeing which point we got closer to.
                        r1 = np.linalg.norm([xp-x1, yp-y1]) # Fly to pt1 distance
                        r2 = np.linalg.norm([xp-x2, yp-y2]) # Fly to pt2 distance
                        xa = xp + 1 * np.cos(theta)         # Go one millimeter forward.
                        ya = yp + 1 * np.sin(theta)
                        r1a= np.linalg.norm([xa-x1, ya-y1]) # Fly+1mm to pt1 distance
                        
                        # If we got closer to pt1 at xa, then use pt1, else use pt2 
                        if r1a < r1:
                            angle = np.arctan2(y1,x1) % (2.0*np.pi)
                        else:
                            angle = np.arctan2(y2,x2) % (2.0*np.pi)
                        
                        if np.isfinite(angle):
                            x = xmax * angle / (2.0*np.pi)
                            y = 0
                            
                            command.command = 'set_position'
                            command.arg1 = int(x)
                            command.arg2 = int(y)
                            bValidCommand = True
                        #else:
                            #rospy.logwarn('isnan: (%f,%f), (%f,%f)' % (x1,y1,x2,y2))
                            
                    # end if command == 'trackposition' or 'trackview'
                        
                    if (bValidCommand):                    
                        self.pubLEDPanelsCommand.publish(command)
                        
            
                if self.preempt_requested():
                    rospy.loginfo('preempt requested: LEDPanels()')
                    self.service_preempt()
                    rv = 'preempt'
                    break
    
                self.rosrate.sleep()


                # Handle commands.
                if (self.commandExperiment=='continue'):
                    pass
                
                if (self.commandExperiment=='pause_now'):
                    while (self.commandExperiment=='pause_now'):
                        rospy.sleep(0.5)
                        self.timePrev = rospy.Time.now()

                if (self.commandExperiment=='pause_after_trial'):
                    pass
                
                if (self.commandExperiment=='exit_after_trial'):
                    pass
                
                if (self.commandExperiment=='exit_now'):
                    rv = 'aborted'
                    break
                
            # End while not rospy.is_shutdown()

        else:
            rv = 'disabled'
            command.command = 'all_off'
            self.pubLEDPanelsCommand.publish(command)
            
        # end if self.paramsIn.ledpanels.enabled
                
                
        userdata.experimentparamsOut = self.experimentparams
        return rv
# End class Action()

            
            
    def __init__(self):

        self.pub = rospy.Publisher('/ledpanels/command',
                                   MsgPanelsCommand,
                                   queue_size=10)
        self.msg = MsgPanelsCommand()