Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

146 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Health Robot

Robot de santé autonome avec backend FastAPI, frontend TanStack Start, broker MQTT et persistance MySQL.


Architecture du Backend (Clean Architecture)

backend/
├── app/
│   ├── domain/              # Cœur métier — pas de dépendances externes
│   │   ├── entities/        #   User, RobotState, MqttTopic
│   │   └── repositories/    #   Protocoles (UserRepository, RobotStateRepository, MessagePublisher)
│   ├── application/         # Cas d'utilisation et DTO
│   │   ├── dto/             #   LoginRequest, CreateUserRequest, TokenResponse, …
│   │   └── use_cases/       #   AuthenticateUser, CreateUser, TriggerEmergencyStop, …
│   ├── infrastructure/      # Adaptateurs concrets
│   │   ├── database/        #   SQLAlchemy, Alembic, models
│   │   ├── mqtt/            #   Client Paho MQTT
│   │   ├── repositories/    #   SqlAlchemyUserRepository, InMemoryUserRepository
│   │   └── security/        #   JwtTokenService, PasswordHasher
│   ├── presentation/        # Couche API
│   │   └── api/
│   │       ├── v1/endpoints/#   auth.py, admin_users.py, robot.py, safety.py, navigation.py
│   │       ├── dependencies.py  # get_current_user, require_roles, dep inj
│   │       └── health.py        # Health check
│   ├── core/
│   │   └── config.py        # Settings (JWT, DB, MQTT, vars env)
│   └── main.py              # create_app, lifespan, assemble DI
├── tests/
│   ├── conftest.py
│   ├── helpers.py
│   ├── test_auth_endpoints.py
│   ├── test_admin_user_endpoints.py
│   ├── test_robot_permissions.py
│   └── test_public_robot_ingestion.py
├── alembic/                 # Migrations DB
├── pyproject.toml
├── requirements.txt
├── Dockerfile
└── uv.lock

Conventions

Règles générales

  • Clean Architecture : le domaine ne dépend jamais de FastAPI, SQLAlchemy, JWT ou passlib
  • Pas de dossiers routes/, services/, models/ à la racine de app/
  • Injection de dépendances : les repositories et services sont passés via le container de use cases (application/use_cases/container.py)
  • Endpoints : définis dans presentation/api/v1/endpoints/, protégés via les dépendances dans presentation/api/dependencies.py

Authentification

  • Deux rôles : admin (accès complet) et caregiver (accès opérationnel)
  • JWT pour l'auth humaine, routes robot-only publiques sans protection
  • Pas d'inscription publique : création des comptes uniquement par l'admin
  • Seed du premier admin via variables d'environnement (INITIAL_ADMIN_EMAIL, INITIAL_ADMIN_PASSWORD, INITIAL_ADMIN_NAME)

Persistance

  • MySQL 8.4 via Docker (volume nommé health_robot_mysql_data)
  • Repository backend paramétrable : USER_REPOSITORY_BACKEND=database ou memory
  • Migrations avec Alembic

Tests

  • pytest + httpx dans tests/
  • scope=module pour partager le TestClient entre tests
  • Compteur global d'emails uniques pour éviter les collisions

Commits

  • [FEAT]:, [FIX]:, [REFACTOR]:, [DOCS]:

Ce qui a été fait

  • Restructuration complète en Clean Architecture
  • Authentification JWT (login, logout, me) avec rôles admin/caregiver
  • CRUD utilisateurs admin (création, liste, modification, désactivation, reset password)
  • Protection dernier admin actif
  • Persistance MySQL avec SQLAlchemy + Alembic
  • Routes robot protégées (status, emergency stop, navigation ETA)
  • Routes robot-only publiques (battery, ETA robot)
  • Documentation OpenAPI enrichie
  • Seed automatique du premier admin
  • Tests organisés par catégorie
  • Docker Compose avec MySQL, Mosquitto, backend et frontend
  • Mission Control backend-owned: points annotés, stocks, missions FIFO, confirmations récupération/livraison
  • /map affiche et administre les points mission directement sur la carte ROS
  • /control est une interface mission-first avec carte interne, sans navigation libre caregiver ni Foxglove
  • /robot-screen affiche le statut mission/idle en plein écran pour l'écran embarqué du robot
  • Service kiosque Chromium installable sur le Jetson via robot/setup/install_robot_screen_kiosk.sh

Lancer le projet

Docs opérationnelles utiles :

  • docs/robot-screen-kiosk.md décrit le mode kiosque de l'écran robot.
  • docs/mission-control-implementation-plan.md garde le modèle mission et les règles métier.

Prérequis

  • Docker & Docker Compose v2
  • Git

1. Cloner le repo

git clone git@github.com:Amineo21/Health_Robot.git
cd Health_Robot

2. Créer le fichier d'environnement

cp infra/.env.example infra/.env

Éditer infra/.env et remplir les valeurs obligatoires :

# Sécurité — REQUIS (le serveur ne démarre pas sans ces variables)
JWT_SECRET_KEY=<un-secret-long-au-moins-32-caracteres>
INITIAL_ADMIN_PASSWORD=<un-mot-de-passe-fort>
ROBOT_SCREEN_TOKEN=<un-token-long-pour-l-ecran-robot>

# MySQL
MYSQL_ROOT_PASSWORD=<un-mot-de-passe-fort>
MYSQL_PASSWORD=<un-mot-de-passe-fort>

# Optionnel — override si besoin
INITIAL_ADMIN_EMAIL=admin@health-robot.local
INITIAL_ADMIN_NAME=Admin

Générer un secret rapide :

openssl rand -base64 48

Variables utiles pour le robot réel :

ROBOT_ROSBRIDGE_ENABLED=true
ROBOT_ROSBRIDGE_URL=ws://10.10.220.180:9090
ROBOT_DASHBOARD_URL=http://10.10.220.180:8080
MISSION_ARRIVAL_RADIUS_M=0.60

Si une page frontend est ouverte depuis le robot, ne laissez pas l'API frontend sur localhost. Utilisez l'IP de cette machine visible depuis le robot :

VITE_API_BASE_URL=http://<ip-de-cette-machine>:4000
CORS_ALLOW_ORIGINS=http://localhost:3000,http://127.0.0.1:3000,http://<ip-de-cette-machine>:3000

3. Lancer tout le stack

docker compose -f infra/docker-compose.yml up --build -d

4. Vérifier que tout tourne

docker compose -f infra/docker-compose.yml ps
curl http://localhost:4000/health

Résultat attendu :

Service URL / Port Vérification
Frontend http://localhost:3000 Page de login s'affiche
Backend http://localhost:4000 {"status":"healthy"}
API Docs http://localhost:4000/docs Swagger UI s'affiche
MQTT localhost:1883 Broker actif
MySQL localhost:3306 Healthcheck OK dans docker ps

5. Lancer le robot screen en mode kiosque

Le mode kiosque lance Chromium en plein écran sur l'écran du robot et ouvre la page frontend /robot-screen. Cette page est read-only: elle affiche CareBot en idle, la mission active, les attentes de confirmation, les échecs et l'urgence.

Préconditions :

  • Le stack Docker local tourne avec ROBOT_SCREEN_TOKEN dans infra/.env.
  • Le frontend est accessible depuis le robot sur http://<ip-de-cette-machine>:3000.
  • Le robot est joignable en SSH via jetson@10.10.220.180.
  • Chromium est installé sur le robot.

Depuis la racine du repo, sur la machine de dev :

ROBOT_SCREEN_TOKEN=<le-même-token-que-dans-infra-env> \
FRONTEND_URL=http://<ip-de-cette-machine>:3000 \
./robot/setup/install_robot_screen_kiosk.sh 10.10.220.180

Le script installe et démarre carebot-kiosk.service sur le robot. Il ouvre Chromium sur /robot-screen?token=...; le frontend stocke ensuite le token localement et nettoie l'URL vers /robot-screen.

Commandes utiles :

ssh jetson@10.10.220.180 'systemctl is-active carebot-kiosk'
ssh jetson@10.10.220.180 'journalctl -u carebot-kiosk -f'
ssh jetson@10.10.220.180 'sudo systemctl restart carebot-kiosk'
ssh jetson@10.10.220.180 'sudo systemctl stop carebot-kiosk'

6. Parcours Mission Control

  1. Ouvrir http://localhost:3000.
  2. Se connecter avec l'admin initial.
  3. Aller dans /map.
  4. Créer au moins un point STOCK, un point DELIVERY_ROOM, et éventuellement un point ROBOT_BASE.
  5. Assigner les fournitures disponibles sur le point STOCK.
  6. Aller dans /control.
  7. Créer une mission avec une fourniture et une chambre.
  8. Le backend sélectionne le stock, démarre la mission si le robot est libre, puis attend la détection d'arrivée par proximité.
  9. Confirmer la récupération quand /control le propose.
  10. Confirmer la livraison quand /control le propose.
  11. La mission suivante en file FIFO démarre automatiquement si elle existe.

Important — connexion au robot réel

Par défaut, le backend essaie de se connecter au robot M3 Pro réel via ROBOT_ROSBRIDGE_URL=ws://10.10.220.180:9090 et ROBOT_DASHBOARD_URL=http://10.10.220.180:8080.

Si la machine n'est pas sur le même réseau que le robot, si l'IP du robot est différente, ou si rosbridge_websocket n'est pas lancé sur le robot, les logs peuvent afficher en boucle :

WARNING:app.infrastructure.rosbridge.mqtt_rosbridge_bridge:Erreur rosbridge: [Errno 111] Connection refused
ERROR:websocket:[Errno 111] Connection refused - goodbye
WARNING:app.infrastructure.rosbridge.mqtt_rosbridge_bridge:Connexion rosbridge perdue, nouvelle tentative dans 3s

Ce warning ne signifie pas que le backend, le frontend, Docker ou MQTT sont cassés. Il indique seulement que le backend ne peut pas ouvrir la WebSocket ROS du robot sur 10.10.220.180:9090 depuis cette machine.

Pour vérifier l'accès au robot depuis une autre machine :

nc -vz 10.10.220.180 9090
curl http://10.10.220.180:8080

Si vous lancez le projet sans robot réel, désactivez simplement le pont rosbridge dans infra/.env :

ROBOT_ROSBRIDGE_ENABLED=false

Si le robot a une autre adresse IP, gardez le pont activé mais remplacez les URLs :

ROBOT_ROSBRIDGE_ENABLED=true
ROBOT_ROSBRIDGE_URL=ws://<ip-du-robot>:9090
ROBOT_DASHBOARD_URL=http://<ip-du-robot>:8080

7. Se connecter pour la première fois

  • URL : http://localhost:3000
  • Email : admin@health-robot.local (ou la valeur de INITIAL_ADMIN_EMAIL)
  • Mot de passe : la valeur de INITIAL_ADMIN_PASSWORD

8. Créer des comptes caregivers

Depuis l'interface admin (/admin/users) ou l'API :

TOKEN=$(curl -s -X POST http://localhost:4000/api/auth/login \
  -H "Content-Type: application/json" \
  -d '{"email":"admin@health-robot.local","password":"<votre-mot-de-passe>"}' \
  | grep -o '"access_token":"[^"]*"' | cut -d'"' -f4)

curl -X POST http://localhost:4000/api/admin/users \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"email":"caregiver@health-robot.local","name":"Infirmier","password":"CaregiverPass123!","role":"caregiver"}'

Lancer le backend en local (sans Docker)

cd backend
pip install -r requirements.txt

# MySQL + Mosquitto via Docker :
docker compose -f ../infra/docker-compose.yml up -d mysql mosquitto

# Variables d'environnement (minimal) :
export JWT_SECRET_KEY=$(openssl rand -base64 48)
export INITIAL_ADMIN_PASSWORD=dev-password
export DATABASE_URL=mysql+pymysql://health_robot:health_robot@localhost:3306/health_robot?charset=utf8mb4
export USER_REPOSITORY_BACKEND=database

# Migrations :
alembic upgrade head

# Lancer :
uvicorn app.main:app --reload --port 4000

Lancer le frontend en local (sans Docker)

cd frontend/health-robot-front
npm ci
echo "VITE_API_BASE_URL=http://localhost:4000" > .env
npm run dev

Le frontend démarre sur http://localhost:3000.

Tests unitaires

# Backend
cd backend
pytest tests/ -v

# Frontend
cd frontend/health-robot-front
npm test

Dépannage

Problème Solution
RuntimeError: Environment variable JWT_SECRET_KEY is required Ajouter JWT_SECRET_KEY=<secret> dans infra/.env
RuntimeError: Environment variable INITIAL_ADMIN_PASSWORD is required Ajouter INITIAL_ADMIN_PASSWORD=<mot-de-passe> dans infra/.env
Backend ne démarre pas, logs Access denied for user Vérifier que MYSQL_USER / MYSQL_PASSWORD / MYSQL_ROOT_PASSWORD sont cohérents dans .env
Frontend affiche "Erreur réseau" Vérifier que le backend tourne : curl http://localhost:4000/health
MQTT ne connecte pas Vérifier docker compose logs mosquitto — le broker doit écouter sur 1883
Logs répétés Erreur rosbridge: [Errno 111] Connection refused La machine ne peut pas joindre le robot sur ROBOT_ROSBRIDGE_URL. Vérifier le réseau/IP/port 9090, ou mettre ROBOT_ROSBRIDGE_ENABLED=false si aucun robot réel n'est utilisé
/robot-screen renvoie 403 Vérifier que ROBOT_SCREEN_TOKEN est identique dans infra/.env et dans la commande d'installation kiosque
L'écran robot n'ouvre pas Chromium Vérifier journalctl -u carebot-kiosk -f, DISPLAY=:0, et que le frontend est joignable depuis le robot
Les points n'apparaissent pas sur /map Vérifier que la carte ROS est reçue, que les points sont actifs, et que leurs coordonnées sont dans les limites de la map

Membres du groupe

  • OUARDI Ahmed-Amine
  • EHOUARA Christ-Yvann
  • KOMOE Daniel
  • SACKO Ousmane
  • DRAME Baboye

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages