예제 #1
0
파일: autoaim.py 프로젝트: frc2423/2016
 def __init__(self):
     self.aimed_at_angle = None
     self.aimed_at_distance = None
     
     self.exposure_control = ExposureControl()
     
     # By default, ensure the operator can see through both cameras
     self.exposure_control.set_auto_exposure(device=0)
     self.exposure_control.set_auto_exposure(device=1)
     
     # target angle stuff
     self.target = None
     
     nt = NetworkTable.getTable('/camera')
     nt.addTableListener(self._on_target, True, 'target')
     
     self.move_to_target_height_output = None
예제 #2
0
파일: autoaim.py 프로젝트: frc2423/2016
class AutoAim(StateMachine):
    '''
        Automatically positions the robot so that it can shoot,
        and then shoots.
    '''
    
    VERBOSE_LOGGING = True
    
    LIGHT_ON = wpilib.Relay.Value.kOn
    LIGHT_OFF = wpilib.Relay.Value.kOff
    
    drive = Drive
    pitcher = Pitcher
    shooter_control = ShooterControl
    
    angle_ctrl = AngleController
    distance_ctrl = DistanceController
    
    pos_history = PositionHistory
    
    # Variables to driver station
    camera_enabled = ntproperty('/camera/enabled', False)
    
    autoaim_enabled = tunable(False)
    
    # straight-line approximation for translating pixels to 
    # encoder feet movements
    #ideal_height = tunable(-3)
    #other_height = tunable(11.7)
    #ideal_encoder = tunable(0)
    #other_encoder = tunable(6.3)
    ideal_distance = tunable(6)
    angle_offset = tunable(-6)

    if hal.HALIsSimulation():
        kP = 0.2
    else:
        kP = 0.06
        
    kI = 0.00
    kD = 0.00
    kF = 0.00
    
    def __init__(self):
        self.aimed_at_angle = None
        self.aimed_at_distance = None
        
        self.exposure_control = ExposureControl()
        
        # By default, ensure the operator can see through both cameras
        self.exposure_control.set_auto_exposure(device=0)
        self.exposure_control.set_auto_exposure(device=1)
        
        # target angle stuff
        self.target = None
        
        nt = NetworkTable.getTable('/camera')
        nt.addTableListener(self._on_target, True, 'target')
        
        self.move_to_target_height_output = None
    
    #
    # Internal API
    #
    
    def _on_target(self, source, key, value, isNew):
        self.target = value
        
    #def _height_to_distance_offset(self, h):
    #    '''converts a height to a distance'''
    #    return ((h - self.other_height) * (self.ideal_encoder - self.other_encoder)) / (self.ideal_height - self.other_height) + self.other_encoder
    
    def _move_to_position(self):
        '''returns true if at correct position, false otherwise'''
        
        # This is the bulk of the logic here.. 
        target = self.target
        
        if target is not None and len(target) > 0:
            
            # copy before using it
            target = target[:]
            
            # old idea: reduce the camera angle by half to compensate for lag
            # new idea: latency compensation
            angle, height, tgt_dist, capture_ts = target
            history = self.pos_history.get_position(capture_ts)
            
            if history is not None:
                r_angle, r_position, r_ts = history
                
                
                #self.aimed_at_angle = self.drive.get_angle_at_ts(capture_ts) + (angle/2.0)
                self.aimed_at_angle = r_angle + angle - self.angle_offset
                self.aimed_at_distance = r_position + (tgt_dist - self.ideal_distance)
                
                
                #self.logger.info("Target distance: %0.3f (%0.3f); %0.3f vs %0.3f; %0.3f", self.aimed_at_distance, offset,
                #                 r_position, self.distance_ctrl.get_position(), height)
            
            self.target = None
        
        # Tell the robot to go to somewhere
        
        if self.aimed_at_angle is not None:
            self.angle_ctrl.align_to(self.aimed_at_angle)
            
        if self.aimed_at_distance is not None:
            self.distance_ctrl.move_to(self.aimed_at_distance)
        
        return self.is_at_position()
        #return False
    
    #
    # External API
    #
    
    def aim(self):
        '''Engage the autoaim procedure'''
        self.engage()
    
    def is_at_position(self):
        ''':returns: True when robot is in firing position'''
        return self.distance_ctrl.is_at_location() and \
               self.angle_ctrl.is_aligned()
    
    #
    # State machine
    #
    
    @state(first=True)
    def initial_state(self):
        
        # Ensure that stale data is removed
        self.target = None
        self.aimed_at_angle = None
        self.aimed_at_distance = None
        
        self.pos_history.enable()
        
        # Tracking only works when exposure is turned down
        self.exposure_control.set_dark_exposure(device=0)
        self.camera_enabled = True
        
        self.next_state_now('moving_to_position')
            
    @state
    def moving_to_position(self):
        '''Cause the robot to automatically move to the correct position to shoot'''
        
        # Don't care about whether the image is 'present', the target
        # angle/height will be set when it is, and if there's a blip where the
        # camera can't see the target we don't want to interrupt the operators
        # movements
        
        if self._move_to_position():
            # at the right place? ok, transition!
            self.next_state('at_position')
    
    @timed_state(duration=.5, next_state='begin_firing')
    def at_position(self):
        '''Only go to 'begin_firing' if we've been at the right position for
        more than a set period of time'''
        
        if not self._move_to_position():
            # if we're no longer on the right spot, reset
            self.next_state('moving_to_position')
    
    @state
    def begin_firing(self):
        '''At the correct position, fire the ball'''
        
        # TODO: should move to position still? Now that vibration
        #       is less of an issue, could continuously adjust?
        # if not self._move_to_position():
        #     self.next_state_now('moving_to_position')
        # else: .. 
        
        self.drive.move(0, 0)
        self.shooter_control.fire()
        
        # Wait for the shooter to report that it has fired
        if self.shooter_control.is_firing():
            self.next_state_now('firing')
    
    @timed_state(duration=0.5, must_finish=True, next_state='end')
    def firing(self):
        '''Waits for the ball to exit before allowing the operator to move'''
        self.drive.move(0, 0)
        self.shooter_control.fire()
    
    @state
    def end(self):
        '''Just sit until the operator lets go of the joystick'''
        pass
    
    def done(self):
        super().done()
        
        self.pos_history.disable()
        
        self.camera_enabled = False
        self.on_target = False
        self.exposure_control.set_auto_exposure(device=0)