Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 17 additions & 13 deletions .github/workflows/check.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,29 +4,32 @@ on:
push:
workflow_dispatch:

env:
WEBOTS_VER: "2025a"

jobs:
test:
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest]
py_version: ["3.8", "3.9", "3.10", "3.11"]
py_version: ["3.9", "3.10", "3.11", "3.12", "3.13", "3.14"]
include:
- os: windows-latest
py_version: "3.8"
py_version: "3.10"
- os: windows-latest
py_version: "3.11"
py_version: "3.13"
- os: macos-latest
py_version: "3.8"
py_version: "3.10"
- os: macos-latest
py_version: "3.11"
py_version: "3.13"
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v6
with:
fetch-depth: 0
- name: Set up Python
uses: actions/setup-python@v5
uses: actions/setup-python@v6
with:
python-version: ${{ matrix.py_version }}
- name: Install dependencies
Expand All @@ -36,8 +39,9 @@ jobs:
- name: Download & install Webots (Linux)
if: runner.os == 'Linux'
run: |
sudo apt-get update
wget -O ./webots.deb \
https://github.com/cyberbotics/webots/releases/download/R2023b/webots_2023b_amd64.deb
https://github.com/cyberbotics/webots/releases/download/R$WEBOTS_VER/webots_${WEBOTS_VER}_amd64.deb
sudo apt-get install --yes ./webots.deb
- name: Download & extract Webots (Windows)
# Windows install was problematic so we just extract the python library for typehints
Expand All @@ -46,14 +50,14 @@ jobs:
run: |
mkdir stubs
C:\\msys64\\usr\\bin\\wget.exe -O ./webots.tar.bz2 \
https://github.com/cyberbotics/webots/releases/download/R2023b/webots-R2023b-x86-64.tar.bz2
https://github.com/cyberbotics/webots/releases/download/R$WEBOTS_VER/webots-R$WEBOTS_VER-x86-64.tar.bz2
C:\\msys64\\usr\\bin\\tar.exe xvf webots.tar.bz2 --strip-components=4 \
--directory=stubs webots/lib/controller/python/controller
- name: Download & install Webots (macOS)
if: runner.os == 'macOS'
run: |
wget -O ./webots.dmg \
https://github.com/cyberbotics/webots/releases/download/R2023b/webots-R2023b.dmg
https://github.com/cyberbotics/webots/releases/download/R$WEBOTS_VER/webots-R$WEBOTS_VER.dmg
hdiutil mount ./webots.dmg
sudo cp -R /Volumes/Webots/Webots.app /Applications
hdiutil unmount /Volumes/Webots
Expand All @@ -74,11 +78,11 @@ jobs:
release:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v6
with:
fetch-depth: 0
- name: Set up Python 3.10
uses: actions/setup-python@v5
uses: actions/setup-python@v6
with:
python-version: "3.10"
- name: Install release dependencies
Expand All @@ -99,7 +103,7 @@ jobs:
unzip dist/*.zip -d dist/
rm dist/sbot-simulator*.zip
- name: Save built release
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v6
with:
name: ${{ steps.release.outputs.RELEASE_NAME }}
path: |
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -167,3 +167,4 @@ cython_debug/
/simulator/controllers/competition_supervisor/runtime.ini
/zone_*
/dist
/uv.lock
2 changes: 0 additions & 2 deletions example_robots/basic_robot.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
from sbot import arduino, motors, utils

# robot = Robot()

motors.set_power(0, 1)
motors.set_power(1, 1)

Expand Down
4 changes: 2 additions & 2 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
sbot==2025.1.1
april_vision==3.0.0
sbot==2026.1.0
april_vision==3.1.0
opencv-python-headless >=4.10,<5
1 change: 1 addition & 0 deletions scripts/generate_release.py
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@

script_dir = temp_dir / "scripts"
script_dir.mkdir()
shutil.copy(project_root / "scripts/setup_python_fix.py", script_dir)
logger.info("Copying example code to temp directory")
shutil.copytree(project_root / "example_robots", temp_dir / "example_robots")

Expand Down
16 changes: 13 additions & 3 deletions scripts/run_simulator.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@
from shutil import which
from subprocess import Popen

BOLD_RED = '\x1b[31;1m'
RESET_COLOUR = '\x1b[0m'


if sys.platform == "win32":
from subprocess import CREATE_NEW_PROCESS_GROUP, DETACHED_PROCESS

Expand Down Expand Up @@ -51,6 +55,10 @@ def get_webots_parameters() -> tuple[Path, Path]:
if not (SIM_BASE / "venv").exists():
raise RuntimeError("Please run the setup.py script before running the simulator.")

# Check setup finish successfully
if not (SIM_BASE / "venv/setup_success").exists():
raise RuntimeError("Setup has not completed successfully. Please re-run the setup.py script.")

# Check if Webots is in the PATH
webots = which("webots")

Expand Down Expand Up @@ -86,13 +94,15 @@ def main() -> None:
else:
Popen([str(webots), str(world_file)], start_new_session=True)
except RuntimeError as e:
print(f"An error occurred: {e}")
input("Press enter to continue...")
print(BOLD_RED)
print(f"An error occurred: \n{e}")
input(f"Press enter to continue...{RESET_COLOUR}")
exit(1)
except Exception as e:
print(BOLD_RED)
print(f"An error occurred: {e}")
print(traceback.format_exc())
input("Press enter to continue...")
input(f"Press enter to continue...{RESET_COLOUR}")
exit(1)


Expand Down
48 changes: 34 additions & 14 deletions scripts/setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
3. Set the python path in runtime.ini to the virtual environment python
4. Repopulate the zone 0 folder with basic_robot.py if robot.py is missing
"""

from __future__ import annotations

import logging
Expand All @@ -16,11 +17,14 @@
import sys
from pathlib import Path
from subprocess import SubprocessError, check_call
from venv import create

logging.basicConfig(level=logging.INFO, format="[%(asctime)s] %(levelname)s: %(message)s")
logger = logging.getLogger(__name__)

BOLD_RED = "\x1b[31;1m"
GREEN = "\x1b[32;20m"
RESET_COLOUR = "\x1b[0m"


def populate_python_config(runtime_ini: Path, venv_python: Path) -> None:
"""
Expand Down Expand Up @@ -50,18 +54,20 @@ def populate_python_config(runtime_ini: Path, venv_python: Path) -> None:
elif not in_python_section:
runtime_content.append(line)

runtime_content.extend([
"",
"[python]",
f"COMMAND = {venv_python.absolute()}",
"",
])
runtime_content.extend(
[
"",
"[python]",
f"COMMAND = {venv_python.absolute()}",
"",
]
)

runtime_ini.write_text('\n'.join(runtime_content))
runtime_ini.write_text("\n".join(runtime_content))


try:
if (Path(__file__).parent / 'simulator/VERSION').exists():
if (Path(__file__).parent / "simulator/VERSION").exists():
# This is running from a release
print("Running in release mode")
project_root = Path(__file__).parent
Expand All @@ -76,8 +82,11 @@ def populate_python_config(runtime_ini: Path, venv_python: Path) -> None:

venv_dir = project_root / "venv"

# Reset success flag
(venv_dir / "setup_success").unlink(missing_ok=True)

logger.info(f"Creating virtual environment in {venv_dir.absolute()}")
create(venv_dir, with_pip=True)
check_call([sys.executable, "-m", "venv", venv_dir])

logger.info(f"Installing dependencies from {requirements.absolute()}")
if platform.system() == "Windows":
Expand All @@ -90,7 +99,13 @@ def populate_python_config(runtime_ini: Path, venv_python: Path) -> None:
[str(venv_python), "-m", "pip", "install", "--upgrade", "pip", "setuptools", "wheel"],
cwd=venv_dir,
)
check_call([str(pip), "install", "-r", str(requirements)], cwd=venv_dir)
check_call(
[str(pip), "install", "--only-binary=:all:", "-r", str(requirements)],
cwd=venv_dir
)

logger.info("Preloading OpenCV")
check_call([str(venv_python), "-c", "import cv2"], cwd=venv_dir)

logger.info("Setting up Webots Python location")

Expand All @@ -100,17 +115,22 @@ def populate_python_config(runtime_ini: Path, venv_python: Path) -> None:
populate_python_config(usercode_ini, venv_python)
populate_python_config(supervisor_ini, venv_python)

# Mark that we succeeded
(venv_dir / "setup_success").touch()

# repopulate zone 0 with example code if robot.py is missing
zone_0 = project_root / "zone_0"
if not (zone_0 / "robot.py").exists():
logger.info("Repopulating zone 0 with example code")
zone_0.mkdir(exist_ok=True)
shutil.copy(project_root / "example_robots/basic_robot.py", zone_0 / "robot.py")
except SubprocessError:
print(BOLD_RED)
logger.error("Setup failed due to an error.")
input("An error occurred, press enter to close.")
input(f"An error occurred, press enter to close.{RESET_COLOUR}")
except Exception:
print(BOLD_RED)
logger.exception("Setup failed due to an error.")
input("An error occurred, press enter to close.")
input(f"An error occurred, press enter to close.{RESET_COLOUR}")
else:
input("Setup complete, press enter to close.")
input(f"{GREEN}Setup complete, press enter to close.{RESET_COLOUR}")
66 changes: 66 additions & 0 deletions scripts/setup_python_fix.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
#!/usr/bin/env python3
"""
A script to setup the environment for running the project in Webots.

It will:
1. Create a setup virtual environment and install uv into it
2. Use uv to run the standard setup using the desired Python version
"""
import logging
import platform
import sys
from pathlib import Path
from subprocess import SubprocessError, check_call

logging.basicConfig(level=logging.INFO, format="[%(asctime)s] %(levelname)s: %(message)s")
logger = logging.getLogger(__name__)

BOLD_RED = '\x1b[31;1m'
GREEN = '\x1b[32;20m'
RESET_COLOUR = '\x1b[0m'

PYTHON_VERSION = "3.13"

try:
if (Path(__file__).parent / 'simulator/VERSION').exists():
# This is running from a release
print("Running in release mode")
project_root = Path(__file__).parent
else:
# This is running from the repository
print("Running in development mode")
project_root = Path(__file__).parents[1]

print(f"Starting with python version: {sys.version} on {platform.platform()}")

venv_dir = project_root / "simulator/setup_venv"
script_dir = Path(__file__).parent

check_call([sys.executable, "-m", "venv", venv_dir])

logger.info("Installing uv")
if platform.system() == "Windows":
venv_bin_dir = venv_dir / "Scripts"
pip = venv_bin_dir / "pip.exe"
uv_bin = venv_bin_dir / "uv.exe"
else:
venv_bin_dir = venv_dir / "bin"
pip = venv_bin_dir / "pip"
uv_bin = venv_bin_dir / "uv"

check_call(
[pip, "install", "--only-binary=:all:", "--upgrade", "wheel", "uv"],
cwd=venv_dir,
)

logger.info(f"Running setup using Python {PYTHON_VERSION}")
setup_script = script_dir.relative_to(project_root) / "setup.py"
check_call([uv_bin, "run", "--python", PYTHON_VERSION, setup_script], cwd=project_root)
except SubprocessError:
print(BOLD_RED)
logger.error("Setup failed due to an error.")
input(f"An error occurred, press enter to close.{RESET_COLOUR}")
except Exception:
print(BOLD_RED)
logger.exception("Setup failed due to an error.")
input(f"An error occurred, press enter to close.{RESET_COLOUR}")
Binary file added simulator/worlds/Arena.afphoto
Binary file not shown.
Binary file modified simulator/worlds/arena_floor.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.