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
7 changes: 7 additions & 0 deletions eslint.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,5 +19,12 @@ export default defineConfig([
ecmaVersion: 2020,
globals: globals.browser,
},
rules: {
'@typescript-eslint/no-unused-vars': ['error', {
argsIgnorePattern: '^_',
varsIgnorePattern: '^_',
caughtErrorsIgnorePattern: '^_',
}]
}
},
])
14 changes: 8 additions & 6 deletions public/newsletters/2702206/draft-022026.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,33 +10,33 @@ Qui dit nouvelle année, dit nouveau thème pour la Coupe de France de Robotique

Après concertation avec l'équipe, nous avons choisi les actions qui nous semblaient les plus réalisables, tout en nous ramenant suffisamment de points. Dans cette newsletter, nous décrirons uniquement les actions que nous avons choisi de réaliser, avec la table de jeu suivante, table officielle de la CDFR 2026 :

![Table de jeu - CDFR 2026](attachments/e63d3f2d-d3bf-4ed2-b486-fb2854401849.png " =493x275")
![Table de jeu - CDFR 2026](attachments/e63d3f2d-d3bf-4ed2-b486-fb2854401849.png " =493x275")

Le robot principal partira de la zone 1, appelée le nid, pour aller vers la zone 8, où la première action a lieu : le curseur de température. À l'aide d'un bras actionné par un servo-moteur, le robot principal viendra déplacer un curseur le long de la table, où figure une échelle de température, et l'amener le plus proche des températures basses.

![Position finale du thermomètre (espérée)](attachments/4be89b77-448f-4954-913f-b98b904b4e12.png " =269x251")
![Position finale du thermomètre (espérée)](attachments/4be89b77-448f-4954-913f-b98b904b4e12.png " =269x251")

Après avoir déplacé le curseur, il passera par les zones 5 qui le séparent du nid, emportant avec lui les caisses de noisettes qui s'y trouvent, pour les ramener dans le nid, et s'y placer à son tour. La mission du robot principal est à présent terminée.

Au tour de nos PAMIs de survivre à l'hiver, pendant les 15 dernières secondes du match : il leur faut atteindre des garde-mangers (zones 6), les occuper jusqu'à la fin du match et faire bouger un actionneur, visible depuis le public, même après la fin du match.

Cependant, un PAMI sort du lot : le PAMI ninja. Il a le droit d'évoluer durant toute la durée du match, il est placé dans la zone 2 (en hauteur par rapport aux autres robots) et travaille en collaboration avec le ninja de l'équipe adverse. Le ninja a 2 missions : vider les frigos (zones 3), jusqu'alors remplis de caisses de noisettes, et remplir les frigos (zones 3) des caisses de noisettes vides situées en zone de chargement (zones 4). Les actions réalisées à cet endroit de la table donnent des points aux 2 équipes.
Cependant, un PAMI sort du lot : le PAMI ninja. Il a le droit d'évoluer durant toute la durée du match, il est placé dans la zone 2 (en hauteur par rapport aux autres robots) et travaille en collaboration avec le ninja de l'équipe adverse. Le ninja a 2 missions : vider les frigos (zones 3), jusqu'alors remplis de caisses de noisettes, et remplir les frigos des caisses de noisettes vides situées en zone de chargement (zones 4). Les actions réalisées à cet endroit de la table donnent des points aux 2 équipes.

Nous pouvons à présent détailler les spécificités de nos robots et de nos systèmes pour cette année : place au côté technique !

### Robot principal et PAMI Ninja

Le robot principal et le PAMI Ninja gardent la même architecture que l'année dernière : une Raspberry Pi 4 et notre PCB plein de connecteurs pour y brancher tous les capteurs et actionneurs. Le robot principal accueille tout de même quelques modifications : les systèmes liés à la CDFR 2025 sont retirés pour y ajouter deux bras permettant de déplacer le curseur du thermomètre (un pour chaque côté) ainsi que des améliorations sur le système d'estimation de position. En plus de ces modifications fonctionnelles, le robot principal a reçu un relooking complet !

![Le robot principal, avec un carénage en plexiglas et non en papier (c'est quand même plus stylé), aux couleurs de notre logo.](attachments/e0439810-b100-4580-8906-6052359aa179.png " =214x268")
![Le robot principal, avec un carénage en plexiglas et non en papier (c'est quand même plus stylé), aux couleurs de notre logo.](attachments/e0439810-b100-4580-8906-6052359aa179.png " =214x268")

Concernant le PAMI Ninja, il était nécessaire de faire une petite adaptation pour que le capteur d'obstacle ne détecte pas les caisses de noisettes comme un obstacle et puisse les pousser.

### Pas trop chaud, ni trop froid : le thermomètre

Pour déplacer le curseur sur le thermomètre représenté le long de la table, nous avons choisi de déployer un bras qui viendra se placer à l'intérieur du curseur, tandis que le robot avancera jusqu'à la zone de température froide. Pour cela, un peu de dimensionnement est nécessaire : il faut étudier l'écart entre le robot principal et le bord de la table afin de déterminer la longueur du bras.

![Etude de l'écartement à la table](attachments/2a92d6eb-f05b-4344-b7ba-354325d62938.jpg " =375x211")
![Etude de l'écartement à la table](attachments/2a92d6eb-f05b-4344-b7ba-354325d62938.jpg " =375x211")

Avec ces dimensions, qui respectent les contraintes de périmètre déployé, on peut construire notre bras et le système d'accroche sur l'étage principal du robot, qui lui permettra de se déployer au moment voulu.

Expand All @@ -46,7 +46,9 @@ L'année dernière, en plus du gros PAMI Superstar (devenu cette année le PAMI

Depuis le début de cette année, de nouveaux PCBs ont été désignés et un premier exemplaire a été soudé. Le PCB principal contient un microprocesseur STM32, le "cerveau" du PAMI, tandis que deux autres PCBs permettent de placer les capteurs d'obstacle et les boutons pour interagir avec le PAMI. Les premiers tests ont permis de montrer que les PCBs n'ont pas de grosses erreurs !

![Le PCB principal de nos nouveaux petits PAMIs lors de la pose des composants.](attachments/3ca55032-5f23-4738-8d3e-e380cb03d3b9.png " =428x250")Désormais, il s'agit de tester les composants qui permettront de détecter un obstacle, faire avancer le PAMI, et créer les pièces mécaniques qui constitueront le PAMI.
![Le PCB principal de nos nouveaux petits PAMIs lors de la pose des composants.](attachments/3ca55032-5f23-4738-8d3e-e380cb03d3b9.png " =428x250")

Désormais, il s'agit de tester les composants qui permettront de détecter un obstacle, faire avancer le PAMI, et créer les pièces mécaniques qui constitueront le PAMI.

On vous parlera de tout ça lors de notre prochaine newsletter, qui mettra *(normalement)* moins de temps à sortir que celle-ci…

Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified public/restricted-assets/cdroms/members/sk.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
66 changes: 66 additions & 0 deletions src/pages/Home.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@

.parallax {
height: calc(100vh - 42px);
width: 100vw;
overflow-x: hidden;
overflow-y: hidden;
}

.parallax-layer {
position: absolute;
height: calc(100vh - 42px);
width: 100vw;
}

.background {
background: url('../../public/assets/home.jpg') no-repeat fixed center;
z-index: 0;
}

.logo-container {
display: flex;
}

.logo {
margin: auto;
background: url('../../public/restricted-assets/cdroms/logos/cdroms-500x500.png') no-repeat center;
background-size: max(20vw, 20vh, 250px);
width: max(20vw, 20vh, 250px);
height: max(20vw, 20vh, 250px);
z-index: 1;
animation: 3s cubic-bezier(.22, .61, .36, 1) 0s normal forwards 1 appears;
}

.logo-leaves {
animation: 3s cubic-bezier(.22, .61, .36, 1) 0s normal forwards 1 disappears;
}

@keyframes appears {
0% {
opacity: 0;
transform: translateX(-400px) rotate(-180deg);
}
33% {
opacity: 0;
transform: translateX(-400px) rotate(-180deg);
}
100% {
opacity: 1;
transform: translateX(0) rotate(0deg);
}
}

@keyframes disappears {
0% {
opacity: 1;
transform: translateX(0) rotate(0deg);
}
33% {
opacity: 1;
transform: translateX(0) rotate(0deg);
}
100% {
opacity: 0;
transform: translateX(400px) rotate(180deg);
}
}
61 changes: 52 additions & 9 deletions src/pages/Home.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,60 @@
import * as React from "react";

import {useMemo, useState} from "react";
import "./Home.scss";

const Home: React.FC = () => {
const [_, setDisappearsTrigger] = useState<number | null>(null);

const hideLogo = useMemo(() => {
return (logo: HTMLElement) => {
logo.style.display = "none";
}
}, []);
const enterLogo = useMemo(() => {
return (event: React.MouseEvent<HTMLDivElement>) => {
// Prevent creating trigger while the logo appears
const logo = event.target as HTMLElement;
for (const animation of logo.getAnimations()) {
if (animation.playState != "finished")
return;
}
// Create a timeout to trigger the animation of disappearance
console.log("Trigger created")
const timeout = setTimeout(() => {
setDisappearsTrigger((trigger) => {
if (trigger != null)
clearTimeout(trigger);
return null
});
const logo = event.target as HTMLElement;
console.log("Trigger triggered")
console.log(logo)
logo.classList.add("logo-leaves");
logo.onanimationend = () => hideLogo(logo);
}, 5000);
setDisappearsTrigger(timeout);
}
}, [hideLogo, setDisappearsTrigger]);
const leaveLogo = useMemo(() => {
return () => {
setDisappearsTrigger((trigger) => {
if (trigger != null) {
console.log("Trigger removed")
clearTimeout(trigger);
}
return null
});
}
}, [setDisappearsTrigger]);

return (
<>
<img style={{
height: "calc(100vh - 42px)",
minWidth: "100vw",
width: "auto",
objectFit: "cover",
objectPosition: "30% 40%",
}} src="/assets/home.jpg" alt="image"/>
<div className="parallax">
<div className="parallax-layer background"/>
<div className="parallax-layer logo-container">
<div className="logo" onMouseEnter={enterLogo} onMouseLeave={leaveLogo}></div>
</div>
</div>
<div className="container mb-5">
<div className="row justify-content-center mt-5">
<div className="col-md-8">
Expand Down Expand Up @@ -68,7 +112,6 @@ const Home: React.FC = () => {
</div>
</div>
</div>

</>
)
};
Expand Down