Auteurs : Enzo L. ; Louis G. ; Lillian D.Classe : 1ere STI2D

Canard Télécommandé

Lycée Haroun Tazieff, Saint-Paul-lès-DaxAnnée 2023/2024

Introduction

Au cours de l’année, nous avons travaillé sur un projet de canard télécommandé, pour cela nous avons utilisé ce matériel :

Pour relier tout ce système nous avons soudé tous les câbles nécessaires au bon fonctionnement du système.

L'objectif sera de créer un serveur sur la carte raspberry pour recevoir le flux vidéo de la caméra, l'encoder et l'envoyer sur un site web. De plus depuis ce site web nous devrions pouvoir diriger le canard. Pour que le canard puisse se déplacer nous allons utilisé des propolseurs.

Vidéo de présentation

Matériels

2Pile 9V
2Propulseur miniature submersibleamazone réf. B07WY4MDYZ
1Une carte raspberry pi4kubii réf. PI5
1Mini caméra filaireokdo réf. 2020456
1Batterie externekeja 78290
4Relaisiduino ME108
1Haut parleursl-200 (action)
NombreMaterielsRéference

Cahier des charges

Câblage

Modélisation 3d

Support canard

Support moteur

Hélices



Support de carte

Pieds du support de carte

Goupille

Photos du projet

Codes

code html

<!DOCTYPE html>
<html>

<head>
  <meta charset="utf-8">
  <style>
  body {
    background-image:url(fondécran.jpg);
    background-repeat: no-repeat;
    background-size: cover;
  }
  svg {
    width: 130px;
    height: 130px;
    margin: 15px 15px 15px 15px;
    position: relative; top: -500px; left: 900px;
  }
  h1 {
    font-size: 48px;
    font-family: Gotham, Tahoma, Fantasy;
    color: #fdf1b8 ;
    position: relative; left: 683px;
  }
  iframe {
    border: thick double #fdf1b8;
    position: relative; top: -10px; left: 150px;
  }
  #rec {
    position: relativ; top: -360px; left: 90px;
    width: 120px;
    height: 120px;
  }
  #off {
    position: relativ; top: -360px; left:850px;
    width: 120px;
    heigt: 120px;
  }
  </style>
  <script>
  ordre=function (val) {
    var xhr=new XMLHttpRequest();
    xhr.open("GET", val, true);
    xhr.send(null);
  };
  </script>
  <title> CANARD ESPION </title>
</head>

<body>
  <h1>CANARD ESPION</h1>
  <iframe src="http://192.168.42.191:8000" width="660" height="500" ></iframe>
  <br>
  <svg></svg>
  <svg onclick="ordre('A1');" viewBox="0 0 24 24" fill="none" stroke="#fdf1b8" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><path d="M16 12l-4-4-4 4M12 16V9"/></svg>
  <br>
  <svg onclick="ordre('G1');" viewBox="0 0 24 24" fill="none" stroke="#fdf1b8" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><path d="M12 8l-4 4 4 4M16 12H9"/></svg>
  <svg onclick="ordre('A0');" viewBox="0 0 24 24" fill="none" stroke="#fdf1b8" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"></circle><rect x="9" y="9" width="6" height="6"></rect></svg>
  <svg onclick="ordre('D1');" viewBox="0 0 24 24" fill="none" stroke="#fdf1b8" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><path d="M12 8l4 4-4 4M8 12h7"/></svg>
  <br>
  <svg></svg>
  <svg onclick="ordre('A-1');" viewBox="0 0 24 24" fill="none" stroke="#fdf1b8" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> <circle cx="12" cy="12" r="10"/><path d="M16 12l-4 4-4-4M12 8v7"/></svg>
  <svg id="rec" onclick="ordre('rec');" viewBox="0 0 24 24" fill="none" stroke="#fdf1b8" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"></circle><polygon points="10 8 16 12 10 16 10 8"></polygon></svg>
  <svg id="off" onclick="ordre('off');" viewBox="0 0 24 24" fill="none" stroke="#fdf1b8" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M18.36 6.64a9 9 0 1 1-12.73 0"></path><line x1="12" y1="2" x2="12" y2="12"></line></svg>
</body>

</html>

le programme pour allumer

marche.sh

#!/bin/bash
./camera.py 1>/dev/null 2>/dev/null &
sleep 15
./serveur.py 1>/dev/null 2>/dev/null &

le programme pour éteindre

stop.sh

#!/bin/bash
killall camera.py
killall serveur.py

le programme pour la camera

#!/usr/bin/python3

import io
import logging
import socketserver
from http import server
from threading import Condition
from picamera2 import Picamera2
from picamera2.encoders import JpegEncoder
from picamera2.outputs import FileOutput
# HTML page for the MJPEG streaming demo
PAGE = """\
 <!DOCTYPE html >
 <html >
 <img src="stream.mjpg" width="640" height="480" >
 </html >
"""
# Class to handle streaming output
class StreamingOutput(io.BufferedIOBase):
  def __init__(self):
    self.frame = None
    self.condition = Condition()
  def write(self, buf):
    with self.condition:
      self.frame = buf
      self.condition.notify_all()
# Class to handle HTTP requests
class StreamingHandler(server.BaseHTTPRequestHandler):
  def do_GET(self):
    if self.path == '/':
      # Redirect root path to index.html
      self.send_response(301)
      self.send_header('Location', '/index.html')
      self.end_headers()
    elif self.path == '/index.html':
      # Serve the HTML page
      content = PAGE.encode('utf-8')
      self.send_response(200)
      self.send_header('Content-Type', 'text/html')
      self.send_header('Content-Length', len(content))
      self.end_headers()
      self.wfile.write(content)
    elif self.path == '/stream.mjpg':
      # Set up MJPEG streaming
      self.send_response(200)
      self.send_header('Age', 0)
      self.send_header('Cache-Control', 'no-cache, private')
      self.send_header('Pragma', 'no-cache')
      self.send_header('Content-Type', 'multipart/x-mixed-replace; boundary=FRAME')
      self.end_headers()
      try:
        while True:
          with output.condition:
            output.condition.wait()
            frame = output.frame
          self.wfile.write(b'--FRAME\r\n')
          self.send_header('Content-Type', 'image/jpeg')
          self.send_header('Content-Length', len(frame))
          self.end_headers()
          self.wfile.write(frame)
          self.wfile.write(b'\r\n')
      except Exception as e:
        logging.warning(
          'Removed streaming client %s: %s',
          self.client_address, str(e))
    else:
      # Handle 404 Not Found
      self.send_error(404)
      self.end_headers()
# Class to handle streaming server
class StreamingServer(socketserver.ThreadingMixIn, server.HTTPServer):
  allow_reuse_address = True
  daemon_threads = True
# Create Picamera2 instance and configure it
picam2 = Picamera2()
picam2.configure(picam2.create_video_configuration(main={"size": (640, 480)}))
output = StreamingOutput()
picam2.start_recording(JpegEncoder(), FileOutput(output))
try:
  # Set up and start the streaming server
  address = ('', 8000)
  server = StreamingServer(address, StreamingHandler)
  server.serve_forever()
finally:
  # Stop recording when the script is interrupted
  picam2.stop_recording()

le programme pour créer le serveur et configurer les gpio

serveur.py

#!/usr/bin/python3
import RPi.GPIO as GPIO
import http.server
import os
from picamera2 import Picamera2
import subprocess
import time
import sys

time.sleep(15)
# Configuration des GPIO pour contrôler les moteurs
GPIO.setwarnings(False)  # Désactiver les avertissements
GPIO.setmode(GPIO.BCM)
GPIO.setup(22, GPIO.OUT)
GPIO.setup(23, GPIO.OUT)
GPIO.setup(24, GPIO.OUT)
GPIO.setup(25, GPIO.OUT)

# Serveur Web sur le port 5555
class rep(http.server.SimpleHTTPRequestHandler):
  def do_GET(self):
    if self.path == '/A1':
      GPIO.output(23, GPIO.HIGH)
      GPIO.output(22, GPIO.LOW)
      GPIO.output(24, GPIO.HIGH)
      GPIO.output(25, GPIO.LOW)
    elif self.path == '/G1':
      GPIO.output(23, GPIO.HIGH)
      GPIO.output(22, GPIO.LOW)
      GPIO.output(24, GPIO.LOW)
      GPIO.output(25, GPIO.LOW)
    elif self.path == '/A0':
      GPIO.output(23, GPIO.LOW)
      GPIO.output(22, GPIO.LOW)
      GPIO.output(24, GPIO.LOW)
      GPIO.output(25, GPIO.LOW)
    elif self.path == '/D1':
      GPIO.output(22, GPIO.LOW)
      GPIO.output(23, GPIO.LOW)
      GPIO.output(24, GPIO.HIGH)
      GPIO.output(25, GPIO.LOW)
    elif self.path == '/A-1':
      GPIO.output(23, GPIO.LOW)
      GPIO.output(22, GPIO.HIGH)
      GPIO.output(24, GPIO.LOW)
      GPIO.output(25, GPIO.HIGH)
    elif self.path == '/rec':
      os.system('mpg123 /home/eric/son_canard.mp3')
    elif self.path == '/off':
      os.system('sudo reboot')
    else:
      super().do_GET()

adr = ("", 5555)
http.server.HTTPServer(adr, rep).serve_forever()


Utiliser crontab
Une autre méthode est d'utiliser cron, un planificateur de tâches Unix. Vous pouvez ajouter une tâche cron pour exécuter votre script au démarrage.

Éditez la crontab pour l'utilisateur pi :

sh
Copier le code
crontab -e
Ajoutez la ligne suivante à la fin du fichier :


@reboot /home/pi/monscript.sh
Enregistrez et quittez l'éditeur :

Si vous utilisez nano, appuyez sur Ctrl+X, puis Y et Enter.

Conclusion

Donc le canard n'a pas explosé.