diff --git a/assets/images/robot.png b/assets/images/robot.png index fc8b613..ecf4c46 100644 Binary files a/assets/images/robot.png and b/assets/images/robot.png differ diff --git a/assets/user_readme.md b/assets/user_readme.md index 2f00f98..3dc1efa 100644 --- a/assets/user_readme.md +++ b/assets/user_readme.md @@ -168,11 +168,12 @@ The robot has a number of boards attached to it that can be interacted with usin These boards include: - Power Board (serial number: `PWR`) + - OUT_H0 controls the vacuum pump. Enabling this allows the robot to pick up the token. - Motor Board (serial number: `MOT`) - The left wheel is connected to motor 0. - The right wheel is connected to motor 1. - Servo Board (serial number: `SERVO`) - - No servos are attached to the simulated robot. + - Servo 0 controls the lifter. Setting the position to -1 will move the lifter to the bottom position and a position of 1 will move the lifter to the top position. - Arduino Board (serial number: `Arduino1`) - The attached sensors are covered in the [Sensors](#attached-sensors) section. - Camera (serial number: `Camera`) @@ -254,6 +255,15 @@ If you see a message saying that Python cannot be found that looks similar to th As well as the guidance above, there are a few other points to note when using the simulator. These can help you to understand what is happening and how to get the most out of the simulator. +### Using Other Zones + +If the arena has multiple starting zones, you can run multiple robots in the simulator. +To test how your robot behaves in each starting zone of the arena, you can copy your robot's code to run in each corner. + +In the folder where you extracted the simulator, alongside the `zone_0` folder, you may have other `zone_` folders. +Such as `zone_1`, `zone_2`, etc. +Each of these folders can contain a `robot.py` file that will be run in the corresponding starting zone of the arena. + ### Performance Optimisations The default settings work for most users however if you are using a less powerful computer or one without a dedicated graphics card (as is the case on many laptops), you may wish to adjust the graphics settings to enable the simulation to run faster. diff --git a/example_robots/keyboard_robot.py b/example_robots/keyboard_robot.py index 3d15285..a013942 100644 --- a/example_robots/keyboard_robot.py +++ b/example_robots/keyboard_robot.py @@ -1,10 +1,9 @@ import math from controller import Keyboard -from sr.robot3 import A0, A1, A2, Robot +from sr.robot3 import A0, A1, A2, OUT_H0, Colour, Robot -# Any keys still pressed in the following period will be handled again -# leading to rprinting sensors multiple times +# Keyboard sampling period in milliseconds KEYBOARD_SAMPLING_PERIOD = 100 NO_KEY_PRESSED = -1 @@ -15,7 +14,11 @@ "right": (ord("D"), ord("L")), "sense": (ord("Q"), ord("U")), "see": (ord("E"), ord("O")), - "led": (ord("R"), ord("P")), + "led": (ord("Z"), ord("M")), + "sucker_enable": (ord("X"), ord(",")), + "sucker_disable": (ord("C"), ord(".")), + "lift_up": (ord("R"), ord("P")), + "lift_down": (ord("F"), ord(";")), "boost": (Keyboard.SHIFT, Keyboard.CONTROL), "angle_unit": (ord("B"), ord("B")), } @@ -88,12 +91,12 @@ def print_sensors(robot: Robot) -> None: print("Touch sensor readings:") for pin, name in touch_sensor_names.items(): - touching = robot.arduino.pins[pin].digital_value + touching = robot.arduino.pins[pin].digital_read() print(f"{pin} {name: <6}: {touching}") print("Reflectance sensor readings:") for Apin, name in reflectance_sensor_names.items(): - reflectance = robot.arduino.pins[Apin].analog_value + reflectance = robot.arduino.pins[Apin].analog_read() print(f"{Apin} {name: <12}: {reflectance:.2f} V") @@ -104,8 +107,9 @@ def print_camera_detection(robot: Robot) -> None: for marker in markers: print(f" #{marker.id}") print( - f" Position: {marker.distance:.0f} mm, azi: {angle_str(marker.azimuth)}, " - f"elev: {angle_str(marker.elevation)}", + f" Position: {marker.position.distance:.0f} mm, " + f"{angle_str(marker.position.horizontal_angle)} right, " + f"{angle_str(marker.position.vertical_angle)} up", ) yaw, pitch, roll = marker.orientation print( @@ -120,10 +124,16 @@ def print_camera_detection(robot: Robot) -> None: robot = Robot() - keyboard = KeyboardInterface() +lift_height = robot.servo_board.servos[0].position + +# Automatically set the zone controls based on the robot's zone +# Alternatively, you can set this manually +# ZONE_CONTROLS = 0 +ZONE_CONTROLS = robot.zone -key_sense = CONTROLS["sense"][robot.zone] +assert ZONE_CONTROLS < len(CONTROLS["forward"]), \ + "No controls defined for this zone, alter the ZONE_CONTROLS variable to use in this zone." print( "Note: you need to click on 3D viewport for keyboard events to be picked " @@ -138,36 +148,58 @@ def print_camera_detection(robot: Robot) -> None: keys = keyboard.process_keys() # Actions that are run continuously while the key is held - if CONTROLS["forward"][robot.zone] in keys["held"]: + if CONTROLS["forward"][ZONE_CONTROLS] in keys["held"]: left_power += 0.5 right_power += 0.5 - if CONTROLS["reverse"][robot.zone] in keys["held"]: + if CONTROLS["reverse"][ZONE_CONTROLS] in keys["held"]: left_power += -0.5 right_power += -0.5 - if CONTROLS["left"][robot.zone] in keys["held"]: + if CONTROLS["left"][ZONE_CONTROLS] in keys["held"]: left_power -= 0.25 right_power += 0.25 - if CONTROLS["right"][robot.zone] in keys["held"]: + if CONTROLS["right"][ZONE_CONTROLS] in keys["held"]: left_power += 0.25 right_power -= 0.25 - if CONTROLS["boost"][robot.zone] in keys["held"]: + if CONTROLS["boost"][ZONE_CONTROLS] in keys["held"]: boost = True + if CONTROLS["lift_up"][ZONE_CONTROLS] in keys["held"]: + # constrain to [-1, 1] + lift_height = max(min(lift_height + 0.05, 1), -1) + robot.servo_board.servos[0].position = lift_height + + if CONTROLS["lift_down"][ZONE_CONTROLS] in keys["held"]: + # constrain to [-1, 1] + lift_height = max(min(lift_height - 0.05, 1), -1) + robot.servo_board.servos[0].position = lift_height + # Actions that are run once when the key is pressed - if CONTROLS["sense"][robot.zone] in keys["pressed"]: + if CONTROLS["sense"][ZONE_CONTROLS] in keys["pressed"]: print_sensors(robot) - if CONTROLS["see"][robot.zone] in keys["pressed"]: + if CONTROLS["see"][ZONE_CONTROLS] in keys["pressed"]: print_camera_detection(robot) - if CONTROLS["led"][robot.zone] in keys["pressed"]: - pass + if CONTROLS["sucker_enable"][ZONE_CONTROLS] in keys["pressed"]: + robot.power_board.outputs[OUT_H0].is_enabled = 1 + + if CONTROLS["sucker_disable"][ZONE_CONTROLS] in keys["pressed"]: + robot.power_board.outputs[OUT_H0].is_enabled = 0 + + if CONTROLS["led"][ZONE_CONTROLS] in keys["pressed"]: + robot.kch.leds[0].colour = Colour.MAGENTA + robot.kch.leds[1].colour = Colour.MAGENTA + robot.kch.leds[2].colour = Colour.MAGENTA + elif CONTROLS["led"][ZONE_CONTROLS] in keys["released"]: + robot.kch.leds[0].colour = Colour.OFF + robot.kch.leds[1].colour = Colour.OFF + robot.kch.leds[2].colour = Colour.OFF - if CONTROLS["angle_unit"][robot.zone] in keys["pressed"]: + if CONTROLS["angle_unit"][ZONE_CONTROLS] in keys["pressed"]: USE_DEGREES = not USE_DEGREES print(f"Angle unit set to {'degrees' if USE_DEGREES else 'radians'}") diff --git a/simulator/controllers/usercode_runner/usercode_runner.py b/simulator/controllers/usercode_runner/usercode_runner.py index 6621c75..c090217 100644 --- a/simulator/controllers/usercode_runner/usercode_runner.py +++ b/simulator/controllers/usercode_runner/usercode_runner.py @@ -48,7 +48,7 @@ def get_robot_file(robot_zone: int) -> Path: # Check if the robot file exists if not robot_file.exists(): - raise FileNotFoundError(f"No robot controller found for zone {robot_file}") + raise FileNotFoundError(f"No robot code to run for zone {robot_zone}") return robot_file @@ -169,8 +169,9 @@ def main() -> bool: robot_file = get_robot_file(zone) except FileNotFoundError as e: print(e.args[0]) + robot.step() # Not having a robot file is not an error in dev mode - return game_mode == 'comp' + return game_mode != 'comp' # Setup log file prefix_and_tee_streams( diff --git a/simulator/environment.py b/simulator/environment.py index 65af930..b512acc 100644 --- a/simulator/environment.py +++ b/simulator/environment.py @@ -11,7 +11,7 @@ MODULES_ROOT = SIM_ROOT / 'modules' GAME_MODE_FILE = SIM_ROOT / 'mode.txt' -NUM_ZONES = 1 +NUM_ZONES = 4 def setup_environment() -> None: diff --git a/simulator/modules/sbot_interface/devices/motor.py b/simulator/modules/sbot_interface/devices/motor.py index 46c579a..4cba116 100644 --- a/simulator/modules/sbot_interface/devices/motor.py +++ b/simulator/modules/sbot_interface/devices/motor.py @@ -97,7 +97,7 @@ def __init__(self, device_name: str) -> None: self._device.setVelocity(0) self._max_speed = self._device.getMaxVelocity() # Limit the torque the motor can apply to have realistic acceleration - self._device.setAvailableTorque(1) + self._device.setAvailableTorque(2) def disable(self) -> None: """Disable the motor.""" diff --git a/simulator/modules/sbot_interface/devices/power.py b/simulator/modules/sbot_interface/devices/power.py index 849914d..71b06d1 100644 --- a/simulator/modules/sbot_interface/devices/power.py +++ b/simulator/modules/sbot_interface/devices/power.py @@ -4,7 +4,7 @@ from abc import ABC, abstractmethod from typing import Callable -from sbot_interface.devices.util import get_globals +from sbot_interface.devices.util import WebotsDevice, get_globals, get_robot_device class Output: @@ -36,6 +36,36 @@ def get_current(self) -> int: return 0 +class ConnectorOutput(Output): + """ + A class to represent a power output that controls a webots connector device. + + :param device_name: The name of the device in webots. + :param downstream_current: A function to get the current draw of the downstream device. + """ + + def __init__( + self, + device_name: str, + downstream_current: Callable[[], int] | None = None, + ) -> None: + super().__init__(downstream_current) + g = get_globals() + self._device = get_robot_device(g.robot, device_name, WebotsDevice.Connector) + self._enabled = False + + def set_output(self, enable: bool) -> None: + """Set the output state.""" + if enable: + self._device.lock() # type: ignore[no-untyped-call] + else: + self._device.unlock() # type: ignore[no-untyped-call] + + def get_output(self) -> bool: + """Get the output state.""" + return self._device.isLocked() + + class BaseBuzzer(ABC): """The base class for the buzzer device.""" diff --git a/simulator/modules/sbot_interface/devices/servo.py b/simulator/modules/sbot_interface/devices/servo.py index a25da32..92e7e07 100644 --- a/simulator/modules/sbot_interface/devices/servo.py +++ b/simulator/modules/sbot_interface/devices/servo.py @@ -4,7 +4,10 @@ The servo will apply a small amount of variation to the power setting to simulate inaccuracies in the servo. """ +from __future__ import annotations + from abc import ABC, abstractmethod +from typing import TYPE_CHECKING from sbot_interface.devices.util import ( WebotsDevice, @@ -14,6 +17,9 @@ map_to_range, ) +if TYPE_CHECKING: + from controller import PositionSensor + MAX_POSITION = 2000 MIN_POSITION = 1000 @@ -97,8 +103,11 @@ def __init__(self, device_name: str) -> None: self._enabled = False g = get_globals() self._device = get_robot_device(g.robot, device_name, WebotsDevice.Motor) + self._pos_sensor: PositionSensor | None = self._device.getPositionSensor() # type: ignore[no-untyped-call] self._max_position = self._device.getMaxPosition() self._min_position = self._device.getMinPosition() + if self._pos_sensor is not None: + self._pos_sensor.enable(g.timestep) def disable(self) -> None: """Disable the servo.""" @@ -112,7 +121,7 @@ def set_position(self, value: int) -> None: """ # Apply a small amount of variation to the power setting to simulate # inaccuracies in the servo - value = int(add_jitter(value, (MIN_POSITION, MAX_POSITION))) + value = int(add_jitter(value, (MIN_POSITION, MAX_POSITION), std_dev_percent=0.5)) self._device.setPosition(map_to_range( value, @@ -128,6 +137,12 @@ def get_position(self) -> int: Position is the pulse width in microseconds. """ + if self._pos_sensor is not None: + self.position = int(map_to_range( + self._pos_sensor.getValue(), + (self._min_position + 0.001, self._max_position - 0.001), + (MIN_POSITION, MAX_POSITION), + )) return self.position def get_current(self) -> int: diff --git a/simulator/modules/sbot_interface/devices/util.py b/simulator/modules/sbot_interface/devices/util.py index 9724b74..a160215 100644 --- a/simulator/modules/sbot_interface/devices/util.py +++ b/simulator/modules/sbot_interface/devices/util.py @@ -13,6 +13,7 @@ Accelerometer, Camera, Compass, + Connector, DistanceSensor, Emitter, Gyro, @@ -45,6 +46,7 @@ class WebotsDevice: Accelerometer = Accelerometer Camera = Camera Compass = Compass + Connector = Connector DistanceSensor = DistanceSensor Emitter = Emitter GPS = GPS @@ -152,6 +154,6 @@ def add_jitter( std_dev = value * (std_dev_percent / 100.0) mean_offset = value * (offset_percent / 100.0) - error = value + gauss(mean_offset, std_dev) + error = gauss(mean_offset, std_dev) # Ensure the error is within the range return max(value_range[0], min(value_range[1], value + error)) diff --git a/simulator/modules/sbot_interface/setup.py b/simulator/modules/sbot_interface/setup.py index 5f022b0..b1b8dc6 100644 --- a/simulator/modules/sbot_interface/setup.py +++ b/simulator/modules/sbot_interface/setup.py @@ -26,8 +26,8 @@ from sbot_interface.devices.camera import Camera from sbot_interface.devices.led import Led, NullLed from sbot_interface.devices.motor import Motor -from sbot_interface.devices.power import NullBuzzer, Output, StartButton -from sbot_interface.devices.servo import NullServo +from sbot_interface.devices.power import ConnectorOutput, NullBuzzer, Output, StartButton +from sbot_interface.devices.servo import NullServo, Servo from sbot_interface.socket_server import Board, DeviceServer, SocketServer @@ -46,7 +46,10 @@ def setup_devices(log_level: int | str = logging.WARNING) -> SocketServer: # this is the configuration of devices connected to the robot devices: list[Board] = [ PowerBoard( - outputs=[Output() for _ in range(7)], + outputs=( + [ConnectorOutput('vacuum sucker')] + + [Output() for _ in range(6)] + ), buzzer=NullBuzzer(), button=StartButton(), leds=(NullLed(), NullLed()), @@ -60,7 +63,10 @@ def setup_devices(log_level: int | str = logging.WARNING) -> SocketServer: asset_tag='MOT', ), ServoBoard( - servos=[NullServo() for _ in range(8)], + servos=( + [Servo('vacuum sucker motor::main')] + + [NullServo() for _ in range(7)] + ), asset_tag='SERVO', ), LedBoard( diff --git a/simulator/protos/SR2025bot.proto b/simulator/protos/SR2025bot.proto new file mode 100755 index 0000000..c05edcc --- /dev/null +++ b/simulator/protos/SR2025bot.proto @@ -0,0 +1,204 @@ +#VRML_SIM R2023b utf8 +EXTERNPROTO "./robot/MotorAssembly.proto" +EXTERNPROTO "./robot/Caster.proto" +EXTERNPROTO "./robot/RobotCamera.proto" +EXTERNPROTO "./robot/UltrasoundModule.proto" +EXTERNPROTO "./robot/RGBLed.proto" +EXTERNPROTO "./robot/ReflectanceSensor.proto" +EXTERNPROTO "./robot/Flag.proto" +EXTERNPROTO "./robot/BumpSensor.proto" +EXTERNPROTO "./robot/VacuumSucker.proto" + +PROTO SR2025bot [ + field SFString name "" + field SFVec3f translation 0 0 0 + field SFRotation rotation 0 0 1 0 + field SFString controller "" + field MFString controllerArgs [] + field SFString customData "" + field SFColor flagColour 1 1 1 +] { + Robot { + name IS name + translation IS translation + rotation IS rotation + controller IS controller + controllerArgs IS controllerArgs + customData IS customData + children [ + Pose { + translation 0 0 0.049 + children [ + MotorAssembly { + name "left motor" + rotation 0 0 1 3.1415 + reversed TRUE + translation 0 0.14 0 + } + MotorAssembly { + name "right motor" + translation 0 -0.14 0 + } + Caster { + name "caster" + translation -0.15 0 -0.045 + } + DEF BASE Solid { + translation -0.065 0 -0.02 + children [ + Shape { + appearance PBRAppearance { + baseColor 0.757 0.604 0.424 + roughness 1 + metalness 0 + } + geometry Box { + size 0.25 0.25 0.02 + } + } + ] + name "Chassis" + boundingObject DEF BASE_GEO Box { + size 0.25 0.25 0.02 + } + physics Physics { + density 2000 # 66% Aluminium + } + } + DEF BOARD Solid { + translation -0.05 0 0 + rotation 0 0 1 1.5708 + children [ + Shape { + appearance PBRAppearance { + baseColor 0 0 0 + roughness 1 + metalness 0 + } + geometry Box { + size 0.08 0.06 0.02 + } + } + ] + name "Board" + } + DEF STABILISER Solid { + translation -0.16 0 0 + children [ + Shape { + appearance PBRAppearance { + baseColor 0.8 0.8 0.75 + roughness 1 + metalness 0 + } + geometry DEF WEIGHT_GEO Box { + size 0.04 0.15 0.02 + } + } + ] + name "Chassis weight" + boundingObject USE WEIGHT_GEO + physics Physics { + density 8000 # Steel + } + } + RobotCamera { + name "camera" + translation 0.05 0 0.03 + } + Solid { + translation 0.03 0 0 + children [ + Shape { + appearance PBRAppearance { + baseColor 0.4 0.4 0.4 + metalness 0 + } + geometry Box { + size 0.01 0.01 0.03 + } + } + ] + name "Camera riser" + } + VacuumSucker { + name "vacuum sucker" + translation 0.01 0 -0.02 + } + UltrasoundModule { + name "ultrasound front" + translation 0.04 0 0 + } + UltrasoundModule { + name "ultrasound left" + translation -0.08 0.12 0 + rotation 0 0 1 1.5708 + } + UltrasoundModule { + name "ultrasound back" + translation -0.18 0 0 + rotation 0 0 1 3.1416 + } + UltrasoundModule { + name "ultrasound right" + translation -0.08 -0.12 0 + rotation 0 0 1 -1.5708 + } + RGBLed { + name "led 1" + translation -0.11 0.08 -0.008 + } + RGBLed { + name "led 2" + translation -0.11 0 -0.008 + } + RGBLed { + name "led 3" + translation -0.11 -0.08 -0.008 + } + ReflectanceSensor { + name "left reflectance sensor" + translation 0.03 0.02 -0.03 + rotation 0 0 1 1.5708 + } + ReflectanceSensor { + name "center reflectance sensor" + translation 0.03 0 -0.03 + rotation 0 0 1 1.5708 + } + ReflectanceSensor { + name "right reflectance sensor" + translation 0.03 -0.02 -0.03 + rotation 0 0 1 1.5708 + } + BumpSensor { + name "front left bump sensor" + translation 0.06 0.06 -0.02 + } + BumpSensor { + name "front right bump sensor" + translation 0.06 -0.06 -0.02 + } + BumpSensor { + name "rear left bump sensor" + translation -0.19 0.06 -0.02 + } + BumpSensor { + name "rear right bump sensor" + translation -0.19 -0.06 -0.02 + } + Flag { + name "flag" + translation 0.03 0.07 0.09 + flagColour IS flagColour + } + ] + } + ] + boundingObject Pose { + translation -0.065 0 0.029 + children [USE BASE_GEO] + } + physics Physics {} + } +} diff --git a/simulator/protos/arena/Arena.proto b/simulator/protos/arena/Arena.proto index 01ebf22..0754203 100755 --- a/simulator/protos/arena/Arena.proto +++ b/simulator/protos/arena/Arena.proto @@ -59,6 +59,7 @@ PROTO Arena [ children [ Solid { # Floor translation 0 -0.002 0 + rotation 0 0 1 3.1416 children [ DEF FLOOR Shape { appearance Appearance { diff --git a/simulator/protos/arena/Pillar.proto b/simulator/protos/arena/Pillar.proto new file mode 100755 index 0000000..88388d6 --- /dev/null +++ b/simulator/protos/arena/Pillar.proto @@ -0,0 +1,76 @@ +#VRML_SIM R2023b utf8 +# template language: javascript +# tags: nonDeterministic + +EXTERNPROTO "../props/Marker.proto" + +PROTO Pillar [ + field SFVec3f translation 0 0 0 + field SFRotation rotation 0 1 0 0 + field SFVec3f size 0.13 0.13 0.13 + field SFVec2f {0.08 0.08, 0.15 0.15, 0.2 0.2} marker_size 0.08 0.08 + field SFFloat marker_height 0.065 + field SFColor colour 0.9 0.9 0.9 + field SFString marker "0" + field SFString model "" + field MFString texture_url [] +] +{ + Pose { + translation IS translation + rotation IS rotation + children [ + Solid { + translation 0 0 %<= fields.size.value.z / 2 >% + children [ + Shape { + appearance DEF PILLAR_APPEARANCE PBRAppearance { + baseColor IS colour + metalness 0 + roughness 1 + } + geometry DEF PILLAR_GEOMETRY Box { + size IS size + } + } + Marker { + translation 0 %<= fields.size.value.y / 2 + 0.001 >% %<= fields.marker_height.value - (fields.size.value.z / 2) >% + rotation 1 0 0 -1.5708 + size IS marker_size + name "front" + model IS marker + texture_url IS texture_url + } + Marker { + translation 0 %<= -(fields.size.value.y / 2 + 0.001) >% %<= fields.marker_height.value - (fields.size.value.z / 2) >% + rotation 1 0 0 1.5708 + size IS marker_size + name "back" + model IS marker + texture_url IS texture_url + } + Marker { + translation %<= fields.size.value.x / 2 + 0.001 >% 0 %<= fields.marker_height.value - (fields.size.value.z / 2) >% + rotation 0 1 0 1.5708 + size IS marker_size + name "side-1" + model IS marker + texture_url IS texture_url + } + Marker { + translation %<= -(fields.size.value.x / 2 + 0.001) >% 0 %<= fields.marker_height.value - (fields.size.value.z / 2) >% + rotation 0 1 0 -1.5708 + size IS marker_size + name "side-2" + model IS marker + texture_url IS texture_url + } + ] + name IS model + model IS model + boundingObject USE PILLAR_GEOMETRY + locked TRUE + } + ] + } +} diff --git a/simulator/protos/props/BoxToken.proto b/simulator/protos/props/BoxToken.proto index f84f25c..461d7fa 100755 --- a/simulator/protos/props/BoxToken.proto +++ b/simulator/protos/props/BoxToken.proto @@ -7,13 +7,15 @@ EXTERNPROTO "./Marker.proto" PROTO BoxToken [ field SFVec3f translation 0 0 0 field SFRotation rotation 0 1 0 0 - field SFVec3f size 0.12 0.12 0.12 + field SFVec3f size 0.13 0.13 0.13 field SFVec2f {0.08 0.08, 0.15 0.15, 0.2 0.2} marker_size 0.08 0.08 field SFColor colour 0.7 0.55 0.35 field SFString marker "0" field SFString model "" - field SFFloat mass 0.100 + field SFFloat mass 0.080 field MFString texture_url [] + field SFFloat connectorStrength 35 + field SFFloat connectorShear 20 ] { Solid { @@ -78,6 +80,39 @@ PROTO BoxToken [ model IS marker texture_url IS texture_url } + # Shape { + # appearance PBRAppearance { + # transparency 0.4 + # baseColor 1 0 0 + # } + # geometry Sphere { + # radius %<= fields.size.value.x / 2 * 1.4 >% + # subdivision 5 + # } + # } + Connector { + type "passive" + distanceTolerance %<= fields.size.value.x / 2 * 1.4 >% + axisTolerance 3.1415 + rotationTolerance 0 + numberOfRotations 0 + tensileStrength IS connectorStrength + shearStrength IS connectorShear + snap FALSE + name "Front Connector" + } + Connector { + rotation 0 0 1 3.1416 + type "passive" + distanceTolerance %<= fields.size.value.x / 2 * 1.4 >% + axisTolerance 3.1415 + rotationTolerance 0 + numberOfRotations 0 + tensileStrength IS connectorStrength + shearStrength IS connectorShear + snap FALSE + name "Rear Connector" + } ] name IS model model IS model diff --git a/simulator/protos/robot/BumpSensor.proto b/simulator/protos/robot/BumpSensor.proto index c2b8927..f567512 100755 --- a/simulator/protos/robot/BumpSensor.proto +++ b/simulator/protos/robot/BumpSensor.proto @@ -17,12 +17,12 @@ PROTO BumpSensor [ roughness 0.7 } geometry DEF BUMPER Box { - size 0.01 0.05 0.01 + size 0.01 0.07 0.01 } } ] boundingObject Box { - size 0.03 0.05 0.01 + size 0.03 0.07 0.01 } } } \ No newline at end of file diff --git a/simulator/protos/robot/VacuumSucker.proto b/simulator/protos/robot/VacuumSucker.proto new file mode 100644 index 0000000..6baffca --- /dev/null +++ b/simulator/protos/robot/VacuumSucker.proto @@ -0,0 +1,201 @@ +#VRML_SIM R2023b utf8 +# template language: javascript + +PROTO VacuumSucker [ + field SFString name "" + field SFVec3f translation 0 0 0 + field SFRotation rotation 0 0 1 0 + field SFFloat max_height 0.35 + field SFFloat forward_reach 0.12 +] { + Pose { + translation IS translation + rotation IS rotation + children [ + Pose { + translation 0 0 %<= fields.max_height.value / 4 >% + children [ + DEF BASE Solid { + children [ + Shape { + appearance PBRAppearance { + baseColor 0.7 0.7 0.7 + roughness 1 + metalness 0 + } + geometry DEF BASE_GEO Box { + size 0.06 0.06 %<= fields.max_height.value / 2 >% + } + } + ] + name "Tower Base" + boundingObject USE BASE_GEO + physics Physics { + density 500 # Hollow Aluminium + } + } + SliderJoint { + jointParameters JointParameters { + axis 0 0 1 + minStop 0 + maxStop IS max_height + position 0.01 + } + device [ + LinearMotor { + name %<= "\"" + fields.name.value + " motor::main\"" >% + minPosition 0 + maxPosition IS max_height + maxVelocity 2 + sound "" + } + PositionSensor { + name %<= "\"" + fields.name.value + " position sensor\"" >% + } + ] + endPoint Solid { + translation %<= (fields.forward_reach.value + 0.055) - 0.05 >% 0 %<= fields.max_height.value / 4 - 0.05 >% + children [ + Solid { + children [ + Pose { + translation %<= 0.025 - (fields.forward_reach.value + 0.055) / 2 >% 0 0.08 + children [ + Shape { # Horizontal arm + appearance PBRAppearance { + baseColor 0.7 0.7 0.7 + roughness 1 + metalness 0 + } + geometry Box { + size %<= fields.forward_reach.value + 0.055 >% 0.05 0.02 + } + } + ] + } + Pose { + translation %<= 0.05 - (fields.forward_reach.value + 0.055) >% 0 %<= 0.06 - (fields.max_height.value / 4) >% + children [ + Shape { # Column + appearance PBRAppearance { + baseColor 0.7 0.7 0.7 + roughness 1 + metalness 0 + } + geometry DEF COLUMN_GEO Box { + size 0.05 0.05 %<= fields.max_height.value / 2 + 0.02 >% + } + } + ] + } + Pose { + translation 0 0 0.045 + children [ + Shape { + appearance PBRAppearance { + baseColor 0.7 0.7 0.7 + roughness 1 + metalness 0 + } + geometry Box { + size 0.05 0.05 0.05 + } + } + ] + } + ] + name "Armature" + boundingObject Pose { + translation %<= 0.05 - (fields.forward_reach.value + 0.055) >% 0 %<= 0.06 - (fields.max_height.value / 4) >% + children [USE COLUMN_GEO] + } + physics Physics { + density 200 # Hollow Aluminium + } + } + DEF SUCKER Shape { + appearance PBRAppearance { + baseColor 0 0 0 + roughness 1 + metalness 1 + } + geometry DEF hook_geo Box { + size 0.05 0.05 0.04 + } + castShadows FALSE + } + Connector { + # Shift origin to near the lower face of the hook shape + translation 0 0 -0.01 + rotation 0 1 0 3.1416 + type "active" + distanceTolerance 0.094 # (0.14 / 2) * sqrt(2) + axisTolerance 3.1415 + rotationTolerance 0 + numberOfRotations 0 + tensileStrength 35 + shearStrength 20 + snap FALSE + autoLock TRUE + name IS name + unilateralUnlock TRUE + unilateralLock TRUE + } + ] + boundingObject Pose { + translation 0 0 0.005 + children [ + Box { + size 0.05 0.05 0.03 + } + ] + } + physics Physics { + density 1500 # rubber + } + } + } + # Secondary slider joint for telescoping column + SliderJoint { + jointParameters JointParameters { + axis 0 0 1 + minStop 0 + maxStop %<= fields.max_height.value / 2 >% + position 0.005 + } + device [ + LinearMotor { + name %<= "\"" + fields.name.value + " motor::extension\"" >% + minPosition 0 + maxPosition %<= fields.max_height.value / 2 >% + maxVelocity 1 + sound "" + multiplier 0.5 + } + ] + endPoint Solid { + translation 0 0 0.005 + children [ + Shape { + appearance PBRAppearance { + baseColor 0.7 0.7 0.7 + roughness 1 + metalness 0 + } + geometry DEF COLUMN_GEO Box { + size 0.055 0.055 %<= fields.max_height.value / 2 + 0.01 >% + } + } + ] + name "Extension" + boundingObject USE COLUMN_GEO + physics Physics { + density 200 # Hollow Aluminium + } + } + } + ] + } + ] + } +} \ No newline at end of file diff --git a/simulator/worlds/arena.wbt b/simulator/worlds/arena.wbt index 17e3fc0..321f53f 100755 --- a/simulator/worlds/arena.wbt +++ b/simulator/worlds/arena.wbt @@ -1,270 +1,550 @@ #VRML_SIM R2023b utf8 -EXTERNPROTO "https://raw.githubusercontent.com/cyberbotics/webots/R2023b/projects/objects/backgrounds/protos/TexturedBackgroundLight.proto" EXTERNPROTO "../protos/arena/Arena.proto" -EXTERNPROTO "../protos/arena/Deck.proto" -EXTERNPROTO "../protos/arena/TriangleDeck.proto" -EXTERNPROTO "../protos/props/Can.proto" +EXTERNPROTO "../protos/arena/Pillar.proto" +EXTERNPROTO "../protos/props/BoxToken.proto" EXTERNPROTO "../protos/props/Marker.proto" -EXTERNPROTO "../protos/SRObot.proto" +EXTERNPROTO "../protos/SR2025bot.proto" WorldInfo { basicTimeStep 8 } Viewpoint { orientation 0.43231 0.43231 -0.79134 1.80272 - position 0 9.1 13.8 + position 0 6.67 9.87 } DEF AMBIENT Background { skyColor [ 0.4 0.4 0.4 ] - luminosity 1.6 + luminosity 1 } -TexturedBackgroundLight { +DirectionalLight { + ambientIntensity 1 + direction -0.1 -0.2 -1 + color 0.95 0.95 1 + intensity 1.5 + on TRUE + castShadows TRUE } -SRObot { - name "robot" - translation 0.45 1.95 0 - rotation 0 0 1 3.1415 - flagColour 1 0 0 +DEF ROBOT0 SR2025bot { + name "robot0" + translation 2.375 -2.375 0 + rotation 0 0 1 2.3562 + flagColour 0 1 0 controllerArgs ["0"] controller "usercode_runner" customData "start" } - -Arena { - size 5.4 5.4 - locked TRUE - floorTexture ["arena_floor.png"] -} -Deck { - name "TL deck" - size 1.2192 1.2192 - translation 2.0904 -2.0904 0.085 - locked TRUE -} -Deck { - name "BR deck" - size 1.2192 1.2192 - translation -2.0904 2.0904 0.085 - locked TRUE -} -Deck { - name "CR deck" - size 1.2192 1.2192 - translation -0.6096 -0.6096 0.085 - locked TRUE +DEF ROBOT1 SR2025bot { + name "robot1" + translation -2.375 -2.375 0 + rotation 0 0 1 0.7854 + flagColour 1 0.5 0 + controllerArgs ["1"] + controller "usercode_runner" + customData "start" } -Deck { - name "CL deck" - size 1.2192 1.2192 - translation 0.6096 0.6096 0.085 - locked TRUE +DEF ROBOT2 SR2025bot { + name "robot2" + translation -2.375 2.375 0 + rotation 0 0 1 -0.7854 + flagColour 1 0 1 + controllerArgs ["2"] + controller "usercode_runner" + customData "start" } -TriangleDeck { - name "TR deck" - size 1.2192 1.2192 - translation -2.0904 -2.0904 0.085 - locked TRUE +DEF ROBOT3 SR2025bot { + name "robot3" + translation 2.375 2.375 0 + rotation 0 0 1 -2.3562 + flagColour 1 1 0 + controllerArgs ["3"] + controller "usercode_runner" + customData "start" } -TriangleDeck { - name "BL deck" - size 1.2192 1.2192 - translation 2.0904 2.0904 0.085 - rotation 0 0 1 3.14159 + +Arena { + size 5.75 5.75 locked TRUE + floorTexture ["arena_floor.png"] } -DEF CANS Pose { - translation 0 0 0.05 +DEF PILLARS Pose { children [ - Can { - name "can1" - translation -0.3 0.44 0 + Pillar { + translation 0.75 -0.75 0 + size 0.15 0.15 0.13 + marker "195" + model "pillar_0" + texture_url ["sim_markers/195.png"] } - Can { - name "can2" - translation -1.5 1.2 0 + Pillar { + translation -0.75 -0.75 0 + size 0.15 0.15 0.13 + marker "196" + model "pillar_1" + texture_url ["sim_markers/196.png"] } - Can { - name "can3" - translation -1.5892 0.06 0 + Pillar { + translation -0.75 0.75 0 + size 0.15 0.15 0.13 + marker "197" + model "pillar_2" + texture_url ["sim_markers/197.png"] } - Can { - name "can4" - translation -2.33 -0.06 0 + Pillar { + translation 0.75 0.75 0 + size 0.15 0.15 0.13 + marker "198" + model "pillar_3" + texture_url ["sim_markers/198.png"] } - Can { - name "can5" - translation -1.5 -1.5 0 + Pillar { + translation 0 0 0 + size 0.15 0.15 0.26 + marker "199" + model "pillar_centre" + texture_url ["sim_markers/199.png"] } + ] +} - Can { - name "can6" - translation 0.3 -0.44 0 +DEF TOKENS Pose { + translation 0 0 0.07 + children [ + # 104, 102, 119, 100, 110, 117 + DEF TOKEN0_1 BoxToken { + translation 0.3 -2.45 0 + colour 0 1 0 + marker "104" + model "T104" + texture_url ["sim_markers/104.png"] + } + DEF TOKEN0_2 BoxToken { + translation 0.3 -2.05 0 + colour 0 1 0 + marker "102" + model "T102" + texture_url ["sim_markers/102.png"] + } + DEF TOKEN0_3 BoxToken { + translation 0.3 -1.65 0 + colour 0 1 0 + marker "119" + model "T119" + texture_url ["sim_markers/119.png"] + } + DEF TOKEN0_4 BoxToken { + translation 2.45 -0.3 0 + colour 0 1 0 + marker "100" + model "T100" + texture_url ["sim_markers/100.png"] + } + DEF TOKEN0_5 BoxToken { + translation 2.05 -0.3 0 + colour 0 1 0 + marker "110" + model "T110" + texture_url ["sim_markers/110.png"] + } + DEF TOKEN0_6 BoxToken { + translation 1.65 -0.3 0 + colour 0 1 0 + marker "117" + model "T117" + texture_url ["sim_markers/117.png"] + } + # 122, 121, 133, 134, 127, 131 + DEF TOKEN1_1 BoxToken { + translation -0.3 -2.45 0 + colour 1 0.5 0 + marker "122" + model "T122" + texture_url ["sim_markers/122.png"] + } + DEF TOKEN1_2 BoxToken { + translation -0.3 -2.05 0 + colour 1 0.5 0 + marker "121" + model "T121" + texture_url ["sim_markers/121.png"] + } + DEF TOKEN1_3 BoxToken { + translation -0.3 -1.65 0 + colour 1 0.5 0 + marker "133" + model "T133" + texture_url ["sim_markers/133.png"] + } + DEF TOKEN1_4 BoxToken { + translation -2.45 -0.3 0 + colour 1 0.5 0 + marker "134" + model "T134" + texture_url ["sim_markers/134.png"] + } + DEF TOKEN1_5 BoxToken { + translation -2.05 -0.3 0 + colour 1 0.5 0 + marker "127" + model "T127" + texture_url ["sim_markers/127.png"] } - Can { - name "can7" - translation 1.5 -1.2 0 + DEF TOKEN1_6 BoxToken { + translation -1.65 -0.3 0 + colour 1 0.5 0 + marker "131" + model "T131" + texture_url ["sim_markers/131.png"] } - Can { - name "can8" - translation 1.5892 -0.06 0 + # 145, 146, 152, 157, 151, 156 + DEF TOKEN2_1 BoxToken { + translation -0.3 2.45 0 + colour 1 0 1 + marker "145" + model "T145" + texture_url ["sim_markers/145.png"] } - Can { - name "can9" - translation 2.33 0.06 0 + DEF TOKEN2_2 BoxToken { + translation -0.3 2.05 0 + colour 1 0 1 + marker "146" + model "T146" + texture_url ["sim_markers/146.png"] } - Can { - name "can10" - translation 1.5 1.5 0 + DEF TOKEN2_3 BoxToken { + translation -0.3 1.65 0 + colour 1 0 1 + marker "152" + model "T152" + texture_url ["sim_markers/152.png"] + } + DEF TOKEN2_4 BoxToken { + translation -2.45 0.3 0 + colour 1 0 1 + marker "157" + model "T157" + texture_url ["sim_markers/157.png"] + } + DEF TOKEN2_5 BoxToken { + translation -2.05 0.3 0 + colour 1 0 1 + marker "151" + model "T151" + texture_url ["sim_markers/151.png"] + } + DEF TOKEN2_6 BoxToken { + translation -1.65 0.3 0 + colour 1 0 1 + marker "156" + model "T156" + texture_url ["sim_markers/156.png"] + } + # 160, 169, 178, 176, 161, 179 + DEF TOKEN3_1 BoxToken { + translation 0.3 2.45 0 + colour 1 1 0 + marker "160" + model "T160" + texture_url ["sim_markers/160.png"] + } + DEF TOKEN3_2 BoxToken { + translation 0.3 2.05 0 + colour 1 1 0 + marker "169" + model "T169" + texture_url ["sim_markers/169.png"] + } + DEF TOKEN3_3 BoxToken { + translation 0.3 1.65 0 + colour 1 1 0 + marker "178" + model "T178" + texture_url ["sim_markers/178.png"] + } + DEF TOKEN3_4 BoxToken { + translation 2.45 0.3 0 + colour 1 1 0 + marker "176" + model "T176" + texture_url ["sim_markers/176.png"] + } + DEF TOKEN3_5 BoxToken { + translation 2.05 0.3 0 + colour 1 1 0 + marker "161" + model "T161" + texture_url ["sim_markers/161.png"] + } + DEF TOKEN3_6 BoxToken { + translation 1.65 0.3 0 + colour 1 1 0 + marker "179" + model "T179" + texture_url ["sim_markers/179.png"] } ] } -Marker { - name "A0" - model "0" - size 0.1 0.1 - translation -1.4798 2.29 0.07 - rotation 0 0 1 1.5708 - texture_url ["sim_markers/0.png"] - upright TRUE -} -Marker { - name "A1" - model "1" - size 0.1 0.1 - translation -1.4798 1.99 0.07 - rotation 0 0 1 1.5708 - texture_url ["sim_markers/1.png"] - upright TRUE -} -Marker { - name "A2" - model "2" - size 0.1 0.1 - translation -0.4192 0.001 0.07 - rotation 0 0 1 3.1415 - texture_url ["sim_markers/2.png"] - upright TRUE -} -Marker { - name "A3" - model "3" - size 0.1 0.1 - translation -0.7192 0.001 0.07 - rotation 0 0 1 3.1415 - texture_url ["sim_markers/3.png"] - upright TRUE -} -Marker { - name "A4" - model "4" - size 0.1 0.1 - translation -2.699 0.91 0.07 - rotation 0 0 1 1.5708 - texture_url ["sim_markers/4.png"] - upright TRUE -} -Marker { - name "A5" - model "5" - size 0.1 0.1 - translation -2.699 0.61 0.07 - rotation 0 0 1 1.5708 - texture_url ["sim_markers/5.png"] - upright TRUE -} -Marker { - name "A6" - model "6" - size 0.1 0.1 - translation -2.19545 -1.98335 0.07 - rotation 0 0 1 2.3561 - texture_url ["sim_markers/6.png"] - upright TRUE -} -Marker { - name "A7" - model "7" - size 0.1 0.1 - translation -1.98335 -2.19545 0.07 - rotation 0 0 1 2.3561 - texture_url ["sim_markers/7.png"] - upright TRUE -} - -Marker { - name "B0" - model "0" - size 0.1 0.1 - translation 1.4798 -2.29 0.07 - rotation 0 0 1 -1.5708 - texture_url ["sim_markers/0.png"] - upright TRUE -} -Marker { - name "B1" - model "1" - size 0.1 0.1 - translation 1.4798 -1.99 0.07 - rotation 0 0 1 -1.5708 - texture_url ["sim_markers/1.png"] - upright TRUE -} -Marker { - name "B2" - model "2" - size 0.1 0.1 - translation 0.4192 -0.001 0.07 - rotation 0 0 1 0 - texture_url ["sim_markers/2.png"] - upright TRUE -} -Marker { - name "B3" - model "3" - size 0.1 0.1 - translation 0.7192 -0.001 0.07 - rotation 0 0 1 0 - texture_url ["sim_markers/3.png"] - upright TRUE -} -Marker { - name "B4" - model "4" - size 0.1 0.1 - translation 2.699 -0.81 0.07 - rotation 0 0 1 -1.5708 - texture_url ["sim_markers/4.png"] - upright TRUE -} -Marker { - name "B5" - model "5" - size 0.1 0.1 - translation 2.699 -0.51 0.07 - rotation 0 0 1 -1.5708 - texture_url ["sim_markers/5.png"] - upright TRUE -} -Marker { - name "B6" - model "6" - size 0.1 0.1 - translation 2.19545 1.98335 0.07 - rotation 0 0 1 -0.7853 - texture_url ["sim_markers/6.png"] - upright TRUE -} -Marker { - name "B7" - model "7" - size 0.1 0.1 - translation 1.98335 2.19545 0.07 - rotation 0 0 1 -0.7853 - texture_url ["sim_markers/7.png"] - upright TRUE +DEF WALL_MARKERS Pose { + children [ + # North wall + Marker { + name "A0" + model "0" + size 0.15 0.15 + translation 2.15625 -2.874 0.125 + rotation 0 0 1 3.1415 + texture_url ["sim_markers/0.png"] + upright TRUE + } + Marker { + name "A1" + model "1" + size 0.15 0.15 + translation 1.4375 -2.874 0.125 + rotation 0 0 1 3.1415 + texture_url ["sim_markers/1.png"] + upright TRUE + } + Marker { + name "A2" + model "2" + size 0.15 0.15 + translation 0.71875 -2.874 0.125 + rotation 0 0 1 3.1415 + texture_url ["sim_markers/2.png"] + upright TRUE + } + Marker { + name "A3" + model "3" + size 0.15 0.15 + translation 0 -2.874 0.125 + rotation 0 0 1 3.1415 + texture_url ["sim_markers/3.png"] + upright TRUE + } + Marker { + name "A4" + model "4" + size 0.15 0.15 + translation -0.71875 -2.874 0.125 + rotation 0 0 1 3.1415 + texture_url ["sim_markers/4.png"] + upright TRUE + } + Marker { + name "A5" + model "5" + size 0.15 0.15 + translation -1.4375 -2.874 0.125 + rotation 0 0 1 3.1415 + texture_url ["sim_markers/5.png"] + upright TRUE + } + Marker { + name "A6" + model "6" + size 0.15 0.15 + translation -2.15625 -2.874 0.125 + rotation 0 0 1 3.1415 + texture_url ["sim_markers/6.png"] + upright TRUE + } + # East wall + Marker { + name "A7" + model "7" + size 0.15 0.15 + translation -2.874 -2.15625 0.125 + rotation 0 0 1 1.5708 + texture_url ["sim_markers/7.png"] + upright TRUE + } + Marker { + name "A8" + model "8" + size 0.15 0.15 + translation -2.874 -1.4375 0.125 + rotation 0 0 1 1.5708 + texture_url ["sim_markers/8.png"] + upright TRUE + } + Marker { + name "A9" + model "9" + size 0.15 0.15 + translation -2.874 -0.71875 0.125 + rotation 0 0 1 1.5708 + texture_url ["sim_markers/9.png"] + upright TRUE + } + Marker { + name "A10" + model "10" + size 0.15 0.15 + translation -2.874 0 0.125 + rotation 0 0 1 1.5708 + texture_url ["sim_markers/10.png"] + upright TRUE + } + Marker { + name "A11" + model "11" + size 0.15 0.15 + translation -2.874 0.71875 0.125 + rotation 0 0 1 1.5708 + texture_url ["sim_markers/11.png"] + upright TRUE + } + Marker { + name "A12" + model "12" + size 0.15 0.15 + translation -2.874 1.4375 0.125 + rotation 0 0 1 1.5708 + texture_url ["sim_markers/12.png"] + upright TRUE + } + Marker { + name "A13" + model "13" + size 0.15 0.15 + translation -2.874 2.15625 0.125 + rotation 0 0 1 1.5708 + texture_url ["sim_markers/13.png"] + upright TRUE + } + # South wall + Marker { + name "A14" + model "14" + size 0.15 0.15 + translation -2.15625 2.874 0.125 + rotation 0 0 1 0 + texture_url ["sim_markers/14.png"] + upright TRUE + } + Marker { + name "A15" + model "15" + size 0.15 0.15 + translation -1.4375 2.874 0.125 + rotation 0 0 1 0 + texture_url ["sim_markers/15.png"] + upright TRUE + } + Marker { + name "A16" + model "16" + size 0.15 0.15 + translation -0.71875 2.874 0.125 + rotation 0 0 1 0 + texture_url ["sim_markers/16.png"] + upright TRUE + } + Marker { + name "A17" + model "17" + size 0.15 0.15 + translation 0 2.874 0.125 + rotation 0 0 1 0 + texture_url ["sim_markers/17.png"] + upright TRUE + } + Marker { + name "A18" + model "18" + size 0.15 0.15 + translation 0.71875 2.874 0.125 + rotation 0 0 1 0 + texture_url ["sim_markers/18.png"] + upright TRUE + } + Marker { + name "A19" + model "19" + size 0.15 0.15 + translation 1.4375 2.874 0.125 + rotation 0 0 1 0 + texture_url ["sim_markers/19.png"] + upright TRUE + } + Marker { + name "A20" + model "20" + size 0.15 0.15 + translation 2.15625 2.874 0.125 + rotation 0 0 1 0 + texture_url ["sim_markers/20.png"] + upright TRUE + } + # # West wall + Marker { + name "A21" + model "21" + size 0.15 0.15 + translation 2.874 2.15625 0.125 + rotation 0 0 1 -1.5708 + texture_url ["sim_markers/21.png"] + upright TRUE + } + Marker { + name "A22" + model "22" + size 0.15 0.15 + translation 2.874 1.4375 0.125 + rotation 0 0 1 -1.5708 + texture_url ["sim_markers/22.png"] + upright TRUE + } + Marker { + name "A23" + model "23" + size 0.15 0.15 + translation 2.874 0.71875 0.125 + rotation 0 0 1 -1.5708 + texture_url ["sim_markers/23.png"] + upright TRUE + } + Marker { + name "A24" + model "24" + size 0.15 0.15 + translation 2.874 0 0.125 + rotation 0 0 1 -1.5708 + texture_url ["sim_markers/24.png"] + upright TRUE + } + Marker { + name "A25" + model "25" + size 0.15 0.15 + translation 2.874 -0.71875 0.125 + rotation 0 0 1 -1.5708 + texture_url ["sim_markers/25.png"] + upright TRUE + } + Marker { + name "A26" + model "26" + size 0.15 0.15 + translation 2.874 -1.4375 0.125 + rotation 0 0 1 -1.5708 + texture_url ["sim_markers/26.png"] + upright TRUE + } + Marker { + name "A27" + model "27" + size 0.15 0.15 + translation 2.874 -2.15625 0.125 + rotation 0 0 1 -1.5708 + texture_url ["sim_markers/27.png"] + upright TRUE + } + ] } diff --git a/simulator/worlds/arena_floor.png b/simulator/worlds/arena_floor.png index 73809dc..f0fa347 100755 Binary files a/simulator/worlds/arena_floor.png and b/simulator/worlds/arena_floor.png differ