Résumé :
Utilisation de l'image debian trixie (stable) ou debian forky (testing) pour Raspberry Pi avec un processeur arm64 (Pi3 4 5). Cette image est directement utilisable pour apprendre ou enseigner le codage avec les outils SNAP!BYOB (analogue à scratch) et jupyter pour aborder python C et javascript. L'image rpi-devDeb-trixie64_2026-09-30 https://media.tremplin.ens-lyon.fr/isoImages/RaspBerry) est construite à partir de la source debian standard https://raspi.debian.net/ et l'image rpi-devPiOs-trixie64_2026-09-30 https://media.tremplin.ens-lyon.fr/isoImages/RaspBerry de la source PiOS standard (https://www.raspberrypi.com/.
Motivations
Le but de cet article est de décrire la prise en main d'une RaspberryPi préparée par le projet Tremplin des Sciences. La procédure concerne :
-
soit un système d'exploitation
Debian "orthodoxe"(analogue à celui qui est installé sur un ordinateur ordinaire) et qui fonctionne sur une Raspberry Pi ARM-64. -
soit un système d'exploitation Debian
PiOSqui contient des modifications nécessaires à l'usage des overlays.
La motivation principale est de disposer d'une RaspberryPi directement utilisable avec une préconfiguration et des choix correspondant au dispositif Tremplin des sciences. L'image est augmentée de nombreux logiciels nécessaires pour piloter le GPIO de la RaspberryPi, apprendre à coder en python ou C++ à l'aide d'une interface web jupyterou jupyterlab.
Remerciements
Éric le Jan et Charles-Henri Eyraud.
Téléchargements
Lors du développement du projet "Météo et Climat tremplin pour l'enseignement des sciences et dès que l'utilisation d'objets connectés (RaspberryPi, Odroïd, Intel edison, Intel joule) a été entérinée, des images ont été construites au coup par coup pour soutenir les fonctions attribuées à chacun des objets connectés. Cet article présente la prise en main des images "Développement" du dispositif Tremplin des Sciences. Pour réaliser cette opération il est nécessaire de disposer : * d'un ordinateur * d'un réseau soit filaire soit WIFI dont on connait le nom et le mot de passe * d'une carte micro-SD vierge de bonne qualité supportant le maximum possible d'écritures
L'utilisateur privilégié initial s'appelle localadm mais les outils de construction sont conservés dans le bureau de l'utilisateur privilégié tremplin. Il est recommandé laisser ce dernier en l'état pour éventuellement permettre un intervention de secours en ligne. Une clef publique ssh a été fournie à l'utilisateur tremplin, il est recommandé dès la première connexion de supprimer l'autorisation par mot de passe et de préferer les authentifications via des clés ssh pour éviter l'utilisation de mots de passe (un mot de passe de secours est toutefois prévu dans la configuration).
1. Téléchargement de l'image et création de la micro-SD
Le site de dépôt des images fournit pour chaque image :
* un fichier ISO
* un fichier bmap qui permet des lectures/écritures plus rapides avec l'outil bmaptool
* un fichier de hash sha256sum pour vérifier l'intégrité du téléchargement
1.1. copie du fichier ISO sur l'espace de stockage de l'ordinateur hôte
1.2. Copie de l'image sur une carte micro-SD
La copie doit être faite via un protocole binaire sur une micro SD vide et non formattée, toute donnée sur la carte micro-SD sera irrémédiablement détruite. L'utilisation de l'outil bmaptool permet de réduire les temps de copie.
2. Première connexion
L'image est préconfigurée pour pouvoir être utilisée sans écran ni clavier ni souris ni connexion filaire. Il est possible d'interagir en ligne de commande ou en mode graphique via un serveur de terminaux utilisant le protocole xrdp pour afficher l'écran de la raspberry dans un autre ordinateur. On dispose ainsi des outils graphiques standards d'un environnement linux. Le gestionnaire d'affichage est sddm et le gestionnaire de fenêtres lxqt choisis pour leur faible empreinte en mémoire car les raspberriesPi en ont peu, l'utilisation de cet environnement est assez intuitive.
La première connexion est cruciale car il est impossible de créer une image qui permette de s'insérer dans toute infrastructure (notamment sans fil), cependant les configurations nécessaires sont réduites au minimum. L'utilisation des lignes de commandes peut paraître archaïque mais c'est en réalité un moyen d'interagir le plus simplement et avec le moins d'opérations possibles.
2.1. Connexion automatique au réseau de la RaspberryPi
Afin de permettre à coup sûr la connexion de la RaspberryPi, elle propose son propre point d'accès :
- nom : raspi-Wifi
- mot de passe : rpiTremplin2026
- adresses fournies : 192.168.12.2 -> 192.168.12.254
- adresse de la RaspberryPi : 192.168.12.2
les informations nécessaires au fonctionnement du point d'accès sont réunies dans 3 fichiers de configuration qu'il est possible de modifier au besoin ou en fin de manipulation (bien respecter les consignes car une erreur peut entraîner l'interruption du réseau et imposer l'utilisation d'un clavier et d'un écran):
/etc/systemd/network/46-wlan1server.network/etc/udhcpd.conf/etc/hostapd/hostapd.conf
Sur un ordinateur disposant d'une connection WIFI se connecter au réseau raspi-Wifi avec le mot de passe rpiTremplin2026. La machine utilisée quitte le réseau sur lequel elle se trouvait pour de positionner sur le même réseau que la RaspberryPi, son adresse devient de la forme 192.168.12.***
2.2. Connexion à la RaspberryPi
Depuis un terminal se connecter en ssh ssh localadm@192.168.12.2 -p22022 mot de passe AChanger1$, aller dans le dossier netplan cd /etc/netplan:
ls -al
drwxr-xr-x 2 root root 4096 13 oct. 13:42 .
drwxr-xr-x 146 root root 12288 13 oct. 12:11 ..
-rw------- 1 root root 296 16 sept. 09:18 50-eth0.yaml
-rw------- 1 root root 378 16 sept. 09:19 60-wlan0-modele.suspended
-rw------- 1 root root 299 16 sept. 09:20 70-allenx.yaml
-rw------- 1 root root 296 16 sept. 09:21 80-end0.yaml
Les fichiers commençant par 50, 70, 80 concernent le réseau filaire et les différentes options possibles de nommage de cette interface. Copier 60-wlan0-modele.suspended en 60-wlan0-MyIdentifier.yaml :
network:
version: 2
renderer: networkd
wifis:
wlan0:
accept-ra: true
access-points:
"Name 1st WIFI network":
password: "Password 1st WIFI network"
"Name 2nd WIFI network":
password: "Password 2nd WIFI network"
dhcp4: true
dhcp6: true
Remplacer Name and Password les valeurs de votre réseau (sur l'exemple ci-dessus deux réseaux sont disponibles).
Pour une sécurité complète nous allons tester la configuraton du réseau avec la séquence de commandes ci-dessous qui seront enchaînées si tout va bien et qui signaleront toute anomalie en cas de problème :
sudo netplan generate
sudo netplan try
sudo netplan apply
3. Vérification du réseau
Rebooter la RaspberryPi sudo reboot puis se reconnecter au réseau 192.168.11.0/24 récupérer les informations réseau avec la commande ip a Si les deux réseaux wlan0 et wlan1 sont "UP" on peut passer à l'étape suivante de nettoyage pour retrouver les performances maximales du WIFI.
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host noprefixroute
valid_lft forever preferred_lft forever
2: eth0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc mq state DOWN group default qlen 1000
link/ether ##:##:##:##:##:## brd ff:ff:ff:ff:ff:ff
3: wlan0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
link/ether ##:##:##:##:##:## brd ff:ff:ff:ff:ff:ff
inet 192.168.10.54/24 metric 600 brd 192.168.10.255 scope global dynamic wlan0
valid_lft 81840sec preferred_lft 81840sec
inet6 fe80::dea6:32ff:fedf:ad12/64 scope link proto kernel_ll
valid_lft forever preferred_lft forever
4: wlan1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
link/ether ##:##:##:##:##:## brd ff:ff:ff:ff:ff:ff
inet 192.168.12.2/24 brd 192.168.12.255 scope global wlan1
valid_lft forever preferred_lft forever
inet 192.168.12.1/24 brd 192.168.12.255 scope global secondary wlan1
valid_lft forever preferred_lft forever
inet6 fe80::dca6:32ff:fe7f:ad12/64 scope link proto kernel_ll
valid_lft forever preferred_lft forever
4. Suppression du reseau 192.168.12.0/24
Comme précisé dans l'introduction la configuration du rseau local de la RaspberryPi dépend de 3 fichiers de configuration qui conditionnent l'exécution de services. Pour permettre de remettre en route ce WIFI local nous n'allons pas toucher 2 fichiers de configuration et simplement suspendre les services qui seront réactivés en cas de besoin. Le 3ème service est le réseau qui ne doit pas être interrompu et pour éviter les erreurs que causerait une tentative de redémarrage de l'interface virtuelle, le fichier de configuration de cete interface va être renommé. Toutes les commandes ci-dessous se font avec l'utilisateur localadm.
4.1. Supension de hostapd
Pour interrompre le service au démarrage utiliser la commande : sudo systemctl disable hostapd
4.2. Suspension de udhcpd
Pour interrompre le service au démarrage utiliser la commande : sudo systemctl disable udhcpd
4.3. Inactivation du point d'accès
- interrompre le service au démarrage avec la commande :
sudo systemctl disable wireless-apdevice - renommer le fichier
/etc/systemd/network/46-wlan1server.networkavec la commandesudo mv/etc/systemd/network/46-wlan1server.network /etc/systemd/network/46-wlan1server.suspended`
Redémarrer avec sudo reboot et l'interface virtuelle wlan1 aura disparu.
5. Reconstruction du reseau 192.168.12.0/24
Pour reconstruire le réseau 192.168.12.0/24 en prévision d'un changement d'environnement afin de pouvoir reconfigurer la raspberryPi, faire les manipulations suivantes :
Régénérer le fichier 46-wlan1server.network par exemple (si la suspension a été faite comme indiqué ci-dessus) :
sudo mv `/etc/systemd/network/46-wlan1server.suspended /etc/systemd/network/46-wlan1server.network
Réinstaller les services pour le prochain démarrage :
sudo systemctl enable hostapd
sudo systemctl enable udhcpd
sudo systemctl enable wireless-apdevice
6. Vidéo et streaming
La gestion de la vidéo a évolué ce site détaille les opérations à effectuer pour piloter les caméras raspberry quel que soit le modèle. Des ajouts d'optimisation sont possibles dasn le fichier `/boot/firmaware/config.txt. Une des façons les plus robustes de gérer la vidéo serait de compiler libcamera et rpicam depuis github mais il semble manquer des drivers dans le noyau de la debian.
Par contre la PiOS dispose des drivers ainsi que de libcamera et rpicam préinstallés. Les commandes décrites dans le tutoriel fonctionnent directement sans autre installation. Il est recommandé d'utiliser le tutoriel, ce document ne contient que des exemples succincts et peu commentés.
6.1 Mise en oeuvre de rpicam-*
Ce chapitre s'applique uniquement aux PiCamera connectées sur le port caméra de la RaspberryPi. La configuration se fait dans /boot/firmware/config.txt. Il est possible de moduler le comportement de la caméra en utilisat l'option --tuning-file /usr/share/libcamera/ipa/rpi/pisp/######, ###### étant l'un des fichiers du dossier /usr/share/libcamera/ipa/rpi/pisp.
6.1.1 rpicam-hello
Cette commande permet d'afficher la prévisualisation de ce capture la caméra, nombreuses options disponibles (voir le help). Il est nécessaire d'avoir une interface graphique, par exemple en utilisant le service xrdp
rpicam-hello --timeout 10000 -p 50,50,640,480 --vflip
Affiche en mode pré-visualisation une image de 640X480 à 50x50 pixels du coin haut gauche (le --vflip est nécessaire car la caméra est ici en position tête en bas)
6.1.2 rpicam-jpeg
Cette commande permet de capturer une image depuis la caméra, une pré-visualisation est activée puis l'image est acquise. Nombreux paramètres dispobibles.
rpicam-jpeg --output test.jpg --timeout 2000 --width 640 --height 480
Acquiert une image de taille 640x480 avec une pré-visualisation de 2 secondes.
6.1.3 rpicam-still
Cette commande permet d'acquérir une image ou des séquences d'images pour former une vidéo. De très nombreuses options issues de la commande obsolète raspistill sont disponibles, voir la documentation. Il est possible par exemple de prendre des images à intervalle de temps régulier pour faire une vidéo accélérée d'un événement lent. Il est aussi possible de choisir des formats variés et d'enregistrer des métadonnées.
rpicam-still --timeout 2000 --encoding png --output test.png --width 640 --height 480
Acquiert une image au format png de taille 640x480 avec une pré-visualisation de 2 secondes.
6.1.4 rpicam-vid
Cette commande permet a deux effets elle permet d'acquérir et d'enregistrer une vidéo dans un format qui peut être choisi et elle affiche une pré-visualisation de la capture. Il y a énormément d'options possibles permettant d'adapter la capture au besoin.
rpicam-vid -n -t 10s -o test.h264
Enregistre une vidéo de 10s sans prévisualisation avec le codec h264, le résultat est le suivant :
ffprobe test.h264
Input #0, h264, from 'test.h264':
Duration: N/A, bitrate: N/A
Stream #0:0: Video: h264 (High), yuv420p(progressive), 640x480, 25 fps, 60 tbr, 1200k tbn
Pour produire du mp4 sur une raspberryPi4 utiliser
rpicam-vid -n -t 10s --codec libav -o test.mp4
Pour modifier le mode de capture :
--mode arg : Camera mode as W:H:bit-depth:packing, where packing is P (packed) or U (unpacked)
6.1.5 rpicam-raw
Enregistre sans pré-visualisaton un flux vidéo brut depuis la caméra.
6.1.6 rpicam-detect
Cette commande affiche une fenêtre d'aperçu et surveille le contenu à l'aide d'un réseau neuronal Google MobileNet v1 SSD (Single Shot Detector) entraîné pour identifier environ 80 classes d'objets à l'aide du jeu de données Coco. Rpicam-Detect reconnaît les personnes, les voitures, les chats et de nombreux autres objets.
6.2 Mise en oeuvre de webcams (USB)
Plusieurs commandes permettent d'utiliser une caméra connectée sur un port USB.
* v4l2-ctl fournit toutes les informations sur l'état de la vidéo sur la raspi
* fswebcam outil de capture
* ffmpeg couteau suisse de la vidéo (énormément de possibilités et d'options)
L'usage est l'usage standard d'une webcam USB sous linux. Par exemple :
- pour voir sur l'écran une capture vidéo
ffplay -f v4l2 -i /dev/video1 - pour enregistrer la vidéo
ffmpeg -f v4l2 -i /dev/video1 output.mp4
6.3 Streaming
6.3.1 Mediamtx
Installation de MediaMtx avec le user motion
cd Logiciels/
mkdir MediaMTX
cd MediaMTX/
wget https://github.com/bluenviron/mediamtx/releases/download/v1.21.0/mediamtx_v1.21.0_linux_arm64.tar.gz
tar xvfz mediamtx_v1.21.0_linux_arm64.tar.gz
Une fois installé il est possible de tester mediamtx en le lançant directement depuis le répertoire d'installation.
./mediamtx
MediaMTX v1.21.0, linux, arm64
configuration loaded from /home/tremplin/Logiciels/Mediamtx/mediamtx.yml
[RTSP] started with listeners on :8554 (TCP/RTSP), :8000 (UDP/RTP), :8001 (UDP/RTCP)
[RTMP] started with listener on :1935 (TCP/RTMP)
[HLS] started with listener on :8888 (TCP/HTTP)
[WebRTC] started with listeners on :8889 (TCP/HTTP), :8189 (UDP/ICE)
[SRT] started with listener on :8890 (UDP/SRT)
[MoQ] started with listeners on :8892 (TCP/HTTP2), :8892 (UDP/HTTP3), :8893 (UDP/QUIC)
#arrêter avec `Ctrl-c`
mediamtx fonctionne correctement et à ouvert les ports de diffusion énumérés ci-dessus. On peut passer maintenant à la mise en œuvre d'un service permettant de gérer mediamtx. Passer en administrateur.
sudo jed /etc/systemd/system/mediamtx.service
[Unit]
Description=mediaMTX media stream server
After=network.target
[Service]
User=motion
RuntimeDirectory=/home/motion/MediaMTX
LogsDirectory=/home/motion/MediaMTX
ExecStart=/home/motion/MediaMTX/mediamtx /home/motion/MediaMTX/mediamtx.yml
Restart=on-abort
[Install]
WantedBy=multi-user.target
Modifier le fichier de configuration de MediaMtx en fonction des besoins
sudo su motion
jed MediaMTX/mediamtx.yml
sed -e '/^\s*#.*$/d' -e '/^\s*$/d' mediamtx.yml
Une fois lancé par sudo systemctl start mediamtx, les flux suivants sont ouverts (Configurer le pare-feu pour les laisser passer)
sudo netstat -lntpe | grep mediamtx
tcp6 0 0 :::1935 :::* LISTEN 1009 23643 4536/mediamtx
tcp6 0 0 :::8554 :::* LISTEN 1009 23641 4536/mediamtx
tcp6 0 0 :::8892 :::* LISTEN 1009 23648 4536/mediamtx
tcp6 0 0 :::8888 :::* LISTEN 1009 23645 4536/mediamtx
tcp6 0 0 :::8889 :::* LISTEN 1009 19424 4536/mediamtx ```
On récupère le flux en http ou autres cf [doc](https://github.com/Tyicenet/Raspberry-Pi-RTSP-Camera-Setup-with-MediaMTX)
```shell
browser -> http://192.168.10.53:8889/cam/
vlc -> rtsp://192.168.10.53:8554/cam
shell -> ffplay rtsp://192.168.10.53:8554/cam
Doc mediamtx avec ffmpeg
https://mediamtx.org/docs/publish/ffmpeg
6.3.2 Autres caméras
mediamtx fonctionne pour d'autres types de cameras en particulier les caméras USB, cela simplifie les choses et racourcit (semble-t-il) le lag. Il suffit de rajouter une caméra dans la configuration /home/motion/MediaMTX/mediamtx.yml dans la solution testée le flux est créé depuis la configuration de mediamtx, une version plus progressive serait de créer le flux d'une part et de le streamer via medimtx d'autre part ce qui conduirait à l'exemple commenté ci-dessous.
# example:
# my_camera:
# source: rtsp://my_camera
# Settings under path "all_others" are applied to all paths that
# do not match another entry.
cam1:
runOnInit: ffmpeg -f v4l2 -i /dev/video1 -pix_fmt yuv420p -video_size 640x480 -framerate 30 -preset ultrafast -c:v libx264 -b:v 6000k -f rtsp rtsp://localhost:$RTSP_PORT/$MTX_PATH
runOnInitRestart: yes
all_others:
ffplay -rtsp_transport tcp -i rtsp://login:password@192.168.***.***:554/stream1
ffmpeg -i input -listen 1 -f mp4 -movflags frag_keyframe+empty_moov http://localhost:8080
ffmpeg -i rtsp://login:password@192.168.***.***:554/stream1 -x 1280 -y 720 -an -c:v h264 -f flv rtmp://livestream.tremplin.ens-lyon.fr:1935/liverec/test.flv
ffmpeg -i rtsp://login:password@192.168.***.***:554/stream1 -vf "scale=1280:720" -an -c:v h264 -f flv rtmp://livestream.tremplin.ens-lyon.fr:1935/liverec/test.flv
ffmpeg -loglevel quiet -i rtsp://login:password@192.168.***.***:554/stream1 -vf "scale=1280:720" -an -c:v h264 -f flv rtmp://livestream.tremplin.ens-lyon.fr:1935/liverec/test.flv
ffmpeg -loglevel quiet -i rtsp://login:password@192.168.***.***:554/stream1 -vf "scale=1280:720" -an -c:v h264 -f flv rtmp://livestream.tremplin.ens-lyon.fr:1935/live/test.flv
ffmpeg -i rtsp://login:password@192.168.***.***:554/stream1 -vf "scale=1280:720" -an -c:v h264 -f flv rtmp://livestream.tremplin.ens-lyon.fr:1935/live/test.flv
ffmpeg -loglevel quiet -i rtsp://login:password@192.168.***.***:554/stream1 -vf "scale=1280:720" -an -c:v h264 -f flv rtmp://livestream.tremplin.ens-lyon.fr:1935/live/test.flv
ffmpeg -i rtsp://login:password@192.168.***.***:554/stream1 -vf "scale=1280:720" -an -c:v h264 -f flv rtmp://livestream.tremplin.ens-lyon.fr/live/test.flv
ffmpeg -loglevel quiet -i rtsp://login:password@192.168.***.***:554/stream1 -vf "scale=1280:720" -an -c:v h264 -f flv rtmp://livestream.tremplin.ens-lyon.fr:1935/live/test.flv
ffmpeg -loglevel quiet -i rtsp://login:password@192.168.***.***:554/stream1 -vf "scale=1280:720" -an -c:v h264 -f flv rtmp://livestream.tremplin.ens-lyon.fr/live/test.flv
ffmpeg -loglevel quiet -i rtsp://login:password@192.168.***.***:554/stream1 -vf "scale=1280:72Mar0" -an -c:v h264 -f flv rtmp://livestream.tremplin.ens-lyon.fr/liverec/test.flv
ffmpeg -loglevel quiet -i rtsp://login:password@192.168.***.***:554/stream1 -vf "scale=1280:720" -an -c:v h264 -f flv rtmp://livestream.tremplin.ens-lyon.fr/live/test.flv
ffmpeg -loglevel quiet -i rtsp://login:password@192.168.***.***:554/stream1 -vf "scale=1280:720" -an -c:v h264 -f flv rtmp://livestream.tremplin.ens-lyon.fr/liverec/test.flv
ffmpeg -i /dev/video0 -an -c:v h264 -f hls rtmp://livestream.tremplin.ens-lyon.fr:1935/hls/test
ffmpeg -i /dev/video0 -an -c:v h264 -f hls rtmp://livestream.tremplin.ens-lyon.fr:1935/live/test
ffmpeg -i /dev/video0 -an -c:v h264 -f flv rtmp://livestream.tremplin.ens-lyon.fr:1935/live/test
6.3.3 utilisation de nginx
Configurations nginx variées :
rtmp {
server {
listen 1935;
ping 3m;
ping_timeout 30s;
chunk_size 2048;# default 4096
access_log /var/log/nginx/rtmpaccess.log;
# Main live streaming application
application live {
live on;
record off;
# HLS packaging
hls on;
hls_path /opt/live/hls;
hls_fragment 3;
hls_playlist_length 60;
# Disable consuming the stream from nginx as rtmp
deny play all;
}
# Recording application
application liverec {
live on;
record all;
record_unique on;
record_path /opt/live/Recorded;
record_suffix -%Y%m%d-%H%M%S.flv;
record_unique on;
# disable consuming the stream from nginx as rtmp
#deny play all;
hls on;
hls_path /var/www/html/hls;
hls_fragment 3;
hls_playlist_length 60;
}
# Streaming application with authentication
application secure {
live on;
# Enable stream key authentication
on_publish http://localhost/auth;
hls on;
hls_path /var/www/html/hls;
hls_fragment 3;
hls_playlist_length 60;
}
# Transcoding (ffmpeg needed)
application big {
live on;
exec ffmpeg -re -i rtmp://localhost:1935/$app/$name \
-vcodec flv -acodec copy -s 32x32 -f flv \
rtmp://localhost:1935/small/${name};
}
application small {
live on;
# Video with reduced resolution comes here from ffmpeg
}
# application webcam {
# live on;
# # Stream from local webcam
# exec_static ffmpeg -f video4linux2 -i /dev/video0 \
# -c:v libx264 -an -f flv \
# rtmp://localhost:1935/webcam/mystream;
# }
application hls {
live on;
record all;
hls on;
hls_path /opt/live/hls/;
hls_fragment 3;
hls_playlist_length 60;
# disable consuming the stream from nginx as rtmp
# deny play all;
}
application dash {
live on;
record all;
dash on;
dash_path /opt/live/dash;
# disable consuming the stream from nginx as rtmp
deny play all;
}
}
}
Comments !