- How to setup the developer environment
- How to use nvidia
- How to execute the tests
- How to add a new exercise
- Steps to change models from CustomRobots in RoboticsAcademy exercises
Important: when a new version of Robotics Academy is released it also updates the official RADI. Make sure to upgrade it using the following command: docker pull jderobot/robotics-academy:latest and docker pull jderobot/robotics-database:latest.
Before starting developing, please ensure that you have understood RoboticsAcademy architecture and where the different resources are placed. There are three different ways of developing in RA:
We provide an sh script that configures and runs automatically a developing environment:
- Clone RA repo
git clone --recurse-submodules https://github.com/JdeRobot/RoboticsAcademy.git -b <src-branch>
cd RoboticsAcademy/
You can ignore the -b arg if you want to start working from the main branch.
- Run the script with your desired config
./scripts/develop_academy.sh -r <link to the RAM repo/fork> -b <branch of the RAM repo> -i <humble>
If you don't provide any arguments, it will prepare a humble environment with the current stable branch of RAM. You may start working from that and then create the branch you need. You may access RA frontend at http://127.0.0.1:7164/academy/
If you need more information about the options available for launching the script, you can use:
./scripts/develop_academy.sh -h
Which will display a help message.
- Developing procedure
After running the script, the src folder will be created, which contains all the files of the RoboticsApplicationManager. You can create branches and commit normally to the RAM repo from inside that folder. For the rest of the changes, you can also work normally from the RoboticsAcademy folder, the contents of the src folder are automatically ignored.
Whenever you want to finish developing, you just can close the script with Crtl+C. It will take care of cleaning files so you can restart again without any additional config.
Note: For Apple M1/M2 Chip Users,Docker provides the feature in-built in docker Desktop to use Rosetta
Go to Settings > General : Enable Use Rosetta for x86_64/amd64 emulation on Apple Silicon
- Use Rosetta for x86_64/amd64 emulation on Apple Silicon
Please look at the attached image for reference.
It is possible that the first time you follow the instructions, a dependency may not be installed correctly, or it may not be added to the path for some reason.
One of the most frequent problems is that the frontend doesn't launch, you can solve it in two ways, the first one is to launch the frontend separately from another terminal:
cd /RoboticsAcademy
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh | bash
nvm install 20
nvm use 20
npm install --global yarn
cd react_frontend/ && yarn install && yarn run dev
Another way to solve it is to try to delete the old RADI image and download it again.
NOTE: If you are following this tutorial as a Windows users, please follow all these steps but using WSL (Linux kernel for Windows). Please visit the next link in case you don't have WSL installed.
Docker Compose is a tool for defining and running multi-container applications. It is the key to unlocking a streamlined and efficient development and deployment experience. Compose makes easy to manage services, networks, and volumes in a single, comprehensible YAML configuration file. Then, with a single command, you create and start all the services from your configuration file. In this YAML file we provide all the configurations needed for a smooth development experience, mainly ports and volumes. This method works by binding your local folder to the appropiate place inside a RoboticsBackend container, where all the dependencies are installed.
The steps for setting up a development environment using Docker Compose are:
- Install Docker Compose
sudo apt install docker-compose
- Clone RoboticsAcademy repo (or your fork) and create src folder
git clone --recurse-submodules https://github.com/JdeRobot/RoboticsAcademy.git -b <src-branch>
cd RoboticsAcademy/
- Clone RAM repo (or your fork) inside RA
git clone https://github.com/JdeRobot/RoboticsApplicationManager.git -b <src-branch> src
For the moment, the RAM folder MUST be called src, and the previous command takes care of that. You can create branches and commits from that folder without any issues.
- Creation commons.zip
In order for the front-end to build, you need to manually create the commons zip, that will be used to pass those files to the Robotics Backend.
# Prepare the commons zip file
cd common
cd console_interfaces
zip -r ../common.zip console_interfaces/
cd ..
cd gui_interfaces
zip -r -u ../common.zip gui_interfaces/
cd ..
cd hal_interfaces
zip -r -u ../common.zip hal_interfaces/
cd ../..
mv common/common.zip react_frontend/src/common.zip
- Build the REACT frontend. You must do this each time
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh | bash
nvm install 20
nvm use 20
npm install --global yarn
cd react_frontend/ && yarn install && yarn run dev
Please take into consideration that the yarn run dev script will continously watch for changes in the frontend, so you should execute this commands in a separate terminal.
- Copy the desired compose config into the main RA folder
cp compose_cfg/<your desired compose cfg> docker-compose.yaml
Feel free to study the configs, and adapt/create new ones suitable for your needs.
NOTE: As a Windows user, if you are willing to use GPU acceleration, there is a docker-compose file prepared for that BUT ONLY AVAILABLE with Nvidia GPUs (and WSL). Visit the following links WSL + CUDA, WSL + Docker Desktop to set-up Nvidia CUDA on WSL.
- Start Docker Compose
docker-compose up
Now you can open the RoboticsAcademy folder in your preferred code editor and test the changes inside the docker without having to regenerate a new image. Please keep in mind that this method works using a given RoboticsBackend version as the base. The only difference for developing between RoboticsBackend versions is the ROS version (humble) and the branch of RoboticsInfrastructure. If you need to make changes in RI, we recommend that you follow this procedure.
After testing the changes, you can simply commit them from the RA repo. Please keep in mind that the changes in RAM inside the src folder won't be commited, as they are not part of RoboticsAcademy. To commit those changes, just get inside the src/ folder and work from there (remember, this is the RAM repo with another name).
- Stop docker compose
docker-compose down
When you finish developing, you can close the container with Ctrl+C, but after that, you must clean the environment executing the previous command, otherwise, some things may not work in the next execution.
If you are launching Robotics Academy this way you need to manually create the commons zip, that will be used to pass those files to the Robotics Backend.
# Prepare the commons zip file
cd common
cd console_interfaces
zip -r ../common.zip console_interfaces/
cd ..
cd gui_interfaces
zip -r -u ../common.zip gui_interfaces/
cd ..
cd hal_interfaces
zip -r -u ../common.zip hal_interfaces/
cd ../..
mv common/common.zip react_frontend/src/common.zip
You must compile the frontend each time using:
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh | bash
nvm install 20
nvm use 20
npm install --global yarn
cd react_frontend/ && yarn install && yarn run dev
You also have to download the Robotics Applictaion Manager using:
git clone https://github.com/JdeRobot/RoboticsApplicationManager.git -b humble-devel src
You have 2 ways of launching Robotics Academy with docker run:
- Creating a new RADI. To see how to do it and why to use it, read how to generate a RADI.
- Using the docker image:
robotics-academy:latest
Then to launch Robotics Academy first you have to launch the database docker container. For example if you want to launch it from where you cloned Robotics Academy you can use the next command:
NOTE: If you are in another folder you may need to change the first part of the paths of the volume bindings (-v) to the correct path.
docker run --hostname my-postgres --name academy_db -d\
-e POSTGRES_DB=academy_db \
-e POSTGRES_USER=user-dev \
-e POSTGRES_PASSWORD=robotics-academy-dev \
-e POSTGRES_PORT=5432 \
-d -p 5432:5432 \
-v ./RoboticsInfrastructure/database/universes.sql:/docker-entrypoint-initdb.d/1.sql \
-v ./database/exercises/db.sql:/docker-entrypoint-initdb.d/2.sql \
-v ./database/django_auth.sql:/docker-entrypoint-initdb.d/3.sql \
jderobot/robotics-database:latestNow you can launch Robotics Academy using the followings commands:
NOTE: If you are in another folder you may need to change the first part of the paths of the volume bindings (-v) to the correct path.
- Automatic GPU selection
docker run --rm -it $(nvidia-smi >/dev/null 2>&1 && echo "--gpus all" || echo "") --device /dev/dri -p 6080-6090:6080-6090 -p 7163:7163 -p 7164:7164 --link academy_db -v ./:/RoboticsAcademy -v ./src:/RoboticsApplicationManager jderobot/robotics-academy:latest- Automatic GPU selection (Without Nvidia)
docker run --rm -it --device /dev/dri -p 6080-6090:6080-6090 -p 7163:7163 -p 7164:7164 --link academy_db -v ./:/RoboticsAcademy -v ./src:/RoboticsApplicationManager jderobot/robotics-academy:latest- Only CPU
docker run --rm -it -p 6080-6090:6080-6090 -p 7163:7163 -p 7164:7164 --link academy_db -v ./:/RoboticsAcademy -v ./src:/RoboticsApplicationManager jderobot/robotics-academy:latestWhen launching the developer script you can use the options -g to use the integrated graphics card or -n to use the nvidia graphics card. Before you start, make sure you have the NVIDIA Container Toolkit installed.
Now we will have to install the nvidia runtime to use it with our docker:
sudo apt-get update
sudo apt-get install -y nvidia-docker2Now we will check if docker recognises nvidia as a new runtime (restarting the docker service to update the new configuration):
sudo systemctl restart docker
docker info | grep -i runtimeIt will most likely not recognise it, so we will have to do it manually by editing or creating the /etc/docker/daemon.json file:
{
"runtimes": {
"nvidia": {
"path": "nvidia-container-runtime",
"runtimeArgs": []
}
}
}It is also possible that nvidia-runtime is not installed, check and install it if it is not.
dpkg -l | grep nvidia-container-runtimeIf it is not installed:
sudo apt-get install -y nvidia-container-runtimeNow everything should be ready to start using nvidia with our dockers, restart the docker service to update the configuration and check that everything works correctly.
sudo systemctl restart dockerIn order to execute the Robotics Academy test you must have launched RoboticsAcademy beforehand and then follow the next steps:
- In another terminal enter inside the react_frontend directory and execute
npm run test. - In the new open window select "E2E Testing".
- Select your prefered browser. RoboticsAcademy officially supports Chrome and Firefox.
- Click on the green button "Start E2E Testing in ...".
- It will open a new window in the selected browser. Now select one of the available test and let it execute.
You must mantain the window were the tests are executing always visible, because some tests fail if it is not.
To create a new exercise you must complete this 2 sections:
Create a folder with the folder name as "exercise_id" at the location from repository root : "exercises".
Inside that folder create 2 or more new ones with the following names:
<language>_template: the available languages arepythonandcpp. One for each supported language.cpp_lib: used for precompilation of additional C++ libaries like WebGUI or HAL.frontend
You may add a teaser to the exercise by creating a file called teaser.png using a 9/10 aspect ratio.
An exercise must contain this 3 files:
- WebGUI.py: used for the interactions between exercise and frontend.
- HAL.py: Hardware Abstraction Layer for accesing the robot data.
- Frequency.py: needed for frequency control of iterative code.
There are a three python packages to help the development of a new exercise:
- Hal Interfaces: provides the hardware abstraction layer for various components
- Gui Interfaces: provides with various base GUI's for easy development
- Console Interfaces: provides control of the console
For knowing how to use each package, please follow the links in the list above.
An exercise must contain this 3 files and a folder:
- main.cpp: used as the entrypoint for launching the WebGUI, HAL, console control and the user code. Must contain the next code:
#include "HAL.hpp"
#include "WebGUI.hpp"
#include "academy.cpp"
#include "rclcpp/rclcpp.hpp"
#include <bits/stdc++.h>
#include <filesystem>
#include <string>
#include <thread>
void start_console()
{
int virtual_terminal = 0;
for (const auto &entry : std::filesystem::directory_iterator("/dev/pts/"))
{
std::filesystem::path outfilename = entry.path();
std::string filename = outfilename.filename().string();
if (filename != "ptmx" && std::stoi(filename) > virtual_terminal)
{
virtual_terminal = std::stoi(filename);
}
}
const std::string v_terminal_str = "/dev/pts/" + std::to_string(virtual_terminal);
if (freopen(v_terminal_str.c_str(), "w", stdout) == NULL)
{
std::cerr << "Error redirecting stdout!" << std::endl;
}
if (freopen(v_terminal_str.c_str(), "w", stderr) == NULL)
{
std::cerr << "Error redirecting stderr!" << std::endl;
}
if (freopen(v_terminal_str.c_str(), "w", stdin) == NULL)
{
std::cerr << "Error redirecting stdin!" << std::endl;
}
};
int main(int argc, char *argv[])
{
rclcpp::init(argc, argv);
start_console();
rclcpp::executors::MultiThreadedExecutor executor(rclcpp::ExecutorOptions(), 2);
auto HAL_node = std::make_shared<HAL>();
executor.add_node(HAL_node);
auto WebGUI_node = std::make_shared<WebGUINode>();
executor.add_node(WebGUI_node);
#ifdef USER_NODE
auto user_node = std::make_shared<UserNode>();
executor.add_node(user_node);
#else
std::thread user(exercise);
#endif
std::thread ros([&executor]{executor.spin();});
WebGUI();
#ifndef USER_NODE
user.join();
#endif
ros.join();
rclcpp::shutdown();
return 0;
}- package.xml: Package description of the ROS package.
- CMakeLists.txt: needed for compilation of the ROS package.
- libs/: needed for storing the libraries for user access.
WORK IN PROGRESS
This directory contains the source code for the C++ libraries WebGUI, HAL, Frequency and others.
It must contain:
- src/: contains the source code for at least HAL, WebGUI and Frequency.
- include/: contains the headers for the source code.
- CMakeLists.txt: needed for compilation of the libraries.
This directory will not be accesible to the user and will only be used to compile the libraries.
To do that compilation you must launch the RADI using Robotics Academy as a volume (it is recommende to use the developer script) using the next command (in Linux):
docker exec -it cf17d87822efd8f7596d8c5dd274ef84789e7be57eaa6a9a78ad7d1e16dd0807 bashThen inside the RADI navigate to the desired exercise like:
cd RoboticsAcademy/exercises/vacuum_cleanerAfter being inside the exercise directory you must compile the libary inside the RADI using;
cd cpp_lib
mkdir build
cd build/
cmake ..
make
chmod 777 *.soAfter compiling the libraries you must move them to the libs folder created in the cpp_template section.
mv *.so ../../cpp_template/libs/
cd ..
rm -r build/
# Copy the headers to the cpp_template directory
cp -r include/ ../cpp_template/libs/An exercise must contain the following files:
- tsconfig.json: used for the tsconfig. Must contain the next code:
{
"compilerOptions": {
"target": "es5",
"lib": ["dom", "dom.iterable", "esnext"],
"types": [
"../../../react_frontend/svg.d.ts",
"../../../react_frontend/png.d.ts",
"../../../react_frontend/jpg.d.ts",
"../../../react_frontend/zip.d.ts"
],
"paths": {
"Assets/*": ["../../../react_frontend/src/assets/*"],
"Components/*": ["../../../react_frontend/src/components/*"],
"Utils/*": ["../../../react_frontend/src/utils/*"],
"Contexts/*": ["../../../react_frontend/src/contexts/*"],
"Helpers/*": ["../../../react_frontend/src/helpers/*"],
"Icons/*": ["../../../react_frontend/src/icons/*"],
"Styles/*": ["../../../react_frontend/src/styles/*"],
"Types/*": ["../../../react_frontend/src/types/*"],
"Constants/*": ["../../../react_frontend/src/constants/*"],
"Api": ["../../../react_frontend/src/api/index.ts"],
"Routes": ["../../../react_frontend/src/routes/index.ts"],
"*": ["../../../react_frontend/node_modules/*"]
},
"baseUrl": "./",
"rootDirs": ["./", "../../../react_frontend/src"],
"typeRoots": ["../../../react_frontend/node_modules/@types"],
"declaration": true,
"allowJs": true,
"skipLibCheck": true,
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
"strict": true,
"noImplicitAny": true,
"forceConsistentCasingInFileNames": true,
"noFallthroughCasesInSwitch": true,
"module": "esnext",
"moduleResolution": "node",
"resolveJsonModule": true,
"isolatedModules": true,
"noEmit": true,
"jsx": "react-jsx"
},
"include": [
"./",
"eslint.config.mts",
"../../../react_frontend/src",
"../../../react_frontend/png.d.ts",
"../../../react_frontend/jpg.d.ts",
"../../../react_frontend/svg.d.ts",
"../../../react_frontend/zip.d.ts"
]
}- eslint.config.mts: used for the eslint (Currently does not work). Must contain the next code:
import js from "@eslint/js";
import globals from "globals";
import tseslint from "typescript-eslint";
import pluginReact from "eslint-plugin-react";
import { defineConfig } from "eslint/config";
export default defineConfig([
{
files: ["**/*.{js,mjs,cjs,ts,mts,cts,jsx,tsx}"],
plugins: { js },
extends: ["js/recommended"],
languageOptions: {
globals: globals.browser,
parserOptions: {
project: "./tsconfig.json",
tsconfigRootDir: import.meta.dirname,
},
},
},
tseslint.configs.recommended,
pluginReact.configs.flat.recommended,
{
settings: {
react: {
version: "detect",
},
},
},
]);- WebGUI.tsx: used for the exercise frontend.
And should have the following:
- updateCallback: will be called when the data is sent from the application. In here you must update the shown data. Obligatory
- stateCallback: will be called when the state of the Robotics Backend is changed. In here you may unset shown images or reset variables when the application is reset.
- canvasRef and resizeObserver: should be used when information displayed is dependant on the screen size. resizeObserver will be called when the size changes.
import React, { useState, useEffect } from "react";
import WebGUIImage from "Components/exercise/WebGUIImage";
import WebGUIContainer, {
connectApplication,
} from "Components/exercise/WebGUIContainer";
import { useExercise } from "Contexts/ExerciseContext";
import { states } from "jderobot-commsmanager";
function WebGUI() {
const exerciseContext = useExercise();
const [image, setImage] = useState<string | undefined>(undefined);
const [manager, setManager] = useState(exerciseContext.manager);
useEffect(() => {
setManager(exerciseContext.manager);
}, [exerciseContext]);
const updateCallback = (updateData: unknown) => {
const data = updateData as any;
const update = data.update;
if (update.image) {
const image = JSON.parse(update.image);
setImage(`data:image/png;base64,${image.image}`);
}
};
const stateCallback = (state: string) => {
if (state === states.TOOLS_READY) {
setImage(undefined);
}
};
connectApplication(manager, updateCallback, stateCallback);
return (
<WebGUIContainer>
<WebGUIImage id="gui_canvas" src={image} style={{ width: "100%" }} />
</WebGUIContainer>
);
}
export default WebGUI;You may add as many TypeScript helper files needed inside a helper directory, and as many CSS files inside a css folder.
If there is need for additional resources such as images, you may add them inside a resources folder.
To add a exercise to the database you must use Django Web Admin:
- Launch the docker as normal.
- Access http://127.0.0.1:7164/admin/ on a browser and log in with "user" and "pass".
- Click on "add exercise" and fill the required fields specified below.
- Save the exercise clicking on the "Local Save" button.
An exercise entry in the database must include the following data:
exercise id: unique exercise identifier, must match the folder namename: name to display on the exercise listdescription: description to display on the exercise listtags: an exercise must include at least one ROS tag ("ROS2"). The exercise will only be shown on the exercise list when the RoboticsBackend ROS version installed is listed in the tags. Tags are also used by the search bar.status: changes the state indicator (ACTIVE = green; PROTOTYPE = yellow; INACTIVE = red)url: url of the exercise documentation
- Follow the guide in Robotics Infrastructure.