diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 26a0e894..86c59e1b 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -15,7 +15,7 @@ env: jobs: build-and-push-image: name: Build and push image - runs-on: self-hosted + runs-on: [self-hosted, build] outputs: version: ${{ steps.build.version.outputs.version }} permissions: @@ -35,6 +35,18 @@ jobs: - name: Set up Docker Buildx uses: docker/setup-buildx-action@v2 + - name: Cache Docker layers + uses: actions/cache@v4 + with: + path: | + /tmp/.buildx-cache/cache/test + /tmp/.buildx-cache/cache/latest + /tmp/.buildx-cache/cache-new/test + /tmp/.buildx-cache/cache-new/latest + key: ${{ runner.os }}-buildx-${{ github.sha }} + restore-keys: | + ${{ runner.os }}-buildx- + - name: Log in to the Container registry uses: docker/login-action@v2 with: @@ -42,15 +54,6 @@ jobs: username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - - name: Create cache directory - run: | - mkdir -p ./.buildx-cache/cache - mkdir ./.buildx-cache/cache-new - mkdir ./.buildx-cache/cache/test - mkdir ./.buildx-cache/cache/latest - mkdir ./.buildx-cache/cache-new/test - mkdir ./.buildx-cache/cache-new/latest - - name: Test build if: github.event_name == 'pull_request' uses: docker/build-push-action@v3 @@ -59,8 +62,8 @@ jobs: file: ./build/docker/agent/Dockerfile load: true tags: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME}}:test - cache-from: type=local,src=./.buildx-cache/cache/test/ - cache-to: type=local,dest=./.buildx-cache/cache-new/test/,mode=max + cache-from: type=local,src=/tmp/.buildx-cache/cache/test/ + cache-to: type=local,dest=/tmp/.buildx-cache/cache-new/test/,mode=max build-args: | USERNAME=paf USER_UID=1000 @@ -76,31 +79,51 @@ jobs: push: true # tag 'latest' and version on push to main, otherwise use the commit hash tags: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest - cache-from: type=local,src=./.buildx-cache/cache/latest/ - cache-to: type=local,dest=./.buildx-cache/cache-new/latest/,mode=max + cache-from: type=local,src=/tmp/.buildx-cache/cache/latest/ + cache-to: type=local,dest=/tmp/.buildx-cache/cache-new/latest/,mode=max build-args: | USERNAME=paf USER_UID=1000 USER_GID=1000 - - name: Save PR ID + - name: Save pull request artifact if: github.event_name == 'pull_request' env: PR_ID: ${{ github.event.number }} run: | - mkdir -p ./pr - echo $PR_ID > ./pr/pr_id + mkdir -p ./artifact + printf '{ + "is_pr": true, + "pr_id": $PR_ID + }' >> ./artifact/artifact.json - - name: Upload PR ID - if: github.event_name == 'pull_request' + - name: Save merge artifact + if: github.event_name != 'pull_request' + run: | + mkdir -p ./artifact + printf '{ + "is_pr": false, + "pr_id": -1 + }' >> ./artifact/artifact.json + + - name: Upload artifact uses: actions/upload-artifact@v4 with: - name: pr_id - path: pr/ + name: artifact + path: ./artifact/artifact.json retention-days: 1 - - name: Clean up cache + - name: Clean up PR cache + if: github.event_name == 'pull_request' + run: | + rm -rf /tmp/.buildx-cache/cache/test + mv /tmp/.buildx-cache/cache-new/test /tmp/.buildx-cache/cache/test + + - name: Clean up merge cache + if: github.event_name != 'pull_request' run: | - rm -rf ./.buildx-cache/cache/test - rm -rf ./.buildx-cache/cache/latest - mv ./.buildx-cache/cache-new ./.buildx-cache/cache \ No newline at end of file + rm -rf /tmp/.buildx-cache/cache/latest + mv /tmp/.buildx-cache/cache-new/latest /tmp/.buildx-cache/cache/latest + + - name: Prune all images older than 1 days from self-hosted runner + run: docker image prune -a -f --filter "until=24h" \ No newline at end of file diff --git a/.github/workflows/drive.yml b/.github/workflows/drive.yml index 933fb9a9..3f2e0761 100644 --- a/.github/workflows/drive.yml +++ b/.github/workflows/drive.yml @@ -8,7 +8,7 @@ on: jobs: drive: - runs-on: self-hosted + runs-on: [self-hosted, drive] env: AGENT_VERSION: latest COMPOSE_FILE: ./build/docker-compose.cicd.yaml @@ -20,47 +20,18 @@ jobs: run: | echo "AGENT_VERSION=${AGENT_VERSION}" echo "COMPOSE_FILE=${COMPOSE_FILE}" - - name: 'Download artifact (PR ID)' - if: github.event_name == 'pull_request' - uses: actions/github-script@v6 + - name: Download artifact + uses: actions/download-artifact@v4 with: - script: | - let allArtifacts = await github.rest.actions.listWorkflowRunArtifacts({ - owner: context.repo.owner, - repo: context.repo.repo, - run_id: context.payload.workflow_run.id, - }); - let matchArtifact = allArtifacts.data.artifacts.filter((artifact) => { - return artifact.name == "pr_id" - })[0]; - if (!matchArtifact) { - core.setFailed('No pr_id artifact found from the build workflow'); - return; - } - let download = await github.rest.actions.downloadArtifact({ - owner: context.repo.owner, - repo: context.repo.repo, - artifact_id: matchArtifact.id, - archive_format: 'zip', - }); - let fs = require('fs'); - fs.writeFileSync(`${process.env.GITHUB_WORKSPACE}/pr_id.zip`, Buffer.from(download.data)); - - - name: 'Unzip artifact (PR ID)' - if: github.event_name == 'pull_request' - run: | - unzip pr_id.zip - - - name: Check PR ID - if: github.event_name == 'pull_request' + name: artifact + - name: Return artifact JSON + id: return-artifact-json uses: actions/github-script@v6 with: script: | - let issue_number = fs.readFileSync('./pr_id'); - if (!issue_number || isNaN(Number(issue_number))) { - core.setFailed(`Invalid PR ID: ${prIdContent}`); - return; - } + let fs = require('fs'); + let data = JSON.parse(fs.readFileSync('${process.env.GITHUB_WORKSPACE}/artifacts.json')); + return data; - name: Run docker-compose run: | @@ -73,12 +44,10 @@ jobs: if: always() run: docker compose down -v # add rendered JSON as comment to the pull request - - name: Add simulation results as comment - if: github.event_name == 'pull_request' + - name: Create simulation results table + id: simulation-results uses: actions/github-script@v6 with: - github-token: ${{ secrets.GITHUB_TOKEN }} - # this script reads the simulation_results.json and creates a comment on the pull request with the results. script: | const fs = require('fs'); // read the simulation results @@ -94,13 +63,26 @@ jobs: let resultsTableDivider = `| --- | --- |`; // add everything to the resultsTable resultsTable = resultsTableHeader + '\n' + resultsTableDivider + '\n' + resultsTable.join('\n'); + return resultsTable; + result-encoding: string + - name: Print simulation results + run: | + echo "Simulation results\n" + echo "${{ steps.simulation-results.outputs.result }}" + - name: Add simulation results as comment + if: ${{ steps.return-artifact-json.outputs.result.is_pr }} + uses: actions/github-script@v6 + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + # this script reads the simulation_results.json and creates a comment on the pull request with the results. + script: | + let issue_number = Number(${{ steps.return-artifact-json.outputs.pr_id }}); // add the results as a comment to the pull request - let issue_number = Number(fs.readFileSync('./pr_id')); github.rest.issues.createComment({ issue_number: issue_number, owner: context.repo.owner, repo: context.repo.repo, - body: "## Simulation results\n" + resultsTable + body: "## Simulation results\n" + ${{ steps.simulation-results.outputs.result }} }); - - name: Prune all images older than 30 days from self-hosted runner - run: docker image prune -a --force --filter "until=720h" \ No newline at end of file + - name: Prune all images older than 1 days from self-hosted runner + run: docker image prune -a --filter "until=24h" \ No newline at end of file diff --git a/doc/README.md b/doc/README.md index 7546ccb8..197a48bd 100644 --- a/doc/README.md +++ b/doc/README.md @@ -2,16 +2,15 @@ This document provides an overview of the structure of the documentation. -- [PAF Documentation](#paf-documentation) - - [`general`](#general) - - [`development`](#development) - - [`research`](#research) - - [`examples`](#examples) - - [`perception`](#perception) - - [`planning`](#planning) - - [`acting`](#acting) - - [`assets`](#assets) - - [`dev_talks`](#dev_talks) +- [`general`](#general) +- [`development`](#development) +- [`research`](#research) +- [`examples`](#examples) +- [`perception`](#perception) +- [`planning`](#planning) +- [`acting`](#acting) +- [`assets`](#assets) +- [`dev_talks`](#dev_talks) ## `general` @@ -47,4 +46,4 @@ The [`assets`](./assets/) folder contains mainly images that are used inside the ## `dev_talks` -The [`dev_talks`](./dev_talks/) folder contains the protocols of each sprint review and roles that the students fill during the project. +The [`dev_talks`](./dev_talks/README.md) folder contains the protocols of each sprint review and roles that the students fill during the project. diff --git a/doc/dev_talks/README.md b/doc/dev_talks/README.md new file mode 100644 index 00000000..db9a4f8a --- /dev/null +++ b/doc/dev_talks/README.md @@ -0,0 +1,4 @@ +# Dev Talks + +- [PAF24](./paf24/README.md) +- [PAF23](./paf23/) diff --git a/doc/dev_talks/paf24/README.md b/doc/dev_talks/paf24/README.md new file mode 100644 index 00000000..04311f31 --- /dev/null +++ b/doc/dev_talks/paf24/README.md @@ -0,0 +1,16 @@ +# PAF24 + +**Summary**: The PAF24 folder contains documents that are relevant for the PAF24 group. + +- [General Information](#general-information) +- [Notes for Sprints](#notes-for-sprints) + +## General Information + +- [Mermaid Gantt Chart](./mermaid_paf24.md) +- [Student Roles](./student_roles.md) +- [Joker Rules] + +## Notes for Sprints + +- [T03](./T03_2024-10-28.md) diff --git a/doc/dev_talks/paf24/joker_rules_paf24.md b/doc/dev_talks/paf24/joker_rules_paf24.md new file mode 100644 index 00000000..b325a71a --- /dev/null +++ b/doc/dev_talks/paf24/joker_rules_paf24.md @@ -0,0 +1,63 @@ +# Joker Rules PAF24 + +**Purpose**: This document outlines the rules for using the Joker card in the PAF24 project. + +- [1. Overview](#1-overview) +- [2. Using the Joker Card](#2-using-the-joker-card) +- [3. Special Circumstances](#3-special-circumstances) + - [3.1. Unable to Present Work Due to Scheduling Conflicts](#31-unable-to-present-work-due-to-scheduling-conflicts) + - [3.2. Illness or Emergency](#32-illness-or-emergency) + +## 1. Overview + +- **Project Duration**: October 2024 – March 2025 +- The Joker card allows you to be excused from duties during specific periods, especially during the exam phase in February 2025. +- **Total Joker Allocation**: + - **Joker Card** Up to 4 weeks throughout the project. + - **Presentation Only Joker Card** Maximum of 2 uses. +- **When to Use**: The Joker card should be played if you are unable to present your work during a sprint review or if the amount of work completed is insufficient. +- The intention of the Joker card is to ensure you have the appropriate time to prepare your exam phase. + +## 2. Using the Joker Card + +To play the Joker card: + +1. **Notify the Team and Chair**: Inform both the team and chair staff by posting in the `#joker` channel on our Discord server. +2. **Deadline**: Notify the team at least **7 days** before the sprint review. +3. **Example Post**: + - “I would like to play the Joker card for the sprint review on 2024-11-25.” +4. Your name and intent will be confirmed by the team and chair. + +> [!NOTE] 2-week sprints require two Joker cards to cover the entire sprint. + +## 3. Special Circumstances + +### 3.1. Unable to Present Work Due to Scheduling Conflicts + +- If you completed the sprint’s work but cannot present it, you have two options: + 1. Play the standard Joker card. + 2. Use a `Presentation Only Joker Card` by arranging for a teammate to present on your behalf. + +- **Presentation Only Joker Card Details**: + - **Maximum Use**: Limited to two times throughout the project. + - **Requirements**: + - Notify the team and chair at least **7 days** before the sprint review. + - Submit a written summary of your work in the `#joker` Discord channel at least **1 day** before the review. + - Find a teammate who presents your work. + +- **Written Summary Contents**: + - Overview of completed work. + - Key achievements. + - Lessons learned. + - Goals for the next sprint. + +> [!CAUTION] Presentation Only Joker Card +> We encourage all team members to only present your teammates work if absolutely necessary. +> The work completed by your colleagues is their responsibility, and they should be the ones to present it. +> Furthermore, you should only present their work if you are familiar with it and can answer questions about it. +> Additionally, you should be confident that your team member has completed the work to a satisfactory standard. + +### 3.2. Illness or Emergency + +- **Illness**: If you cannot attend due to illness, provide a medical certificate to be excused from duties without using a Joker card. +- **Emergency**: Emergencies are evaluated individually. diff --git a/doc/research/paf24/planning/decision_making_rationale.md b/doc/research/paf24/planning/decision_making_rationale.md new file mode 100644 index 00000000..a5f3976c --- /dev/null +++ b/doc/research/paf24/planning/decision_making_rationale.md @@ -0,0 +1,58 @@ +# Decision Making Approaches + +Responsible for making decisions based on information provided by other system components. It should account for all possible traffic scenarios to ensure comprehensive coverage and safe driving behavior + +## Decision Tree - current implementations + +- a tool to organizes decisions and their possible outcomes in a tree-like structure +- a branch represents a choice/condition which may lead to further options. + - starting at the root: checking surrounding conditions (traffic lights, obstacles, speed limits etc) branching out based on yes/no questions at each node +- in our case each node is deterministic (as no ML is used) + +### Pros and Cons + +- `+` are easy to understand and interpret +- `+` decision paths are traceable → suitable for debugging +- `+` deterministic outputs beneficial when predictability is essential +- `+` compared to NN, low computational cost +- `-` Adding too many branches for every possible situation can make the tree unwieldy and hard to manage + - can easily overfit with too many conditions +- `-` no reasoning and no probabilistic capabilities; trees tend to make suboptimal decisions in new, unclear situations + - hard to account for every situation + +### Changes in Previous Semesters + +- removing redundant behaviours + + - reducing to `Intersection`, `Lane Switch` and `Cruise` + +![decision_tree](/doc/assets/behaviour_tree.png) + +## Finite State Machine - previous implementations + +- model with an discrete number of possible states with rule-based control + - can only inherit one state at a time +- each state represents a specific driving mode, such as "Lane Switching" "Stopping," or "Overtaking" + - triggered by inputs like traffic signals, obstacles, or speed limits + +### Pros and Cons + +- `+` each state and transition is explicitly defined → suitable for debugging and testing +- `+` easier implementations than a decision tree +- `-` scalability issues with increasing number of states +- `-` less flexible than decision trees + +## Combining Planning and Reinforcement Learning + +[C.-J. Hoel, K. Driggs-Campbell, K. Wolff, L. Laine, and M. J. Kochenderfer, "Combining Planning and Deep Reinforcement Learning in Tactical Decision Making for Autonomous Driving," arXiv preprint arXiv:1905.02680, 2019.](https://arxiv.org/abs/1905.02680) + +- Monte Carlo Tree Search (MCTS): Used for planning by creating a search tree that simulates possible actions, selecting those that maximize expected rewards (maintaining desired speed, reaching end points, avoinding collision etc.) + - considers all possible actions → Each action creates a new branch that represents what the new situation might look like if the agent took that action +- deep neural network guides the MCTS by predicting action probabilities (which actions are most likely to lead to good outcomes: changing lanes, speeding up, breaking etc.) and state values (scores that tell the agent whether its current situation is favorable or not based on expected future rewards) + +### Pros and Cons + +- `+` generalizes better to complex scenarios + - takes advantage of continuous and high-dimensional state spaces +- `-` computational complexity and real-time feasibility +- `-` extensive training data and tuning required to handle a broad range of driving situations