Compare commits

..

No commits in common. "02ae6a6a037bda152a027c57a3c578937c222651" and "be166899c5276cc36a75fd70a16e075699f1b850" have entirely different histories.

21 changed files with 729 additions and 344 deletions

View File

@ -1,28 +0,0 @@
name: Build and deploy blog
on:
push:
branches:
- master
jobs:
Build-and-deploy:
runs-on: alpine
steps:
- name: Install dependencies
run: |
apk add git openssh zola rsync
- name: Check out repository code
uses: actions/checkout@v4
with:
submodules: 'recursive'
- name: Build blog
run: |
zola build
- name: Deploy blog using rsync
run: |
eval $(ssh-agent -s)
echo "${{ secrets.SSH_PRIVATE_KEY }}" | tr -d '\r' | ssh-add -
mkdir -p ~/.ssh
chmod 700 ~/.ssh
rsync -e "ssh -o StrictHostKeyChecking=no -p ${{ secrets.SSH_PORT }}" -rvz ./public/ ${{ secrets.SSH_DESTINATION }}:/var/www/blog.louis-vallat.dev/ --delete

21
.gitlab-ci.yml Normal file
View File

@ -0,0 +1,21 @@
image: alpine
variables:
GIT_SUBMODULE_STRATEGY: recursive
stages:
- deploy
deploy:
stage: deploy
before_script:
- apk add openssh zola rsync
- eval $(ssh-agent -s)
- echo "$SSH_PRIVATE_KEY" | tr -d '\r' | ssh-add -
- mkdir -p ~/.ssh
- chmod 700 ~/.ssh
script:
- zola build
- rsync -e "ssh -o StrictHostKeyChecking=no -p $SSH_PORT" -rvz ./public/ $SSH_DESTINATION:/var/www/blog.louis-vallat.fr/ --delete
only:
- master

View File

@ -1,6 +1,6 @@
# Blog # Blog
> This is the source code from [this live website](https://blog.louis-vallat.dev). > This is the source code from [this live website](https://blog.louis-vallat.fr).
Build it using [Zola](https://www.getzola.org): Build it using [Zola](https://www.getzola.org):

View File

@ -1,36 +1,35 @@
base_url = "https://blog.louis-vallat.dev" base_url = "https://blog.louis-vallat.fr"
title = "Louis' thoughts" title = "Le blog de Louis"
description = "The very simple blog of a very complex developer." description = "Le blog très simple d'un développeur très compliqué."
theme = "terminimal" theme = "terminimal"
compile_sass = true compile_sass = true
default_language = "en" default_language = "fr"
generate_feeds = true generate_feed = true
feed_filenames = ["atom.xml"] feed_filename = "atom.xml"
taxonomies = [ taxonomies = [
{name = "tags"}, {name = "tags"},
{name = "categories"}
] ]
[markdown] [markdown]
highlight_code = true highlight_code = true
[extra] [extra]
logo_text = "Louis' thoughts" logo_text = "Le blog de Louis"
author = "Louis Vallat" author = "Louis Vallat"
page_titles = "combined" page_titles = "combined"
accent_color = "blue"
background_color = "blue"
enable_post_view_navigation = true enable_post_view_navigation = true
post_view_navigation_prompt = "More" post_view_navigation_prompt = "En savoir plus"
menu_items = [ menu_items = [
{name = "blog", url = "$BASE_URL"}, {name = "blog", url = "$BASE_URL"},
{name = "tags", url = "$BASE_URL/tags"}, {name = "tags", url = "$BASE_URL/tags"},
{name = "archive", url = "$BASE_URL/archive"}, {name = "archive", url = "$BASE_URL/archive"},
{name = "portfolio", url = "https://louis-vallat.dev"}, {name = "portfolio", url = "https://louis-vallat.fr"},
{name = "gitlab", url = "https://gitlab.com/lovallat", newtab = true}, {name = "gitlab", url = "https://gitlab.com/lovallat", newtab = true},
] ]

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 11 KiB

View File

@ -0,0 +1,260 @@
+++
title = "Git Workflow"
description = "Git est un outil de versionnage très utile, voici comment je m'en sers."
date = 2021-05-10
[taxonomies]
tags = ["git", "workflow"]
+++
Git est un outil de versionnage très utile, voici comment je m'en sers.
<!-- more -->
> À noter que ce guide est destiné aux personnes qui ont déjà utilisé git auparavant,
> il ne s'agit pas ici d'un tutoriel pour débutants (bien que je sois ici assez
> exhaustif dans mes explications).
[TL;DR](#tldr)
## Les fondations
Vous êtes bien installé devant votre écran, les doigts ne demandent qu'à
furieusement taper les touches de votre clavier, mais avant le top départ, il faut
préparer le terrain ! Voici quelques commandes **primordiales** (pour ne pas dire
**obligatoires**) à réaliser avant de se lancer dans un projet.
Premièrement, je n'aime pas la manière qu'a git de faire des commits de fusion
lors d'un pull qui se passe mal (divergence entre votre version locale et distante
par exemple, aka. vous avez committé et quelqu'un d'autre aussi en même temps).
Nous allons donc demander à git de ne pull que lorsque l'historique est linéaire
(fast-forward), et sinon de faire automatiquement un rebase :
```bash
git config pull.rebase true
```
En cas de divergence, un simple `git rebase origin/branche_concernée` vous sortira
d'affaire !
Ensuite, il nous arrive de vouloir avoir une vue plus graphique de notre historique
git. Voici un alias, à placer dans votre `~/.gitconfig`, qui vous permet d'afficher
un graphique de vos branches et vos commits de manière plus visuelle que le `git log`
de base de git (honteusement volés [ici](https://stackoverflow.com/a/9074343)) :
```conf
[alias]
lg1 = log --graph --abbrev-commit --decorate --format=format:'%C(bold blue)%h%C(reset) - %C(bold green)(%ar)%C(reset) %C(white)%s%C(reset) %C(dim white)- %an%C(reset)%C(bold yellow)%d%C(reset)' --all
lg2 = log --graph --abbrev-commit --decorate --format=format:'%C(bold blue)%h%C(reset) - %C(bold cyan)%aD%C(reset) %C(bold green)(%ar)%C(reset)%C(bold yellow)%d%C(reset)%n'' %C(white)%s%C(reset) %C(dim white)- %an%C(reset)' --all
lg = !"git lg1"
```
Si vous n'avez pas besoin d'autant de décorations, ou que vous ne pouvez pas définir
d'alias, cette commande fait quelque chose d'assez similaire :
```bash
git log --all --decorate --oneline --graph
```
Pour avoir des messages de commits unifiés et cohérents avec de jolis alias :
```conf
fix = "!f() { git commit -sm \"fix: $1\"; }; f"
feat = "!f() { git commit -sm \"feat: $1\"; }; f"
misc = "!f() { git commit -sm \"misc: $1\"; }; f"
wip = "!f() { git commit -sm \"wip: $1\"; }; f"
```
## Des branches, des branches, et encore des branches
Quand on travaille à plusieurs sur git, il devient presque obligatoire d'avoir
des branches pour éviter de se sentir "à l'étroit" dans son `repo`. Pour pouvoir
collaborer et avancer sur un projet en groupe sans se marcher sur les pieds les
uns des autres, les branches deviennent l'outil indispensable de git.
J'utilise les branches de la manière suivante :
- les branches ont une durée de vie **très courte**
- une fois que la branche a rempli son rôle et qu'elle a été fusionnée, elle doit être supprimée
- une branche par fonctionnalité ou par résolution de problème
- les noms des branches sont libres *tant qu'ils sont clairs*
- c'est mieux d'avoir comme nom la fonctionnalité développée ou son rôle
- lorsqu'une branche sert à développer une résolution de bug ou un `fix`, il est mieux de l'inclure dans le nom
- lorsque vous travaillez à plusieurs sur la même fonctionnalité, il est conseillé de
faire une branche par personne en partant de la branche princpale de cette fonctionnalité
Évidemment, une branche fait exception : `master` (ou `main`, peu importe),
qui est une version "propre", "stable", et qui doit présenter le projet dans un état
fonctionnel, tel qu'il serait montré à un client ou à un responsable.
Il est possible d'avoir une seconde branche sur les projets plus importants, qui se
nomme alors `develop` et qui est la version en développement actif d'un projet,
mais qui ne peut pas être fusionnée sur la branche princpale pour des raisons de
stabilité par exemple, ou qui n'est pas prête pour la mise en production.
Pour créer une branche fille à partir de la branche sur laquelle vous êtes :
```bash
git checkout -b nom_de_la_nouvelle_branche
```
Et pour basculer de branche en branche :
```bash
git checkout nom_de_la_branche
```
Si vous ne savez pas sur quelle branche vous vous trouvez, vous pouvez faire :
```bash
git branch
```
## Rebaser, c'est la clef
> Cette partie peut être ignorée si vous ne pouvez pas réaliser de `push force`
> (ou équivalent). En effet, un `rebase` modifie fondamentalement l'historique de
> votre git. Si vous n'êtes pas sûr de vous, n'en faites pas. Je ne suis pas
> responsable si vous perdez des données.
Votre fonctionnalité est développée et testée, vous voulez la fusionner avec votre
branche parente ? Vous voulez récupérer ce qui est sur votre branche parente et
que vous aimeriez récupérer sur la votre ? Il est temps de rebase !
Lorsque l'on crée une branche, celle-ci a un `commit` de "départ", depuis lequel
elle se *base* pour faire du versionnage en parallèle des autres branches. Parfois
il est nécessaire de récupérer du travail qui a été mis sur la branche mère dans
notre branche de travail, par exemple la résolution d'un bogue handicapant.
Un `rebase` va faire changer votre commit de départ et l'échanger avec un autre.
Prenons le schéma suivant :
![Schéma d'un rebase](images/git_rebase.svg)
Nous avons ici la branche `new_feature` qui part d'un commit de master. Disons
que vous êtes en train de développer une fonctionnalité importante, et qu'un bug
vous ralentit dans l'exécution de vos tests, mais qu'il a été réglé après la création
de votre branche, et qu'il est disponible sur `master`. Pour le récupérer sur votre
branche, vous n'avez qu'à `rebase` votre branche sur la dernière version de `master`.
La commande pour faire ceci serait alors :
```bash
git rebase nom_de_branche_parente
```
Il est important de noter que vous risquez d'avoir des conflits au cours de cette
opération. En cas de conflit, vous pouvez les régler, puis faire `git add fichier_en_conflit`
et enfin `git rebase --continue`. Cela aura pour effet de **réécrire** l'historique
git de votre branche, d'où l'importance de faire un push en force, puisque votre
version locale et la/les version(s) distante(s) n'auront plus rien à voir.
### Quel rapport avec ce git flow
Comme dit plus haut, les branches ont une existence précise et bien définie dans
le temps. Une branche n'a pas a être fusionnée dans sa branche parente tant que
son contenu n'est pas complet, ou au moins utilisable. Cela ne fait pas vraiment
de sens de "polluer" une branche parente dans le seul but d'en récupérer le nouveau
contenu. Les opérations de rebase sont donc ici fréquentes.
## Fusion non préparée = fusion refusée
Votre fonctionnalité ou correctif est terminé(e), votre branche est prête à être
fusionnée ? En vérité, pas tout à fait. Il faut maintenant préparer la fusion !
Afin de faciliter au maximum la fusion de votre branche, il va falloir faire un
dernier rebase. Le but de ce rebase est ici de vérifier que le rôle de la branche
et du contenu qu'elle propose sont toujours fonctionnels et qu'aucun bogue n'a été
intruduit par les nouveautés disponibles sur la branche parente. Cela va aussi
vous permettre de gérer les conflits avec la branche mère au sein même de la votre.
Une fusion n'introduira donc pas de bogue, et vous restez pleinement responsable
de votre branche.
Enfin, vous n'êtes pas responsables de la fusion, un collègue ou responsable va
d'abord vérifier votre code et le contenu que vous apportez et approuver (ou rejeter)
la fusion que vous demandez. Grâce aux opérations de rebasage successifs que vous
avez fait durant la durée de vie de votre branche, la fusion se fera sans encombre.
À noter que si vous avez des outils tels que les [Merge Requests](https://docs.gitlab.com/ee/user/project/merge_requests/getting_started.html)
chez GitLab, ou [Pull Requests](https://docs.github.com/en/github/collaborating-with-issues-and-pull-requests/about-pull-requests)
chez GitHub, n'hésitez surtout pas à les utiliser ! Ces outils permettront de garder
un suivi des fusions, et d'expliquer son but à un responsable qui ne les a pas
forcément toutes en tête.
Pour fusionner une branche dans celle sur laquelle vous vous trouvez :
```bash
git merge nom_de_la_branche_à_fusionner_dans_celle_sur_laquelle_vous_êtes
```
## Au revoir vieille branche
> Les opérations décrites ici peuvent entraîner une perte de code. Je ne suis pas
> responsable si vous supprimez une branche avant qu'elle n'ait été fusionnée.
> Ne supprimez une branche que si vous êtes sûr qu'elle n'a plus d'utilité.
Votre branche est désormais fusionnée ? C'est la fin pour elle, il est désormais
temps de lui dire au revoir !
Commençons d'abord par la supprimer sur le repo distant :
```bash
git push -d origin nom_de_branche
```
Ici, le serveur distant s'appelle `origin`, comme c'est le cas la plupart du temps.
Vos collègues peuvent synchroniser leurs branches et faire disparaître leurs
références locales à des branches fantômes distantes avec la commande `git fetch -p` (le
`-p` étant ici pour "prune").
Enfin, il est temps de supprimer votre copie locale de cette branche :
```bash
git branch -d nom_de_branche
```
À noter que le `-d` ne supprimera votre branche que si elle a été fusionnée. Il est
possible de forcer la suppression d'une branche locale non fusionnée avec l'option
`-D` qui équivaut à un `git --delete --force` sur la branche.
"Don't cry because it's over, smile because it happened." - *Dr. Seuss*
## TL;DR {#tldr}
On commence par demander à git de ne pull que s'il n'y a pas de divergence avec
la version distante de notre branche, et sinon, de rebase notre branche automatiquement :
```bash
git config pull.rebase true
```
Ensuite on utilise une branche par fonctionnalité et par correctif. Une branche a
un rôle précis et une durée de vie très courte. Lorsque plusieurs développeurs
travaillent sur la même branche, ils ne doivent pas exclure la possibilité de créer
des branches personnelles.
`master` est en tous temps propre et présentable. Une branche intermédiaire peut
être utilisée pour éviter de polluer inutilement la branche principale. Elle pourra
s'appeler `develop` par exemple.
Les rebase sont fréquents et servent à récupérer sur une branche fille du nouveau
contenu de sa branche mère.
La fusion se déroule sans accroc, un rebase doit être fait avant pour gérer les
conflits sur la branches fille.
Une fois la branche fusionnée, elle doit être supprimée.
## Informations supplémentaires
### Vocabulaire
- `repo` : raccourci de `repository`, qui est l'environnement de travail de git,
c'est là dedans que l'on créé ses branches, et que l'on versionne son travail.
### Pour aller plus loin
- Le fonctionnement des objets, commits et arbres sur git (en profondeur) : [vidéo](https://youtu.be/MyvyqdQ3OjI).
- Le fonctionnement des branches sur git (en profondeur) : [vidéo](https://youtu.be/mhZQRBp8dXE).
- Comment git stocke son arborescence de fichiers : [article](https://book.git-scm.com/book/en/v2/Git-Internals-Git-Objects).
- Les commandes associées à `git branch` : [documentation](https://git-scm.com/docs/git-branch).

View File

@ -0,0 +1,286 @@
+++
title = "Robot timide le robot qui fuit la lumière"
description = "Création d'un robot timide pour un projet scolaire."
date = 2022-05-19
[taxonomies]
tags = ["maker", "fablab", "robotique"]
+++
Création d'un robot timide pour un projet scolaire.
> Article cloné depuis [Eirlab](https://www.eirlab.net/2022/05/19/robot-timide-le-robot-qui-fuit-la-lumiere/)
Dans le cadre de loption Makers proposée en deuxième année à lENSEIRB-MATMECA,
en filière Informatique, un robot timide a vu le jour au sein dEirlab.
Cet article est un guide pour expliquer comment reproduire notre travail, dans
le plus pur esprit Maker.
<!-- more -->
![Une vue de 3/4 face du robot finalisé](images/robot_timide_header.jpg)
## Concept de base
Nous voulions mettre en oeuvre un robot qui détecterait en temps réel la
luminosité autour de lui et ce dans le but de se déplacer vers lendroit le
plus sombre de la pièce dans lequel il se trouve, et de sy cacher. Un autre
mode est aussi disponible, permettant non pas daller vers lendroit le plus
sombre, mais à linverse de fuir lendroit le plus lumineux, pour avoir deux
manières de voir le problème.
![Une vue de face du robot timide dans sa forme finale.](images/robot_timide_enseirb.jpg)
## Du matériel
Avant de pouvoir travailler sur une partie logicielle du projet, il faut
évidemment avoir une base physique pour accueillir et exécuter ce code.
À noter que ce projet na nécessité aucune dépense et a été réalisé entièrement
avec du matériel déjà disponible au sein du Fablab.
### Liste du matériel
Pour pouvoir reproduire ce projet, il vous faudra avoir en votre possession les
éléments suivants :
- 1x Arduino Uno (ou clone équivalent) cest la tête pensante de ce projet
- 1x Arduino Motor Shield pour contrôler les deux moteurs du robot
- 2x moteurs à courant continu, ici des FT DC 130D pour se mouvoir dans lespace
- 3x capteurs de distance à ultrasons HC-SR04 pour éviter de rencontrer des murs trop souvent
- 4x photo résistances une par côté, pour pouvoir détecter la luminosité autour de lui
- 4x résistances de 2kΩ pour le circuit des photo résistances, permettant davoir une amplitude optimale
- 1x pile 9 Volts pour alimenter tout le système
- 1x boîtier pour pile 9 Volts [OPTIONNEL] pour éviter de perdre lunique source dalimentation du robot
### Base du châssis
Le châssis est une plaque en bois, ici du contreplaqué de 5 millimètres
dépaisseur, qui a été usinée à laide de la découpeuse laser du Fablab. Elle
mesure 17×15,5 centimètres, et dispose de deux bords biseautés pour avoir une
vue frontale des obstacles que le robot pourrait rencontrer. Ici, ces biseaux
ont des angles de 20 degrés, sur 4,5 centimètres. La plaque de base est ensuite
percée pour accueillir les différents modules du robot. Les éléments les plus
légers ou risquant moins de se détacher sont fixés par un simple système de
mâchoire, prenant en étau la plaque de bois dans une forme de U.
![La forme de U pour prendre la plaque de base en mâchoire et tenir un capteur par pression.](images/u_shape.jpg)
### Alimentation
Pour lalimentation du robot, on vient envoyer 9 Volts dune source quelconque,
dune pile ou dune alimentation stabilisée par exemple, dans lentrée `VIN`
de lArduino, qui sera après régulée en interne pour donner les différents
rails dalimentation. Cette entrée dalimentation est connectée en interne au
port DC “barrel jack” de lArduino, donc avant les régulateurs de courant,
et prend donc des tensions entre 5 et 9 Volts.
Dans ce projet, nous utilisons une pile 9 Volts rechargeable dans un boîtier
vissé au châssis.
![Une vue de la pile 9 Volts que nous utilisons, rechargeable en micro USB.](images/pile9v.jpg)
### Moteurs
Les moteurs ici sont vissés au châssis, car juste pris en mâchoire ils ne
tiennent pas et se détachent à la moindre accélération.
Ils sont directement alimentés et pilotés via la carte Arduino Motor Shield,
qui permet de sélectionner leur vitesse sur une échelle de `0` à `255`,
dactionner les freins et de leur donner un sens de rotation, et ce très
simplement dans le code.
Des roues ont été imprimées en 3D pour aller sur les embouts des moteurs, et un
joint torique sert de pneu pour améliorer ladhérence du robot et éviter les
démarrage en “burn”.
### PCB
Au début de ce projet, nous avons utilisé une carte de prototypage électronique,
aussi appelé breadboard. Dans un second temps et pour éviter toute déconnexion
de câbles liée à une potentielle accélération violente, nous avons fait un PCB,
soudé manuellement sur une carte de prototypage prévu à cet effet.
![Une vue du dessus de notre PCB fait main.](images/pcb_irl.jpg)
Au niveau électronique, le PCB est routé de la manière suivante :
![Le routage du PCB sur une carte de protypage de type Breadboard.](images/pcb_fritzing.png)
Les différents composants viennent se connecter sur le PCB au moyen de
différentes broches femelles, pour que ce dernier puisse être détaché et modifié
sans devoir dessouder le moindre composant.
## Et du logiciel
Dun point de vue logiciel, notre projet est assez simple. En pseudo-algorithme,
on peut tout simplement le résumer à “on regarde parmi les 4 photo résistances
et on tourne ou avance vers celle ayant la valeur la plus sombre” dans le cas
`followDark` est à `true`. Si au contraire cette valeur est à `false`, alors
il ira dans la direction opposée à la photorésistance ayant la plus haute valeur.
Une mesure des distances en face des trois capteurs à ultrasons permet darrêter
le robot (presque) avant collision frontale, et le robot ne se déplacera pas
tant que lobjet en face est toujours présent, et donc en théorie tant quil a
trouvé lendroit le plus sombre.
```cpp
#define echo1Pin 5
#define trig1Pin 4
#define echo2Pin 7
#define trig2Pin 6
#define echo3Pin 10
#define trig3Pin 2
#define rotMot1Pin 12
#define brakeMot1Pin 9
#define vitMot1Pin 3
#define rotMot2Pin 13
#define brakeMot2Pin 8
#define vitMot2Pin 11
#define photoRes1Pin A2
#define photoRes2Pin A3
#define photoRes3Pin A4
#define photoRes4Pin A5
#define followDark false
long duration;
int distance;
void setup() {
Serial.begin(9600);
pinMode(rotMot1Pin, OUTPUT);
pinMode(brakeMot1Pin, OUTPUT);
pinMode(vitMot1Pin, OUTPUT);
pinMode(rotMot2Pin, OUTPUT);
pinMode(brakeMot2Pin, OUTPUT);
pinMode(vitMot2Pin, OUTPUT);
pinMode(photoRes1Pin, INPUT);
pinMode(photoRes2Pin, INPUT);
pinMode(photoRes3Pin, INPUT);
pinMode(photoRes4Pin, INPUT);
pinMode(trig1Pin, OUTPUT);
pinMode(echo1Pin, INPUT);
pinMode(trig2Pin, OUTPUT);
pinMode(echo2Pin, INPUT);
pinMode(trig3Pin, OUTPUT);
pinMode(echo3Pin, INPUT);
delay(3000);
}
void loop(){
byte echoPins[3] = {echo1Pin,echo2Pin,echo3Pin};
byte trigPins[3] = {trig1Pin,trig2Pin,trig3Pin};
long int durations[3] = {};
long int distances[3] = {};
for(int i = 0; i < 3; i++){
digitalWrite(trigPins[i], LOW);
delayMicroseconds(2);
digitalWrite(trigPins[i], HIGH);
delayMicroseconds(10);
digitalWrite(trigPins[i], LOW);
durations[i] = pulseIn(echoPins[i], HIGH);
distances[i] = durations[i] * 0.034 / 2;
}
int photoRes[4] = {};
Serial.print("Capteur infra : 1[");
photoRes[0] = analogRead(photoRes1Pin);
Serial.print(photoRes[0]);
Serial.print("] 2[");
photoRes[1] = analogRead(photoRes2Pin);
Serial.print(photoRes[1]);
Serial.print("] 3[");
photoRes[2] = analogRead(photoRes3Pin);
Serial.print(photoRes[2]);
Serial.print("] 4[");
photoRes[3] = analogRead(photoRes4Pin);
Serial.print(photoRes[3]);
for(int i = 0; i < 3; i++){
Serial.print("] - distance(cm) : ");
Serial.print(distances[i]);
}
Serial.println();
bool b = false;
for(int i = 0; i < 3; i++){
if (distances[i] < 30) {
b= true;
}
}
int photoResRef = photoRes[0];
bool photoStop = true;
int photoResMinPos = 0;
if (followDark){
int photoResMin = 1024;
for (int i = 0; i < 4; i++){
if (photoResMin > photoRes[i]){
photoResMin = photoRes[i];
photoResMinPos = i;
}
if (abs(photoResRef - photoRes[i]) > 20){
photoStop = false;
}
}
} else{
int photoResMax = 0;
for (int i = 0; i < 4; i++){
if (photoResMax < photoRes[i]){
photoResMax = photoRes[i];
photoResMinPos = (i + 2)%4;
}
if (abs(photoResRef - photoRes[i]) > 20){
photoStop = false;
}
}
}
Serial.println(photoResMinPos);
if (b || photoStop){
digitalWrite(brakeMot1Pin, HIGH);
digitalWrite(brakeMot2Pin, HIGH);
} else {
digitalWrite(brakeMot1Pin, LOW);
digitalWrite(brakeMot2Pin, LOW);
}
if (photoResMinPos == 0){
digitalWrite(rotMot1Pin, LOW);
digitalWrite(rotMot2Pin, LOW);
}
if (photoResMinPos == 1){
digitalWrite(rotMot1Pin, LOW);
digitalWrite(rotMot2Pin, LOW);
}
if (photoResMinPos == 2){
digitalWrite(rotMot1Pin, HIGH);
digitalWrite(rotMot2Pin, HIGH);
}
if (photoResMinPos == 3){
digitalWrite(rotMot1Pin, HIGH);
digitalWrite(rotMot2Pin, LOW);
}
analogWrite(vitMot1Pin, 150);
analogWrite(vitMot2Pin, 150);
}
```
## Remerciements
Merci au Fablab de lENSEIRB-MATMECA, Eirlab, pour nous avoir permis de
travailler sur ce projet et davoir contribué matériellement au projet.
Merci aussi aux différents Fabmanagers qui nous ont aidés tout au long du projet
en répondant à nos questions plus ou moins posées sous lemprise de la fatigue.
À la mémoire de Kaitlin Rooke.

View File

@ -1,294 +0,0 @@
+++
title = "Shy bot the robot which is scared of the light"
description = "Creating a shy robot for a school project."
date = 2022-05-19
[taxonomies]
tags = ["maker", "fablab", "robotics"]
+++
Creating a shy robot for a university project.
> This is a translated article of mine, original can be found on
[Eirlab](https://www.eirlab.net/2022/05/19/robot-timide-le-robot-qui-fuit-la-lumiere/)
As part of my computer science engeneering curriculum, I enrolled in an option called
"Makers" during my fourth year. From this course within
[ENSEIRB-MATMECA's makerlab](https://www.eirlab.net)
is born a shy robot, one that hates light and loves the shadows.
This article is all about explaining how it works and how you could reproduce our work, in the
most "maker" spirit.
<!-- more -->
![A 3/4th view of said robot](images/robot_timide_header.jpg)
## Base concept
We wanted to create a robot which would be able to detect, in real time,
the brightness of its surroundings, and would then use it to go in the
darkest place of the room it would be in, in order to hide (it's a shy one, remember?).
Instead of going to the darkest place it can detect, there's also another mode
available, where instead of moving towards the darkest place, it tries to
flee the brightest direction. Although looking similar, these two ways of thinking
yield to different results.
![A view of the robot in its final form.](images/robot_timide_enseirb.jpg)
## Some hardware
Before working on the software part of this project, we needed to have some hardware
to run our code on.
It should be noted that all of the components required for this project were
supplied by the fablab. We tried to only use parts that were already available,
without the need to spend a single euro for this project.
### Shopping list
In order to recreate this project, you would need these components:
- 1x Arduino Uno (or an equivalent clone) it's the brains of this whole project
- 1x Arduino Motor Shield to control the motors that will move the robot
- 2x DC motors (here FT DC 130D) to actually move the robot
- 3x ultrasonic distance sensors HC-SR04 to avoid hitting walls too often
- 4x photoresistors one per side, to be able to detect brightness around it
- 4x 2kΩ resistors for the photocell circuit, to have a better detection amplitude
- 1x 9V battery because it needs power to do anything
- 1x box for 9V batteries [optional] so the battery is safely mounted
### Chassis
The chassis for this robot is a piece of plywood, 5mm thick to be precise. It
has been machined using a laser cutter, availabe in the fablab. This plank
is about 17 by 15.5 centimeters, and has two beveled corners, which are useful
so the robot can see in front of it. The bevels have a 20 degrees angle, going on
4.5cm.
The base plate is then pierced to accomodate for the different components that
will need to be mounted on the said plate. The lighter components will be pressure
mounted, using a u-shape that will fit around the plate's side.
![The u-shape to pressure-mount the component on the plate.](images/u_shape.jpg)
### Power
For powering the robot, we want to send 9 volts, from a battery or a power supply,
in the power input `VIN` of our Arduino board. This tension will then be regulated
on the PCB to create the different power rails that would be needed. This input is
connected internally to the barrel jack of the Arduino, which can take power ranging
from 5 to 9 volts.
In this project, we are using a 9V battery which is placed in a case that is bolted
on the base plate.
![A picture of the rechargeable 9 volts battery that we are using.](images/pile9v.jpg)
### Motors
The motors are bolted to the chassis in this project, because when they were
mounted just using pressure, they would run away each time the robot made a
rough acceleration.
These motors are directly powered and controlled using the Arduino Motor Shield,
which lets us select a speed ranging from `0` to `255` using a coding API.
This API also lets us engage brakes or set the direction in which the wheels
are turning.
The wheels for this project have been 3D printed and pressure-fit on the motors
themselves, and an O-ring seal is then used to add some grip.
### PCB
In the beginning of this project, we used a breadboard for electronics prototyping.
We had a lot of disconnect issues, so as soon as the hardware part could be frozen,
we migrated the breadboard electronics to a hand-made PCB using a prototyping board.
This made the robot way more resilient to a sharp acceleration curve.
![A top-view of our hand-made PCB.](images/pcb_irl.jpg)
On an electronic level, the PCB is routed such as:
![The PCB routing on a prototyping breadboard.](images/pcb_fritzing.png)
The different components are interfaced with the PCB using a kind of connector that
lets us connect and disconnect things as we iterated on the sensors without having to
use a soldering iron.
## And finally some software
From a software point-of-view, the project is quite simple.
On a high-level, the algorithm could be summed up as follows: check all four photocells,
and move, using rotation and translation, towards the one that has the darkest value, if
`followDark` is set to `true`. If this value is set to `false`, then the robot will move
itself in the opposite direction to this brighest value.
A distance mesurement is made using the three ultrasonic distance sensor, so the robot is
able to stop before hitting a wall (hopefully). These sensors act as "kill switches" that
forbid the robot from ever moving while these sensors are detecting an obstacle.
The code is as follow:
```cpp
#define echo1Pin 5
#define trig1Pin 4
#define echo2Pin 7
#define trig2Pin 6
#define echo3Pin 10
#define trig3Pin 2
#define rotMot1Pin 12
#define brakeMot1Pin 9
#define vitMot1Pin 3
#define rotMot2Pin 13
#define brakeMot2Pin 8
#define vitMot2Pin 11
#define photoRes1Pin A2
#define photoRes2Pin A3
#define photoRes3Pin A4
#define photoRes4Pin A5
#define followDark false
long duration;
int distance;
void setup() {
Serial.begin(9600);
pinMode(rotMot1Pin, OUTPUT);
pinMode(brakeMot1Pin, OUTPUT);
pinMode(vitMot1Pin, OUTPUT);
pinMode(rotMot2Pin, OUTPUT);
pinMode(brakeMot2Pin, OUTPUT);
pinMode(vitMot2Pin, OUTPUT);
pinMode(photoRes1Pin, INPUT);
pinMode(photoRes2Pin, INPUT);
pinMode(photoRes3Pin, INPUT);
pinMode(photoRes4Pin, INPUT);
pinMode(trig1Pin, OUTPUT);
pinMode(echo1Pin, INPUT);
pinMode(trig2Pin, OUTPUT);
pinMode(echo2Pin, INPUT);
pinMode(trig3Pin, OUTPUT);
pinMode(echo3Pin, INPUT);
delay(3000);
}
void loop(){
byte echoPins[3] = {echo1Pin,echo2Pin,echo3Pin};
byte trigPins[3] = {trig1Pin,trig2Pin,trig3Pin};
long int durations[3] = {};
long int distances[3] = {};
for(int i = 0; i < 3; i++){
digitalWrite(trigPins[i], LOW);
delayMicroseconds(2);
digitalWrite(trigPins[i], HIGH);
delayMicroseconds(10);
digitalWrite(trigPins[i], LOW);
durations[i] = pulseIn(echoPins[i], HIGH);
distances[i] = durations[i] * 0.034 / 2;
}
int photoRes[4] = {};
Serial.print("Capteur infra : 1[");
photoRes[0] = analogRead(photoRes1Pin);
Serial.print(photoRes[0]);
Serial.print("] 2[");
photoRes[1] = analogRead(photoRes2Pin);
Serial.print(photoRes[1]);
Serial.print("] 3[");
photoRes[2] = analogRead(photoRes3Pin);
Serial.print(photoRes[2]);
Serial.print("] 4[");
photoRes[3] = analogRead(photoRes4Pin);
Serial.print(photoRes[3]);
for(int i = 0; i < 3; i++){
Serial.print("] - distance(cm) : ");
Serial.print(distances[i]);
}
Serial.println();
bool b = false;
for(int i = 0; i < 3; i++){
if (distances[i] < 30) {
b= true;
}
}
int photoResRef = photoRes[0];
bool photoStop = true;
int photoResMinPos = 0;
if (followDark){
int photoResMin = 1024;
for (int i = 0; i < 4; i++){
if (photoResMin > photoRes[i]){
photoResMin = photoRes[i];
photoResMinPos = i;
}
if (abs(photoResRef - photoRes[i]) > 20){
photoStop = false;
}
}
} else{
int photoResMax = 0;
for (int i = 0; i < 4; i++){
if (photoResMax < photoRes[i]){
photoResMax = photoRes[i];
photoResMinPos = (i + 2)%4;
}
if (abs(photoResRef - photoRes[i]) > 20){
photoStop = false;
}
}
}
Serial.println(photoResMinPos);
if (b || photoStop){
digitalWrite(brakeMot1Pin, HIGH);
digitalWrite(brakeMot2Pin, HIGH);
} else {
digitalWrite(brakeMot1Pin, LOW);
digitalWrite(brakeMot2Pin, LOW);
}
if (photoResMinPos == 0){
digitalWrite(rotMot1Pin, LOW);
digitalWrite(rotMot2Pin, LOW);
}
if (photoResMinPos == 1){
digitalWrite(rotMot1Pin, LOW);
digitalWrite(rotMot2Pin, LOW);
}
if (photoResMinPos == 2){
digitalWrite(rotMot1Pin, HIGH);
digitalWrite(rotMot2Pin, HIGH);
}
if (photoResMinPos == 3){
digitalWrite(rotMot1Pin, HIGH);
digitalWrite(rotMot2Pin, LOW);
}
analogWrite(vitMot1Pin, 150);
analogWrite(vitMot2Pin, 150);
}
```
## Thanks
We wanted to say thank you to the ENSEIRB-MATMECA, to our fablab, EIRLAB, for
trusting us, helping us and providing the hardware we used throughout this project.
Thank you also to the fab-managers who helped us and answered all of our questions,
more or less asked under fatigue.
In memory of Kaitlin Rooke.

View File

@ -1,5 +1,5 @@
+++ +++
title = "Archived articles" title = "Articles archivés"
path = "archive" path = "archive"
+++ +++

View File

@ -2,7 +2,7 @@
{% block content %} {% block content %}
<div class="post"> <div class="post">
<h1 class="post-title">{% block heading %}Lost?{% endblock heading %}</h1> <h1 class="post-title">{% block heading %}Perdu ?{% endblock heading %}</h1>
<p>{% block message %}Looks like you're trying something that doesn't exist (anymore?).{% endblock message %}</p> <p>{% block message %}Cette page n'existe pas.{% endblock message %}</p>
</div> </div>
{% endblock content %} {% endblock content %}

View File

@ -1,9 +1,5 @@
{% extends "terminimal/templates/index.html" %} {% extends "terminimal/templates/index.html" %}
{% block extra_head %}
<script defer src="https://umami.louis-vallat.dev/emmet.js" data-website-id="00cd1102-a4c5-4048-b720-b65f38d346b0"></script>
{% endblock extra_head %}
{% block content %} {% block content %}
<div class="posts"> <div class="posts">
{%- if paginator %} {%- if paginator %}
@ -24,14 +20,14 @@
<span class="button previous"> <span class="button previous">
<a href="{{ paginator.previous | safe }}"> <a href="{{ paginator.previous | safe }}">
<span class="button__icon"></span>&nbsp; <span class="button__icon"></span>&nbsp;
<span class="button__text">More recent posts</span> <span class="button__text">Posts plus récents</span>
</a> </a>
</span> </span>
{% endif -%} {% endif -%}
{%- if paginator.next %} {%- if paginator.next %}
<span class="button next"> <span class="button next">
<a href="{{ paginator.next | safe }}"> <a href="{{ paginator.next | safe }}">
<span class="button__text">Older posts</span>&nbsp; <span class="button__text">Posts plus anciens</span>&nbsp;
<span class="button__icon"></span> <span class="button__icon"></span>
</a> </a>
</span> </span>

108
templates/macros/post.html Normal file
View File

@ -0,0 +1,108 @@
{% macro content(page, summary, show_only_description) %}
{%- if show_only_description %}
<div class="post-content">
{{ page.description | safe }}
</div>
{% elif summary and page.summary %}
<div class="post-content">
{{ page.summary | safe }}
</div>
<div>
<!-- &#xFE0E; -- force text style - some devices render this as emoji -->
<a class="read-more button" href="{{ page.permalink | safe }}">
<span class="button__text">En savoir plus</span>&nbsp;
<span class="button__icon">&#8617;&#xFE0E;</span>
</a>
</div>
{% else %}
{#- full content -#}
<div class="post-content">
{{ page.content | safe }}
</div>
{%- endif %}
{% endmacro content %}
{% macro date(page) %}
<span class="post-date">
{%- if page.date %}
{{ page.date | date(format="%d-%m-%Y") }}
{% endif -%}
</span>
{% endmacro post_date %}
{% macro earlier_later(page) %}
{%- if config.extra.enable_post_view_navigation and page.lower or page.higher %}
<div class="pagination">
<div class="pagination__title">
<span class="pagination__title-h">{{ config.extra.post_view_navigation_prompt }}</span>
<hr />
</div>
<div class="pagination__buttons">
{%- if page.higher %}
<span class="button previous">
<a href="{{ page.higher.permalink | safe }}">
<span class="button__icon"></span>&nbsp;
<span class="button__text">{{ page.higher.title }}</span>
</a>
</span>
{% endif %}
{% if page.lower %}
<span class="button next">
<a href="{{ page.lower.permalink | safe }}">
<span class="button__text">{{ page.lower.title }}</span>&nbsp;
<span class="button__icon"></span>
</a>
</span>
{% endif -%}
</div>
</div>
{% endif -%}
{% endmacro earlier_later %}
{% macro header(page) %}
<h1 class="post-title"><a href="{{ page.permalink | safe }}">{{ page.title }}</a></h1>
<div class="post-meta-inline">
{{ post_macros::date(page=page) }}
</div>
{{ post_macros::tags(page=page) }}
{% endmacro header %}
{% macro list_posts(pages) %}
<ul>
{%- for page in pages %}
{%- if page.draft %}
{% continue %}
{% endif -%}
<li class="post-list">
<a href="{{ page.permalink | safe }}">
{{ post_macros::date(page=page) }}
:: <span class="post-list-title">{{ page.title }}</span></a>
{{ post_macros::tags(page=page, short=true) }}
</li>
{% endfor -%}
</ul>
{% endmacro list_posts %}
{% macro tags(page, short=false) %}
{%- if page.taxonomies and page.taxonomies.tags %}
<span class="post-tags-inline">
{%- if short %}
::
{%- set sep = "," -%}
{% else %}
:: tags:&nbsp;
{%- set sep = "&nbsp;" -%}
{% endif -%}
{%- for tag in page.taxonomies.tags | sort | unique(case_sensitive=false) %}
<a class="post-tag" href="{{ get_taxonomy_url(kind='tags', name=tag) | safe }}">#{{ tag }}</a>
{%- if not loop.last %}{{ sep | safe }}{% endif -%}
{% endfor -%}
</span>
{% endif -%}
{% endmacro tags %}

17
templates/tags/list.html Normal file
View File

@ -0,0 +1,17 @@
{% extends "terminimal/templates/tags/list.html" %}
{% block content %}
<div class="post">
<h1 class="post-title">Liste des tags</h1>
<ul>
{% for term in terms %}
<li class="tag-list">
<a href="{{ term.permalink | safe }}">
{{ term.name }} ({{ term.pages | length }} post{{ term.pages | length | pluralize }})
</a>
</li>
{% endfor %}
</ul>
</div>
{% endblock content %}

View File

@ -0,0 +1,17 @@
{% extends "terminimal/templates/tags/single.html" %}
{% block content %}
<div class="post">
<h1 class="post-title">
tag: #{{ term.name }}
({{ term.pages | length }} post{{ term.pages | length | pluralize }})
</h1>
<a href="{{ config.base_url | safe }}/tags">
Voir tous les tags
</a>
{{ post_macros::list_posts(pages=term.pages) }}
</div>
{% endblock content %}

@ -1 +1 @@
Subproject commit 7f630a4e319c089f27b6704e622b38d874406381 Subproject commit 0ced77898f37eb388181c4bdfa564febe437841e