示例#1
0
 def setUp(self):
     PybulletAPI.initialize(SimulationTime(1000), False)
     PybulletAPI.gui = MagicMock(return_value=True)
     # Use side_effect to spy on a method: Can assert calls but functionality doesn't change.
     PybulletAPI.addUserDebugLine = MagicMock(
         side_effect=PybulletAPI.addUserDebugLine)
     self._debug_line = DebugLine(Vec3([0, 0, 0]), Vec3([0, 0, 0]))
示例#2
0
 def test_updating_when_time_has_passed(self):
     # Mocking time to return number bigger than update frequency
     with patch(
             'time.time',
             mock.MagicMock(return_value=DebugLine._MIN_UPDATE_INTERVAL +
                            1E-6)):
         self._debug_line.update(Vec3([0, 0, 0]), Vec3([0, 0, 0]))
     # Assert debug line is not called twice because cannot create line too frequent
     self.assertEqual(2, PybulletAPI.addUserDebugLine.call_count)
    def addUserDebugLine(lineFromXYZ: Vec3, lineToXYZ: Vec3, lineWidth: float, lineColorRGB: List[float],
                         parentObjectUniqueId: int = -1, replaceItemUniqueId: int = -1) -> int:

        if PybulletAPI.gui():
            return p.addUserDebugLine(lineFromXYZ=lineFromXYZ.as_nwu(),
                                      lineToXYZ=lineToXYZ.as_nwu(),
                                      lineWidth=lineWidth,
                                      lineColorRGB=lineColorRGB,
                                      parentObjectUniqueId=parentObjectUniqueId,
                                      replaceItemUniqueId=replaceItemUniqueId)
示例#4
0
    def test_velocity(self):
        simulator = Simulator(4000, gui=False)
        PybulletAPI.loadURDF("plane.urdf", Vec3([0, 0, 30]))
        simulator.create_robot()
        simulator.robot.set_velocity(linear_velocity=Vec3([1, 1, 1]))

        simulator.do_step()

        previous_velocity = simulator.robot.get_velocity()

        amount_sensor_updates = 0
        for _ in range(500):
            simulator.robot.set_velocity(linear_velocity=Vec3([1, 1, 1]))
            actual_velocity = simulator.robot.get_velocity()
            simulator.do_step()

            sensor_data = simulator.robot.dvl.get_latest_value()

            # Since the dvl runs
            if sensor_data:

                # Velocity_valid should always be true otherwise the dvl is too far away from the surface and this test wouldn't work.
                self.assertTrue(sensor_data[1]['velocity_valid'])

                amount_sensor_updates += 1
                vx, vy, vz = sensor_data[1]['vx'], sensor_data[1]['vy'], sensor_data[1]['vz']

                min_vx = min((actual_velocity[X], previous_velocity[X]))
                max_vx = max((actual_velocity[X], previous_velocity[X]))

                min_vy = min((actual_velocity[Y], previous_velocity[Y]))
                max_vy = max((actual_velocity[Y], previous_velocity[Y]))

                min_vz = min((actual_velocity[Z], previous_velocity[Z]))
                max_vz = max((actual_velocity[Z], previous_velocity[Z]))

                # Make sure the sensor velocities are between the actual velocities, since it is interpolated between
                # the two
                self.assertLessEqual(min_vx, vx)
                self.assertLessEqual(min_vy, vy)
                self.assertLessEqual(min_vz, vz)
                self.assertLessEqual(vx, max_vx)
                self.assertLessEqual(vy, max_vy)
                self.assertLessEqual(vz, max_vz)

            previous_velocity = Vec3(actual_velocity)

        # If there weren't at least 10 sensor updates the there went something wrong with the test.
        self.assertGreater(amount_sensor_updates, 10)
    def test_advanced_buoyancy_is_calculated_when_robot_is_close_to_surface(
            self):
        z_pos = 0.9
        # Length should be twice as much as distance from robot position to sea surface such that buoyancy will be calculated.
        robot_length = (z_pos + 0.1) * 2
        robot_mock = MagicMock()
        with mock.patch(
                "lobster_simulator.robot.buoyancy.Buoyancy._check_ray_hits_robot",
                return_value=True):
            buoyancy_obj = buoyancy.Buoyancy(robot_mock, 0.5, robot_length)

        robot_mock.apply_force = Mock()

        robot_mock.get_position_and_orientation = Mock(
            return_value=(Vec3((0, 0, z_pos)), Quaternion((0, 0, 0, 1))))

        buoyancy_obj.update()

        robot_mock.get_position_and_orientation.assert_called_once()

        # First and third argument could change in the future.
        robot_mock.apply_force.assert_called_once()
        self.assertEqual(
            buoyancy_obj._buoyancy,
            -robot_mock.apply_force.call_args[0][1][Z],
            msg=
            "buoyancy force is not as expected to be when robot is fully underwater."
        )
示例#6
0
    def add_ocean_floor(self, depth=100):
        id = PybulletAPI.loadURDF(resource_filename("lobster_simulator",
                                                    "data/plane1000.urdf"),
                                  base_position=Vec3((0, 0, depth)))

        texture = PybulletAPI.loadTexture(
            resource_filename("lobster_simulator", "data/checker_blue.png"))
        PybulletAPI.changeVisualShape(id, texture, rgbaColor=[1, 1, 1, 1])
    def load_chunk(self, chunk_x, chunk_y):
        height_field_data = self.get_height_field(chunk_x, chunk_y)

        middle = (max(height_field_data) + min(height_field_data)) / 2

        terrainShape = p.createCollisionShape(shapeType=p.GEOM_HEIGHTFIELD,
                                              meshScale=[self.point_spacing, self.point_spacing, 1],
                                              heightfieldTextureScaling=(self.points_per_chunk - 1) / 2,
                                              heightfieldData=height_field_data,
                                              numHeightfieldRows=self.points_per_chunk,
                                              numHeightfieldColumns=self.points_per_chunk)

        terrain = p.createMultiBody(0, terrainShape,
                                    basePosition=Vec3([(self.chunk_size * chunk_x + self.chunk_size / 2),
                                                       (self.chunk_size * chunk_y + self.chunk_size / 2),
                                                       self.depth - middle]).as_nwu(),
                                    baseOrientation=Quaternion.from_euler(Vec3([0, 0, math.pi])).as_nwu())

        return terrain
    def test_pressure_at_surface(self):
        simulator = Simulator(4000, gui=False)
        robot = simulator.create_robot()
        robot.set_position_and_orientation(position=Vec3((0, 0, 0)))
        simulator.do_step()
        depth = robot.get_position()[Z]
        print("depth", depth)
        pressure = robot.pressure_sensor.get_pressure()

        # Only checking accuracy up to 1 decimal place, since the robot moves a bit during the step
        self.assertAlmostEqual(101.3, pressure, places=1)
    def __init__(self, time: SimulationTime):
        water_id = PybulletAPI.loadURDF(
            resource_filename("lobster_simulator", "data/water_surface.urdf"),
            Vec3([0, 0, 0]))

        self.water_texture = PybulletAPI.loadTexture(
            resource_filename("lobster_simulator", "data/water_texture.png"))

        PybulletAPI.changeVisualShape(water_id,
                                      textureUniqueId=self.water_texture,
                                      rgbaColor=[0, 0.3, 1, 0.5])
示例#10
0
def vec3_local_to_world(local_frame_position: Vec3,
                        local_frame_orientation: Quaternion,
                        local_vec: Vec3) -> Vec3:
    """
    Converts a vector in a local reference frame to the global reference frame
    :param local_frame_position: Position of the local frame
    :param local_frame_orientation: Orientation of the local frame
    :param local_vec: Vector in the local reference frame
    :return: Vector in the global reference frame
    """
    word_vec = local_vec.rotate(local_frame_orientation) + local_frame_position
    return word_vec
示例#11
0
    def test_altitude(self):
        dt = SimulationTime(4000)
        simulator = Simulator(4000, gui=False)
        # Load a plane so that the DVL works
        PybulletAPI.loadURDF("plane.urdf", Vec3([0, 0, 30]))
        simulator.create_robot()
        simulator.do_step()
        previous_altitude = simulator.robot._dvl._get_real_values(dt)[0]

        downwards_velocity = Vec3([0, 0, 1])

        amount_sensor_updates = 0
        for _ in range(500):
            simulator.do_step()
            simulator.robot.set_velocity(linear_velocity=downwards_velocity)

            actual_altitude = simulator.robot._dvl._get_real_values(dt)[0]
            sensor_data = simulator.robot._dvl.get_latest_value()

            # Since the dvl runs at a slower rate than the simulator, it's possible that there is no new data point
            if sensor_data is not None:
                # Velocity_valid should always be true otherwise the dvl is too far away from the surface and this test wouldn't work.
                self.assertTrue(sensor_data[1]['velocity_valid'])

                amount_sensor_updates += 1
                sensor_altitude = sensor_data[1]['altitude']

                min_altitude = min((actual_altitude, previous_altitude))
                max_altitude = max((actual_altitude, previous_altitude))

                # Make sure the sensor altitude is between the actual altitudes, since it is interpolated between the
                # two
                self.assertLessEqual(min_altitude, sensor_altitude)
                self.assertLessEqual(sensor_altitude, max_altitude)

            previous_altitude = actual_altitude

        # If there weren't at least 10 sensor updates the there went something wrong with the test.
        self.assertGreater(amount_sensor_updates, 10)
    def test_pressure_increases_when_going_down(self):
        """Move the robot down and assert that the pressure will only increase."""
        simulator = Simulator(4000, gui=False)
        simulator.create_robot()
        downwards_velocity = Vec3([0, 0, 1])
        simulator.robot.set_velocity(linear_velocity=downwards_velocity)
        simulator.do_step()
        previous_pressure = simulator.robot.pressure_sensor.get_pressure()

        for _ in range(100):
            simulator.robot.set_velocity(linear_velocity=downwards_velocity)
            simulator.do_step()
            current_pressure = simulator.robot.pressure_sensor.get_pressure()

            self.assertLess(previous_pressure, current_pressure)
            previous_pressure = current_pressure
示例#13
0
    def __init__(self, time_step: int, config=None, gui=True):
        """
        Simulator
        :param time_step: duration of a step in microseconds
        :param config: config of the robot.
        :param gui: start the PyBullet gui when true
        """
        with resource_stream('lobster_simulator', 'data/config.json') as f:
            base_config = json.load(f)

        if config is not None:
            base_config.update(config)

        config = base_config

        self.rotate_camera_with_robot = bool(
            config['rotate_camera_with_robot'])

        self._time: SimulationTime = SimulationTime(0)
        self._previous_update_time: SimulationTime = SimulationTime(0)
        self._previous_update_real_time: float = t.perf_counter()  # in seconds
        self._time_step: SimulationTime = SimulationTime(
            initial_microseconds=time_step)

        self._cycle = 0

        PybulletAPI.initialize(self._time_step, gui)

        self.water_surface = WaterSurface(self._time)

        self._simulator_frequency_slider = PybulletAPI.addUserDebugParameter(
            "simulation frequency", 10, 1000, 1 / self._time_step.microseconds)
        self._buoyancy_force_slider = PybulletAPI.addUserDebugParameter(
            "buoyancyForce", 0, 1000, 550)

        self._model = None
        self.robot_config = None

        self._camera_position = Vec3([0, 0, 0])
        self._robot: Optional[AUV] = None
示例#14
0
    def __init__(self, robot: AUV, position: Vec3, time_step: SimulationTime, time: SimulationTime, orientation: Quaternion,
                 noise_stds: Optional[Union[List[float], float]]):
        """
        Parameters
        ----------
        robot : AUV
            The robot the sensor is attached to.
        position : array[3]
            The local position of the sensor on the robot.
        orientation : array[4]
            The orientation of the sensor on the robot as a quaternion.
        time_step : int
            The time step between two polls on the sensor in microseconds.
        orientation : Quaternion
            Orientation of the sensor w.r.t. the robot.
        noise_stds :Union[List[float], float]
            Number or list of numbers with the standard deviation for each of the outputs of the sensor.
        """

        if orientation is None:
            orientation = Quaternion.from_euler(Vec3([0, 0, 0]))

        self._robot: AUV = robot
        self._sensor_position: Vec3 = position
        self._sensor_orientation: Quaternion = orientation
        self._time_step = time_step

        self._queue = list()

        self._next_sample_time: SimulationTime = SimulationTime(initial_microseconds=time.microseconds)
        self._previous_update_time: SimulationTime = SimulationTime(initial_microseconds=time.microseconds)
        self._previous_real_value = self._get_real_values(SimulationTime(1))

        self.noise_stds = None
        if noise_stds:
            self.set_noise(noise_stds)