Compare commits
No commits in common. "02ae6a6a037bda152a027c57a3c578937c222651" and "be166899c5276cc36a75fd70a16e075699f1b850" have entirely different histories.
02ae6a6a03
...
be166899c5
@ -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
@ -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
|
@ -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):
|
||||||
|
|
||||||
|
21
config.toml
@ -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},
|
||||||
]
|
]
|
||||||
|
|
||||||
|
3
content/2021-05-10-git-flow/images/git_rebase.svg
Normal file
After Width: | Height: | Size: 11 KiB |
260
content/2021-05-10-git-flow/index.md
Normal 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).
|
Before Width: | Height: | Size: 553 KiB After Width: | Height: | Size: 553 KiB |
Before Width: | Height: | Size: 1.4 MiB After Width: | Height: | Size: 1.4 MiB |
Before Width: | Height: | Size: 1.2 MiB After Width: | Height: | Size: 1.2 MiB |
Before Width: | Height: | Size: 1.2 MiB After Width: | Height: | Size: 1.2 MiB |
Before Width: | Height: | Size: 1.3 MiB After Width: | Height: | Size: 1.3 MiB |
Before Width: | Height: | Size: 2.1 MiB After Width: | Height: | Size: 2.1 MiB |
@ -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 l’option Makers proposée en deuxième année à l’ENSEIRB-MATMECA,
|
||||||
|
en filière Informatique, un robot timide a vu le jour au sein d’Eirlab.
|
||||||
|
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 l’endroit le
|
||||||
|
plus sombre de la pièce dans lequel il se trouve, et de s’y cacher. Un autre
|
||||||
|
mode est aussi disponible, permettant non pas d’aller vers l’endroit le plus
|
||||||
|
sombre, mais à l’inverse de fuir l’endroit 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 n’a 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) – c’est 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 l’espace
|
||||||
|
- 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 d’avoir 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 l’unique source d’alimentation 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 à l’aide 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 l’alimentation du robot, on vient envoyer 9 Volts d’une source quelconque,
|
||||||
|
d’une pile ou d’une alimentation stabilisée par exemple, dans l’entrée `VIN`
|
||||||
|
de l’Arduino, qui sera après régulée en interne pour donner les différents
|
||||||
|
rails d’alimentation. Cette entrée d’alimentation est connectée en interne au
|
||||||
|
port DC “barrel jack” de l’Arduino, 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`,
|
||||||
|
d’actionner 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 l’adhé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
|
||||||
|
|
||||||
|
D’un 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
|
||||||
|
où `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 d’arrêter
|
||||||
|
le robot (presque) avant collision frontale, et le robot ne se déplacera pas
|
||||||
|
tant que l’objet en face est toujours présent, et donc en théorie tant qu’il a
|
||||||
|
trouvé l’endroit 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 l’ENSEIRB-MATMECA, Eirlab, pour nous avoir permis de
|
||||||
|
travailler sur ce projet et d’avoir 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 l’emprise de la fatigue.
|
||||||
|
|
||||||
|
À la mémoire de Kaitlin Rooke.
|
@ -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.
|
|
@ -1,5 +1,5 @@
|
|||||||
+++
|
+++
|
||||||
title = "Archived articles"
|
title = "Articles archivés"
|
||||||
path = "archive"
|
path = "archive"
|
||||||
+++
|
+++
|
||||||
|
|
||||||
|
@ -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 %}
|
||||||
|
@ -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>
|
<span class="button__icon">←</span>
|
||||||
<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>
|
<span class="button__text">Posts plus anciens</span>
|
||||||
<span class="button__icon">→</span>
|
<span class="button__icon">→</span>
|
||||||
</a>
|
</a>
|
||||||
</span>
|
</span>
|
||||||
|
108
templates/macros/post.html
Normal 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>
|
||||||
|
<!-- ︎ -- 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>
|
||||||
|
<span class="button__icon">↩︎</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>
|
||||||
|
<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>
|
||||||
|
<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:
|
||||||
|
{%- set sep = " " -%}
|
||||||
|
{% 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
@ -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 %}
|
17
templates/tags/single.html
Normal 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
|