コード例 #1
0
    def update_sim(self, now: float, tm_diff: float) -> None:
        """
            Called when the simulation parameters for the program need to be
            updated.
            
            :param now: The current time as a float
            :param tm_diff: The amount of time that has passed since the last
                            time that this function was called
        """

        # Simulate the drivetrain and update encoders
        if self.sparkmax:
            #self.l_spark_output.set(0.333) # need the -1 to 1 motor value, and I have to fake it
            #self.r_spark_output.set(0.999)
            l_motor = self.l_spark_output.get()
            r_motor = self.r_spark_output.get()
        else:
            l_motor = self.l_motor.getSpeed(
            )  # these are PWM speeds of -1 to 1
            r_motor = self.r_motor.getSpeed(
            )  #  going forward, left should be positive and right is negative

        # get a new location based on motor movement
        transform = self.drivetrain.calculate(l_motor, r_motor, tm_diff)
        pose = self.physics_controller.move_robot(
            transform)  # includes inertia

        # keep us on the simulated field - reverse the transform if we try to go out of bounds
        sim_padding = 0.25  # 0.25  # let us go a bit outside but not get lost
        bad_move = False  # see if we are out of bounds or hitting a barrier
        if (pose.translation().x < -sim_padding
                or pose.translation().x > self.x_limit + sim_padding
                or pose.translation().y < -sim_padding
                or pose.translation().y > self.y_limit + sim_padding):
            bad_move = True

        # allowing the user to change the obstacles
        pylon_points = []
        if 'slalom' in self.obstacles:
            pylon_points = drive_constants.slalom_points
        if 'barrel' in self.obstacles:
            pylon_points = drive_constants.barrel_points
        if 'bounce' in self.obstacles:
            pylon_points = drive_constants.bounce_points
        if any([
                drive_constants.distance(pose, i) <
                drive_constants.k_track_width_meters / 2 for i in pylon_points
        ]):
            bad_move = True

        # this resets the move if we are hitting a barrier
        # ToDo: stop the motion as well.  Perhaps in addition to moving back we should redo transform w/ no motor speed
        if bad_move:
            curr_x, curr_y = transform.translation().x, transform.translation(
            ).y
            # in 2021 library they added an inverse() to transforms so this could all be one line
            new_transform = geo.Transform2d(geo.Translation2d(-curr_x, curr_y),
                                            transform.rotation())
            pose = self.physics_controller.move_robot(new_transform)

        # Update encoders - need use the pose so it updates properly for coasting to a stop
        # ToDo: get the actual values, probably from wheelspeeds?
        # have to only work with deltas otherwise we can't reset the encoder from the real code
        # damn it, the SparkMax and the standard encoders have different calls

        if self.sparkmax:
            self.l_spark_position.set(
                self.l_spark_position.get() +
                (self.drivetrain.l_position - self.l_distance_old) * 0.3105)
            self.r_spark_position.set(
                self.r_spark_position.get() +
                (self.drivetrain.r_position - self.r_distance_old) * 0.3105)
            self.l_spark_velocity.set(
                0.31 * (self.drivetrain.l_position - self.l_distance_old) /
                tm_diff)
            self.r_spark_velocity.set(
                0.31 * (self.drivetrain.r_position - self.r_distance_old) /
                tm_diff)
        else:
            self.l_encoder.setDistance(
                self.l_encoder.getDistance() +
                (self.drivetrain.l_position - self.l_distance_old) * 0.3105)
            self.r_encoder.setDistance(
                self.r_encoder.getDistance() -
                (self.drivetrain.r_position - self.r_distance_old) *
                0.3105)  # negative going forward
            self.l_encoder.setRate(
                0.31 * (self.drivetrain.l_position - self.l_distance_old) /
                tm_diff)
            self.r_encoder.setRate(
                -0.31 * (self.drivetrain.r_position - self.r_distance_old) /
                tm_diff)  # needs to be negitive going fwd

        self.l_distance_old = self.drivetrain.l_position
        self.r_distance_old = self.drivetrain.r_position

        self.x, self.y = pose.translation().x, pose.translation().y
        # Update the navx gyro simulation
        # -> FRC gyros like NavX are positive clockwise, but the returned pose is positive counter-clockwise
        self.navx_yaw.set(-pose.rotation().degrees())

        # ---------------- HOOD ELEVATOR UPDATES ---------------------------
        # update 'position' (use tm_diff so the rate is constant) - this is for simulating an elevator, arm etc w/ limit switches
        self.hood_position += self.hood_motor.getSpeed(
        ) * tm_diff * 30 - 0.05  # inserting gravity!

        # update limit switches based on position
        if self.hood_position <= 30:
            switch1 = True
            switch2 = False
            if self.hood_position < 29.5:  # don't let gravity sag too much
                self.hood_position = 29.5
        elif self.hood_position > 50:
            switch1 = False
            switch2 = True

        else:
            switch1 = False
            switch2 = False

        # set values here - nice way to emulate the robot's state
        self.limit_low.setValue(switch1)
        self.limit_hi.setValue(switch2)
        self.hood_encoder.setDistance(round(self.hood_position, 2))

        self.counter += 1
        if self.counter % 5 == 0:
            SmartDashboard.putNumber('field_x', round(self.x, 2))
            SmartDashboard.putNumber('field_y', round(self.y, 2))
            SmartDashboard.putNumber('hood', round(self.hood_position, 1))

        if self.counter % 50 == 0:
            self.obstacles = SmartDashboard.getData(
                'obstacles').getSelected()  # read the obstacles from the dash