fbpixel
Entrainer un modèle TensorFlow2 avec Keras

Entrainer un modèle TensorFlow2 avec Keras

Dans ce tutoriel, nous allons entrainer un modèle MobileNetV2 TensorFlow avec Keras pour qu’il s’applique à notre problématique. Nous allons ensuite pouvoir l’utiliser ne temps réel pour classifier de nouvelles images.

Pour ce tutoriel, nous supposons que vous avez suivit les tutoriel précédent: utilisation d’un modèle TensorFlow et préparation d’une base de données pour l’entrainement.

N.B.: je n’ai pas trouvé la bonne méthode pour entrainer le model ssd mobilenetV2, tel quel, avec tensorflow. Je suis donc passé sous Yolo. Si vous avez la bonne méthode n’hésitez pas à laisser un commentaire.

Récupérer une base d’image

Télechargez une des nombreuses bases d’image comme cats-and-dogs ou créez votre propre banque d’image

Dezippé le dossier dans sous Tensorflow>data

Entrainement du modèle

Pour entrainer le modèle, vous pouvez utiliser le script suivant qui va:

  • charger et augmenter la base de données
  • créer un modèle (model) à partir du modèle MobileNetV2(base_model)
  • entrainer les nouveaux gains du model
  • entrainer finement les gains du base_model
import matplotlib.pyplot as plt
import numpy as np
import os
import tensorflow as tf

#_URL = 'https://storage.googleapis.com/mledu-datasets/cats_and_dogs_filtered.zip'
#path_to_zip = tf.keras.utils.get_file('cats_and_dogs.zip', origin=_URL, extract=True)
#PATH = os.path.join(os.path.dirname(path_to_zip), 'cats_and_dogs_filtered')

PATH="./data/cats_and_dogs_filtered"
train_dir = os.path.join(PATH, 'train')
validation_dir = os.path.join(PATH, 'validation')

BATCH_SIZE = 32
IMG_SIZE = (160, 160)

#create train and validation sets
train_dataset = tf.keras.utils.image_dataset_from_directory(train_dir,
                                                            shuffle=True,
                                                            batch_size=BATCH_SIZE,
                                                            image_size=IMG_SIZE)

validation_dataset = tf.keras.utils.image_dataset_from_directory(validation_dir,
                                                                 shuffle=True,
                                                                 batch_size=BATCH_SIZE,
                                                                 image_size=IMG_SIZE)

class_names = train_dataset.class_names

plt.figure(figsize=(10, 10))
for images, labels in train_dataset.take(1):
  for i in range(9):
    ax = plt.subplot(3, 3, i + 1)
    plt.imshow(images[i].numpy().astype("uint8"))
    plt.title(class_names[labels[i]])
    plt.axis("off")

val_batches = tf.data.experimental.cardinality(validation_dataset)
test_dataset = validation_dataset.take(val_batches // 5)
validation_dataset = validation_dataset.skip(val_batches // 5)

print('Number of validation batches: %d' % tf.data.experimental.cardinality(validation_dataset))
print('Number of test batches: %d' % tf.data.experimental.cardinality(test_dataset))


#configure performance
AUTOTUNE = tf.data.AUTOTUNE
train_dataset = train_dataset.prefetch(buffer_size=AUTOTUNE)
validation_dataset = validation_dataset.prefetch(buffer_size=AUTOTUNE)
test_dataset = test_dataset.prefetch(buffer_size=AUTOTUNE)

#augmented data (usefull for small data sets)
data_augmentation = tf.keras.Sequential([
  tf.keras.layers.RandomFlip('horizontal'),
  tf.keras.layers.RandomRotation(0.2),
])

for image, _ in train_dataset.take(1):
  plt.figure(figsize=(10, 10))
  first_image = image[0]
  for i in range(9):
    ax = plt.subplot(3, 3, i + 1)
    augmented_image = data_augmentation(tf.expand_dims(first_image, 0))
    plt.imshow(augmented_image[0] / 255)
    plt.axis('off')


preprocess_input = tf.keras.applications.mobilenet_v2.preprocess_input
rescale = tf.keras.layers.Rescaling(1./127.5, offset=-1)


# Create the base model from the pre-trained model MobileNet V2
IMG_SHAPE = IMG_SIZE + (3,)
base_model = tf.keras.applications.MobileNetV2(input_shape=IMG_SHAPE,
                                               include_top=False,
                                               weights='imagenet')

#or load your own
#base_model= tf.saved_model.load("./pretrained_models/ssd_mobilenet_v2_320x320_coco17_tpu-8/saved_model")

                                               
image_batch, label_batch = next(iter(train_dataset))
feature_batch = base_model(image_batch)
print(feature_batch.shape)

base_model.trainable = False
base_model.summary()

#classification header
global_average_layer = tf.keras.layers.GlobalAveragePooling2D()
feature_batch_average = global_average_layer(feature_batch)
print(feature_batch_average.shape)

prediction_layer = tf.keras.layers.Dense(1)
prediction_batch = prediction_layer(feature_batch_average)
print(prediction_batch.shape)


#create new neural network based on MobileNet
inputs = tf.keras.Input(shape=(160, 160, 3))
x = data_augmentation(inputs)
x = preprocess_input(x)
x = base_model(x, training=False)
x = global_average_layer(x)
x = tf.keras.layers.Dropout(0.2)(x)
outputs = prediction_layer(x)
model = tf.keras.Model(inputs, outputs)

base_learning_rate = 0.0001
model.compile(optimizer=tf.keras.optimizers.Adam(learning_rate=base_learning_rate),
              loss=tf.keras.losses.BinaryCrossentropy(from_logits=True),
              metrics=['accuracy'])

initial_epochs = 10

loss0, accuracy0 = model.evaluate(validation_dataset)
print("initial loss: {:.2f}".format(loss0))
print("initial accuracy: {:.2f}".format(accuracy0))

history = model.fit(train_dataset,
                    epochs=initial_epochs,
                    validation_data=validation_dataset)


#plot learning curves
acc = history.history['accuracy']
val_acc = history.history['val_accuracy']

loss = history.history['loss']
val_loss = history.history['val_loss']

plt.figure(figsize=(8, 8))
plt.subplot(2, 1, 1)
plt.plot(acc, label='Training Accuracy')
plt.plot(val_acc, label='Validation Accuracy')
plt.legend(loc='lower right')
plt.ylabel('Accuracy')
plt.ylim([min(plt.ylim()),1])
plt.title('Training and Validation Accuracy')

plt.subplot(2, 1, 2)
plt.plot(loss, label='Training Loss')
plt.plot(val_loss, label='Validation Loss')
plt.legend(loc='upper right')
plt.ylabel('Cross Entropy')
plt.ylim([0,1.0])
plt.title('Training and Validation Loss')
plt.xlabel('epoch')
plt.show()


#fine tuning
base_model.trainable = True
# Let's take a look to see how many layers are in the base model
print("Number of layers in the base model: ", len(base_model.layers))

# Fine-tune from this layer onwards
fine_tune_at = 100

# Freeze all the layers before the `fine_tune_at` layer
for layer in base_model.layers[:fine_tune_at]:
  layer.trainable = False

model.compile(loss=tf.keras.losses.BinaryCrossentropy(from_logits=True),
              optimizer = tf.keras.optimizers.RMSprop(learning_rate=base_learning_rate/10),
              metrics=['accuracy'])

model.summary()
fine_tune_epochs = 10
total_epochs =  initial_epochs + fine_tune_epochs

history_fine = model.fit(train_dataset,
                         epochs=total_epochs,
                         initial_epoch=history.epoch[-1],
                         validation_data=validation_dataset)

#plot fine learning curves
acc += history_fine.history['accuracy']
val_acc += history_fine.history['val_accuracy']

loss += history_fine.history['loss']
val_loss += history_fine.history['val_loss']

plt.figure(figsize=(8, 8))
plt.subplot(2, 1, 1)
plt.plot(acc, label='Training Accuracy')
plt.plot(val_acc, label='Validation Accuracy')
plt.ylim([0.8, 1])
plt.plot([initial_epochs-1,initial_epochs-1],
          plt.ylim(), label='Start Fine Tuning')
plt.legend(loc='lower right')
plt.title('Training and Validation Accuracy')

plt.subplot(2, 1, 2)
plt.plot(loss, label='Training Loss')
plt.plot(val_loss, label='Validation Loss')
plt.ylim([0, 1.0])
plt.plot([initial_epochs-1,initial_epochs-1],
         plt.ylim(), label='Start Fine Tuning')
plt.legend(loc='upper right')
plt.title('Training and Validation Loss')
plt.xlabel('epoch')
plt.show()


#evaluate
loss, accuracy = model.evaluate(test_dataset)
print('Test accuracy :', accuracy)

model.save('saved_models/my_model')

Utilisation du modèle entrainé

Vous pouvez utiliser le modèle entrainé pour classifier de nouvelles images contenant un seul type d’objet par image. Pour cela, il vous suffit de charger le modèle précédemment sauvegardé (saved_models/my_model)

#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
#  ObjectRecognitionTFVideo.py
#  Description:
#		Use ModelNetV2-SSD model to detect objects on video
#
#  www.aranacorp.com

# import packages
import sys
from imutils.video import VideoStream
from imutils.video import FPS
import numpy as np
import argparse
import imutils
import time
import cv2
import tensorflow as tf
from PIL import Image

# load model from path
#model= tf.saved_model.load("./pretrained_models/ssd_mobilenet_v2_320x320_coco17_tpu-8/saved_model")
model= tf.saved_model.load("./saved_models/my_model")
#model.summary()

print("model loaded")

#load class names
#category_index = label_map_util.create_category_index_from_labelmap(PATH_TO_LABELS,use_display_name=True)
def read_label_map(label_map_path):

    item_id = None
    item_name = None
    items = {}
    
    with open(label_map_path, "r") as file:
        for line in file:
            line.replace(" ", "")
            if line == "item{":
                pass
            elif line == "}":
                pass
            elif "id" in line:
                item_id = int(line.split(":", 1)[1].strip())
            elif "display_name" in line: #elif "name" in line:
                item_name = line.split(":", 1)[1].replace("'", "").strip()

            if item_id is not None and item_name is not None:
                #items[item_name] = item_id
                items[item_id] = item_name
                item_id = None
                item_name = None

    return items

#class_names=read_label_map("./pretrained_models/ssd_mobilenet_v2_320x320_coco17_tpu-8/mscoco_label_map.pbtxt")
class_names = read_label_map("./saved_models/label_map.pbtxt")
class_names = list(class_names.values()) #convert to list
class_colors = np.random.uniform(0, 255, size=(len(class_names), 3))
print(class_names)

if __name__ == '__main__':

	# Open image
	#img= cv2.imread('./data/cats_and_dogs_filtered/train/cats/cat.1.jpg') #from image file
	img= cv2.imread('./data/cats_and_dogs_filtered/train/dogs/dog.1.jpg') #from image file
	img = cv2.resize(img,(160,160))
	img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)

	#input_tensor = np.expand_dims(img, 0)
	input_tensor = tf.convert_to_tensor(np.expand_dims(img, 0), dtype=tf.float32)

	# predict from model
	resp = model(input_tensor)
	print("resp: ",resp)
	score= tf.nn.sigmoid(resp).numpy()[0][0]*100
	cls = int(score>0.5)
	print("classId: ",int(cls))
	print("score: ",score)
	print("score: ",tf.nn.sigmoid(tf.nn.sigmoid(resp)))
	
			
	# write classname for bounding box
	cls=int(cls) #convert tensor to index
	label = "{}".format(class_names[cls])
	img = cv2.resize(img,(640,640))	
	cv2.putText(img, label, (5, 20), cv2.FONT_HERSHEY_SIMPLEX, 0.5, class_colors[cls], 2)
		
	# Show frame
	cv2.imshow("Frame", img)
	cv2.waitKey(0)



Applications

  • reconnaissance de différentes races d’animaux
  • reconnaissance de différents type d’objets comme des cartes électroniques

Autres modèles de classification à considérer

  • vgg16
  • vgg19
  • resnet50
  • resnet101
  • resnet152
  • densenet121
  • densenet169
  • densenet201
  • inceptionresnetv2
  • inceptionv3
  • mobilenet
  • mobilenetv2
  • nasnetlarge
  • nasnetmobile
  • xception

Sources

Entrainement d’un modèle Yolo

Entrainement d’un modèle Yolo

Nous allons voir dans ce tutoriel comment mettre en place l’entrainement d’un modèle YOLO pour de la reconnaissance d’objets sur des données spécifiques. La difficulté se trouve dans l’élaboration de la banque d’images qui servira pour l’entrainement

Matériel

  • Un ordinateur avec une installation de Python3
  • Une caméra

Principe

Nous avons vu dans un précédent tutoriel comment reconnaitre des objets avec Yolo. Ce modèle a été entrainé pour détecter un certain nombre d’objets mais cette liste est limitée.

{0: 'person', 1: 'bicycle', 2: 'car', 3: 'motorcycle', 4: 'airplane', 5: 'bus', 6: 'train', 7: 'truck', 8: 'boat', 9: 'traffic light', 10: 'fire hydrant', 11: 'stop sign', 12: 'parking meter', 13: 'bench', 14: 'bird', 15: 'cat', 16: 'dog', 17: 'horse', 18: 'sheep', 19: 'cow', 20: 'elephant', 21: 'bear', 22: 'zebra', 23: 'giraffe', 24: 'backpack', 25: 'umbrella', 26: 'handbag', 27: 'tie', 28: 'suitcase', 29: 'frisbee', 30: 'skis', 31: 'snowboard', 32: 'sports ball', 33: 'kite', 34: 'baseball bat', 35: 'baseball glove', 36: 'skateboard', 37: 'surfboard', 38: 'tennis racket', 39: 'bottle', 40: 'wine glass', 41: 'cup', 42: 'fork', 43: 'knife', 44: 'spoon', 45: 'bowl', 46: 'banana', 47: 'apple', 48: 'sandwich', 49: 'orange', 50: 'broccoli', 51: 'carrot', 52: 'hot dog', 53: 'pizza', 54: 'donut', 55: 'cake', 56: 'chair', 57: 'couch', 58: 'potted plant', 59: 'bed', 60: 'dining table', 61: 'toilet', 62: 'tv', 63: 'laptop', 64: 'mouse', 65: 'remote', 66: 'keyboard', 67: 'cell phone', 68: 'microwave', 69: 'oven', 70: 'toaster', 71: 'sink', 72: 'refrigerator', 73: 'book', 74: 'clock', 75: 'vase', 76: 'scissors', 77: 'teddy bear', 78: 'hair drier', 79: 'toothbrush'}

Il est possible d’entrainer le modèle pour reconnaitre des objets en plus ou d’autres objets à l’aide d’une banque d’image adaptée.

Configuration de Python

Si ce n’est pas le cas, vous pouvez télécharger et installer Python 3

Vous pouvez ensuite installer les librairies nécessaires imutils, OpenCV, ultralytics

python3 -m pip install imutils opencv-python ultralytics

Configuration des données

Une fois que vous avez créer une base de données d’images avec label et boites au format Yolo Placer la base de données dans le dossier YOLO\datasets. Ensuite, vous pouvez résumer les informations dans un fichier YAML dans lequel vous spécifiez:

  • le chemin de la base de données contenue dans datasets (coffe_mug)
path: coffee_mug/
train: 'train/'
val: 'test/'
 
# class names
names: 
  0: 'mug'

N.B.: vous pouvez passer les chemin d’accès comme répertoire d’images, fichier texte (path/images.txt), ou list de chemin ([path1/images/, path2/images/])

# train and val data as 1) directory: path/images/, 2) file: path/images.txt, or 3) list: [path1/images/, path2/images/]
train: [./coco128/images/train2017/, coffee_mug/test/]  
val: [./coco128/images/train2017/, coffee_mug/train/] 


# class names
names: ['person', 'bicycle', 'car', 'motorcycle', 'airplane', 'bus', 'train', 'truck', 'boat', 'traffic light',
        'fire hydrant', 'stop sign', 'parking meter', 'bench', 'bird', 'cat', 'dog', 'horse', 'sheep', 'cow',
        'elephant', 'bear', 'zebra', 'giraffe', 'backpack', 'umbrella', 'handbag', 'tie', 'suitcase', 'frisbee',
        'skis', 'snowboard', 'sports ball', 'kite', 'baseball bat', 'baseball glove', 'skateboard', 'surfboard',
        'tennis racket', 'bottle', 'wine glass', 'cup', 'fork', 'knife', 'spoon', 'bowl', 'banana', 'apple',
        'sandwich', 'orange', 'broccoli', 'carrot', 'hot dog', 'pizza', 'donut', 'cake', 'chair', 'couch',
        'potted plant', 'bed', 'dining table', 'toilet', 'tv', 'laptop', 'mouse', 'remote', 'keyboard', 'cell phone',
        'microwave', 'oven', 'toaster', 'sink', 'refrigerator', 'book', 'clock', 'vase', 'scissors', 'teddy bear',
        'hair drier', 'toothbrush', 'mug']

Récupérer un modèle pré-entrainé

Il est possible de récupérer un modèle pré-entrainé à partir du script python qui servira de base pour l’entrainement du nouveau modèle.

# load the pre-trained YOLOv8n model
model = YOLO("yolov8n.pt")

N.B.: regardé bien le modèle qui correspond à votre machine et à votre besoin car ils ont des performances différentes.

Script Python pour l’entrainement de Yolo

Une fois votre banque d’image prête, le script d’entrainement est assez simple. Il suffit de spécifier:

  • le nom du nouveau modèle (yolov8n_v8_50e)
  • le nombre d’itération (epochs)
  • la base de données à utiliser (data)
  • le nombre de fichier à utiliser sur une itération (batch)

train_yolo.py

from ultralytics import YOLO
 
# Load the model.
model = YOLO('yolov8n.pt')
 
# Training.
results = model.train(
   data='coffee_mug_v8.yaml',
   imgsz=1280,
   epochs=50,
   batch=8,
   name='yolov8n_v8_50e'
)

L’algorithme d’entrainement enregistre un certains nombre de données pendant le process que vous pouvez visualiser à la suite pour analyser l’entrainement. Les résultats se trouve dans le dossier .\runs\detect\

Script Python pour l’évaluation du modèle

Une fois le modèle entrainé, vous pouvez comparer ses performances sur de nouvelles images.

Pour récupérer le modèle entrainé, vous pouvez le copier à la racine ou entrer le chemin d’accès

« ./runs/detect/yolov8n_v8_50e2/weights/best.pt »

#!/usr/bin/env python
# -*- coding: utf-8 -*-
#

import datetime
from ultralytics import YOLO
import cv2
from imutils.video import VideoStream
#from helper import create_video_writer


# define some constants
CONFIDENCE_THRESHOLD = 0.65
GREEN = (0, 255, 0)


image_list=['./datasets/coffee_mug/test/10.png','./datasets/coffee_mug/test/19.png']

# load the pre-trained YOLOv8n model
#model = YOLO("yolov8n.pt")
model = YOLO("./runs/detect/yolov8n_v8_50e2/weights/best.pt") # test trained model


for i,img in enumerate(image_list):
	#detect on image
	frame= cv2.imread(img)#from image file

	detections = model(frame)[0]
	# loop over the detections
	#for data in detections.boxes.data.tolist():
	for box in detections.boxes:
		#extract the label name
		label=model.names.get(box.cls.item())
			
		# extract the confidence (i.e., probability) associated with the detection
		data=box.data.tolist()[0]
		confidence = data[4]

		# filter out weak detections by ensuring the
		# confidence is greater than the minimum confidence
		if float(confidence) < CONFIDENCE_THRESHOLD:
			continue

		# if the confidence is greater than the minimum confidence,
		# draw the bounding box on the frame
		xmin, ymin, xmax, ymax = int(data[0]), int(data[1]), int(data[2]), int(data[3])
		cv2.rectangle(frame, (xmin, ymin) , (xmax, ymax), GREEN, 2)

		#draw confidence and label
		y = ymin - 15 if ymin - 15 > 15 else ymin + 15
		cv2.putText(frame, "{} {:.1f}%".format(label,float(confidence*100)), (xmin, y), cv2.FONT_HERSHEY_SIMPLEX, 0.5, GREEN, 2)

	# show the frame to our screen
	cv2.imshow("Img{}".format(i), frame)

while True:
	if cv2.waitKey(1) == ord("q"):
		break

Résultats

L’objectif est atteint car nous obtenons un nouveau modèle qui reconnait les mugs ({0: ‘mug’}), seulement.

Vous pouvez tester ce code avec votre webcam ou avec des photos, par exemple, pour voir les performances du modèle et de la reconnaissance d’objet

Pour permettre au modèle de reconnaitre plus de type d’objets, il faut rajouter des images de l’objet considéré dans la base de données.

Sources

Reconnaissance d’objets avec Yolo et OpenCV

Reconnaissance d’objets avec Yolo et OpenCV

Nous allons voir dans ce tutoriel comment faire de la reconnaissance d’objet avec Yolo et OpenCV en utilisant un réseau de neurones pré-entrainé grâce au deep learning.

Nous avons vu dans un précédent tutoriel comment reconnaitre des formes simples avec la vision par ordinateur. Cette méthode ne fonctionne que pour certaines formes simples prédéfinies. Si vous souhaitez reconnaitre une plus grande variété d’objets, le plus simple est d’utiliser l’intelligence artificielle.

Matériel

  • Un ordinateur avec une installation de Python3
  • Une caméra

Principe

L’intelligence artificielle est un domaine de l’informatique dans lequel le programme apprend par lui-même à effectuer certaines tâches. Notamment de la reconnaissance visuelle. Dans ce tutoriel, nous allons utiliser un réseau de neurones entrainé pour reconnaitre des formes particulières.

Il faut de nombreuse données pour pouvoir entrainer correctement un réseau de neurone. Il a été démontré que l’apprentissage était plus rapide sur un réseau de neurones entrainé pour autre chose. Par exemple, un réseau de neurones entrainé pour reconnaitre les chiens s’entrainera plus facilement à reconnaitre les chats.

Ultralytics propose les modèles YOLO qui sont simples d’utilisation et assez efficace pour la détection, la classification et le suivit

Pour chaque version, il existe différents modèle du plus léger et moins performant au plus performant mais plus lourd

YOLOv5nYOLOv5sYOLOv5mYOLOv5lYOLOv5x
YOLOv8nYOLOv8sYOLOv8mYOLOv8lYOLOv8x
(nano, small, medium, large and extra large)

Configuration de Python

Si ce n’est pas le cas, vous pouvez télécharger et installer Python 3

Vous pouvez ensuite installer les librairies nécessaires imutils, OpenCV, ultralytics

python3 -m pip install imutils opencv-python ultralytics

Récupérer un modèle pré-entrainé

Il est possible de récupérer un modèle pré-entrainé à partir du script pyhton

# load the pre-trained YOLOv8n model
model = YOLO("yolov8n.pt")

Script Python pour la reconnaissance d’Objet

Tout d’abord, nous créons un flux vidéo (vs) à l’aide de la librairie imutils qui va récupérer les images de la caméra.

vs = VideoStream(src=0, resolution=(1600, 1200)).start()

Nous initialisons un réseau de neurones avec les paramètres du modèle à l’aide de la librairie YOLO (yolov5, v8, etc.).

model = YOLO("yolov8n.pt")

Nous allons, ensuite, créer une boucle qui à chaque itération va lire l’image de la caméra et la passer en entrée du réseau de neurone pour faire la détection et reconnaissance d’objet.

while True:
	# start time to compute the fps
	start = datetime.datetime.now()

	#ret, frame = video_cap.read()
	#frame = vs.read(); ret=True
	
	
	# if there are no more frames to process, break out of the loop
	if not ret:
		break

	# run the YOLO model on the frame
	detections = model(frame)[0]

Enfin, le code affiche sur l’image la boite de détection, la probabilité de reconnaissance ainsi que la position

	# loop over the detections
	for box in detections.boxes:
		#extract the label name
		label=model.names.get(box.cls.item())
		
		# extract the confidence (i.e., probability) associated with the detection
		data=box.data.tolist()[0]
		confidence = data[4]

		# filter out weak detections
		if float(confidence) < CONFIDENCE_THRESHOLD:
			continue

		# if the confidence is greater than the minimum confidence
		xmin, ymin, xmax, ymax = int(data[0]), int(data[1]), int(data[2]), int(data[3])
		cv2.rectangle(frame, (xmin, ymin) , (xmax, ymax), GREEN, 2)

		#draw confidence and label
		y = ymin - 15 if ymin - 15 > 15 else ymin + 15
		cv2.putText(frame, "{} {:.1f}%".format(label,float(confidence*100)), (xmin, y), cv2.FONT_HERSHEY_SIMPLEX, 0.5, GREEN, 2)

Code complet de reconnaissance d’objet avec OpenCV et YOLO

#!/usr/bin/env python
# -*- coding: utf-8 -*-
#

import datetime
from ultralytics import YOLO
import cv2
from imutils.video import VideoStream
#from helper import create_video_writer


# define some constants
CONFIDENCE_THRESHOLD = 0.8
GREEN = (0, 255, 0)



# load the pre-trained YOLOv8n model
model = YOLO("yolov8n.pt")
#model = YOLO("yolov5n.pt")
"""
#detect on image
frame= cv2.imread('./datasets/two-boats.jpg');ret= True #from image file
detections = model(frame)[0]
# loop over the detections
#for data in detections.boxes.data.tolist():
for box in detections.boxes:
	#extract the label name
	label=model.names.get(box.cls.item())
		
	# extract the confidence (i.e., probability) associated with the detection
	data=box.data.tolist()[0]
	confidence = data[4]

	# filter out weak detections by ensuring the
	# confidence is greater than the minimum confidence
	if float(confidence) < CONFIDENCE_THRESHOLD:
		continue

	# if the confidence is greater than the minimum confidence,
	# draw the bounding box on the frame
	xmin, ymin, xmax, ymax = int(data[0]), int(data[1]), int(data[2]), int(data[3])
	cv2.rectangle(frame, (xmin, ymin) , (xmax, ymax), GREEN, 2)

	#draw confidence and label
	y = ymin - 15 if ymin - 15 > 15 else ymin + 15
	cv2.putText(frame, "{} {:.1f}%".format(label,float(confidence*100)), (xmin, y), cv2.FONT_HERSHEY_SIMPLEX, 0.5, GREEN, 2)

# show the frame to our screen
cv2.imshow("Img", frame)
"""
#detect on video
# initialize the video capture object
#vs = VideoStream(src=0, resolution=(1600, 1200)).start()
video_cap = cv2.VideoCapture("datasets\\Splash - 23011.mp4")
# initialize the video writer object
#writer = create_video_writer(video_cap, "output.mp4")

while True:
	# start time to compute the fps
	start = datetime.datetime.now()

	#ret, frame = video_cap.read()
	#frame = vs.read(); ret=True
	
	
	# if there are no more frames to process, break out of the loop
	if not ret:
		break

	# run the YOLO model on the frame
	detections = model(frame)[0]
	
	# loop over the detections
	#for data in detections.boxes.data.tolist():
	for box in detections.boxes:
		#extract the label name
		label=model.names.get(box.cls.item())
		
		# extract the confidence (i.e., probability) associated with the detection
		data=box.data.tolist()[0]
		confidence = data[4]

		# filter out weak detections by ensuring the
		# confidence is greater than the minimum confidence
		if float(confidence) < CONFIDENCE_THRESHOLD:
			continue

		# if the confidence is greater than the minimum confidence,
		# draw the bounding box on the frame
		xmin, ymin, xmax, ymax = int(data[0]), int(data[1]), int(data[2]), int(data[3])
		cv2.rectangle(frame, (xmin, ymin) , (xmax, ymax), GREEN, 2)

		#draw confidence and label
		y = ymin - 15 if ymin - 15 > 15 else ymin + 15
		cv2.putText(frame, "{} {:.1f}%".format(label,float(confidence*100)), (xmin, y), cv2.FONT_HERSHEY_SIMPLEX, 0.5, GREEN, 2)
		#cv2.circle(frame, (int(X)-15, int(Y)), 1, GREEN, 2)
		#cv2.putText(frame, poslbl, (int(X), int(Y)),cv2.FONT_HERSHEY_SIMPLEX, 0.5, GREEN, 2)

	# end time to compute the fps
	end = datetime.datetime.now()
	# show the time it took to process 1 frame
	total = (end - start).total_seconds()
	print(f"Time to process 1 frame: {total * 1000:.0f} milliseconds")

	# calculate the frame per second and draw it on the frame
	fps = f"FPS: {1 / total:.2f}"
	cv2.putText(frame, fps, (50, 50),
				cv2.FONT_HERSHEY_SIMPLEX, 2, (0, 0, 255), 4)

	# show the frame to our screen
	cv2.imshow("Frame", frame)
	#writer.write(frame)
	if cv2.waitKey(1) == ord("q"):
		break

video_cap.release()
vs.stop()
#writer.release()
cv2.destroyAllWindows()

Sources d’image pour la détection d’objet

Vous pouvez utiliser ce script avec différentes sources d’image. Pour cela, il faut légèrement adapter le code précédent afin de modifier la variable « img » contenant l’image à analyser.

  • La webcam de votre ordinateur
vs = VideoStream(src=0, resolution=(1600, 1200)).start()
while True:
	frame = vs.read()

Le stream vidéo doit être arrêté à la fin du script avec vs.stop()

vc = cv2.VideoCapture('rtsp://user:password@ipaddress:rtspPort')
while True:
	ret, frame=vc.read() #from ip cam

Veillez à arrêter la capture vidéo à la fin du script avec vc.release()

  • La Picam du Raspberry Pi
vs = VideoStream(usePiCamera=True, resolution=(1600, 1200)).start()
while True:
	frame = vs.read()

Pensez à arrêter le stream à la fin du script avec vs.stop()

  • Un fichier vidéo
vc = cv2.VideoCapture('./datasets/Splash - 23011.mp4') #from video
while True:
	ret, frame=vc.read() #from video
  • Un fichier image
frame= cv2.imread('./datasets/two-boats.jpg') 

Résultats

Pour cet exemple nous envoyons en entrée du réseau de neurones une image de deux bateaux qui sont reconnus correctement. Pour obtenir des résultats légèrement différents, vous pouvez modifier le paramètre confidence pour éviter les faux positifs.

Vous pouvez tester ce code avec votre webcam ou avec des photos, par exemple, pour voir les performances du modèle et de la reconnaissance d’objet.

Une fois que votre script fonctionne, vous pouvez entrainer votre modèle pour qu’il puisse détecter d’autres objets.

Sources

Préparer une banque d’image pour l’entrainement d’un Modèle

Préparer une banque d’image pour l’entrainement d’un Modèle

Pour préparer une banque d’image en vue de l’entrainement d’un réseau de neurones à la reconnaissance d’objet, il faut reconnaitre soit même les images de la base de données. C’est à dire leur donner un label et une zone de reconnaissance.

Ce tutoriel fait suite à l’article créer une banque d’image.

Objectif de la préparation

L’objectif est de créer des jeux de données qui permettront de faciliter l’entrainement avec les outils de TensorFlow, Yolo ou Keras

Pour ce faire, deux choix existent:

  • Utiliser labelImg
  • Créer une architecture de dossier et utiliser un script (entrainement avec Keras seulement)

Préparer une banque d’image avec labelImg

Vous pouvez télécharger et installer labelImg

  • Linux
python3 -m pip install labelImg
labelImg
  • Windows

Suivez les consignes de construction sur github. Vous pouvez aussi trouver un exécutable labelImg.exe

Ajouter une boite et un label

Lancer labelImg et sélectionner le dossier à l’aide du bouton « Open Dir ».

Pour chaque image, vous allez entourer l’objet à détecter et lui affecter un nom (label) à l’aide du bouton « Create RectBox ».

N.B.: évitez de dépasser de l’image lorsque vous dessinez la boîte. Cela peut poser des soucis lors de l’entrainement

Convertir au format PascalVOC

Convertir au format YOLO

N.B.: Vous pouvez sauvegarder les deux formats à la suite ou sauvegarder en VOC et convertir en YOLO à l’ai du script convert_voc_to_yolo.py

Préparer une banque d’image avec une architecture de dossier

L’idée est de placer les images dans des sous-dossiers du nom de la classe. Pour l’entrainement, la banque d’image doit contenir entre 1 et 3 dossiers: train, test, validation (les dossiers test et validation sont optionnels car ils peuvent être créés à partir du premier

N.B.: pour cette méthode il faut un seul objet par image

  • images
    • train
      • cats
      • dogs
    • validation
      • cats
      • dogs

Pour créer les fichiers contenant les info de nom et de zone de détection à partir des dossier images, vous pouvez utiliser le scripts generate_voc_files.py en modifiant:

  • les chemins d’accès vers les différents dossiers (folders[‘train’/’validation’/’test’])

Les noms de classe seront définies par les noms de dossier et la zone de détection par la taille des images.

generate_voc_files.py

import glob
import os
import pickle
import cv2
import xml.etree.ElementTree as ET
import xml.dom.minidom
from os import listdir, getcwd
from os.path import join

dirs = ['train', 'test']
classes = ['mug']

def getImagesInDir(dir_path):
	image_list = []
	for filename in glob.glob(dir_path + '/**/*.png', recursive=True):
		image_list.append(filename)
	return image_list

def generate_voc(image_path):

	#get image data
	dirname=os.path.dirname(image_path)
	foldername=dirname.split('\\')[-1]
	basename = os.path.basename(image_path)
	basename_no_ext = os.path.splitext(basename)[0]
	im = cv2.imread(image_path)
	h,w,c=im.shape

	root = ET.Element('annotation')
	folder = ET.SubElement(root, 'folder')
	folder.text=foldername

	filename = ET.SubElement(root, 'filename')
	filename.text=basename

	path = ET.SubElement(root, 'path')
	path.text=image_path

	source = ET.SubElement(root, 'source')
	database = ET.SubElement(source, 'database')
	database.text = 'Unknown'

	size = ET.SubElement(root, 'size')
	width = ET.SubElement(size, 'width')
	width.text='{}'.format(w)
	height = ET.SubElement(size, 'height')
	height.text='{}'.format(h)
	depth = ET.SubElement(size, 'depth')
	depth.text='{}'.format(c)

	segmented = ET.SubElement(root, 'segmented')
	segmented.text = '0'

	objec = ET.SubElement(root, 'object')
	name = ET.SubElement(objec, 'name')
	name.text=foldername
	pose = ET.SubElement(objec, 'pose')
	pose.text='Unspecified'
	truncated = ET.SubElement(objec, 'truncated')
	truncated.text='0'
	difficult = ET.SubElement(objec, 'difficult')
	difficult.text='0'

	bndbox = ET.SubElement(objec, 'bndbox')
	xmin = ET.SubElement(bndbox, 'xmin')
	xmin.text='{}'.format(0+5)
	ymin = ET.SubElement(bndbox, 'ymin')
	ymin.text='{}'.format(0+5)
	xmax = ET.SubElement(bndbox, 'xmax')
	xmax.text='{}'.format(w-5)
	ymax = ET.SubElement(bndbox, 'ymax')
	ymax.text='{}'.format(h-5)

	tree = ET.ElementTree(root)

	outxml=join(dirname,basename_no_ext+'.xml')
	tree.write(outxml)
	return outxml


def convert(size, box):
	dw = 1./(size[0])
	dh = 1./(size[1])
	x = (box[0] + box[1])/2.0 - 1
	y = (box[2] + box[3])/2.0 - 1
	w = box[1] - box[0]
	h = box[3] - box[2]
	x = x*dw
	w = w*dw
	y = y*dh
	h = h*dh
	return (x,y,w,h)

def convert_annotation(in_file):
	dirname=os.path.dirname(in_file)
	basename = os.path.basename(in_file)
	basename_no_ext = os.path.splitext(basename)[0]
	
	out_file = open(join(dirname, basename_no_ext + '.txt'), 'w')
	tree = ET.parse(in_file)
	root = tree.getroot()
	size = root.find('size')
	w = int(size.find('width').text)
	h = int(size.find('height').text)

	for obj in root.iter('object'):
		difficult = obj.find('difficult').text
		cls = obj.find('name').text
		if cls not in classes or int(difficult)==1:
			continue
		cls_id = classes.index(cls)
		xmlbox = obj.find('bndbox')
		b = (float(xmlbox.find('xmin').text), float(xmlbox.find('xmax').text), float(xmlbox.find('ymin').text), float(xmlbox.find('ymax').text))
		bb = convert((w,h), b)
		out_file.write(str(cls_id) + " " + " ".join([str(a) for a in bb]) + '\n')

cwd = getcwd()

for dir_path in dirs:
	full_dir_path = join(cwd,dir_path)
	image_paths = getImagesInDir(full_dir_path)

	for image_path in image_paths:

		xml_path=generate_voc(image_path) #generate voc file
		convert_annotation(xml_path) #convert to yolo file

	print("Finished processing: " + dir_path)

Cette méthode permet d’avoir rapidement une base de données exploitable pour l’entrainement (TensorFlow et Yolo) même si la zone de reconnaissance est approximative.

N.B.: Une fois les fichiers XML et TXT créés, vous pouvez ouvrir lableImg pour affiner les labels ainsi que la zone de détection.

Sources

Reconnaissance d’Objet avec TensorFlow et OpenCV

Reconnaissance d’Objet avec TensorFlow et OpenCV

Nous allons voir dans ce tutoriel comment faire de la reconnaissance d’objet avec TensorFlow et OpenCV en utilisant un réseau de neurones pré-entrainé grâce au deep learning.

Nous avons vu dans un précédent tutoriel comment reconnaitre des formes simples avec la vision par ordinateur. Cette méthode ne fonctionne que pour certaines formes simples prédéfinies. Si vous souhaitez reconnaitre une plus grande variété d’objets, le plus simple est d’utiliser l’intelligence artificielle.

Matériel

  • Un ordinateur avec une installation de Python3
  • Une caméra

Principe

L’intelligence artificielle est un domaine de l’informatique dans lequel le programme apprend par lui-même à effectuer certaines tâches. Notamment de la reconnaissance visuelle. Dans ce tutoriel, nous allons utiliser un réseau de neurones entrainé pour reconnaitre des formes particulières.

Il faut de nombreuse données pour pouvoir entrainer correctement un réseau de neurone. Il a été démontré que l’apprentissage était plus rapide sur un réseau de neurones entrainé pour autre chose. Par exemple, un réseau de neurones entrainé pour reconnaitre les chiens s’entrainera plus facilement à reconnaitre les chats.

Configuration de Python

Si ce n’est pas le cas, vous pouvez télécharger et installer Python 3

Vous pouvez ensuite installer les librairies nécessaires OpenCV, numpy et imutils

python3 -m pip install opencv-python numpy imutils

Voici les versions que j’utilise dans ce tutoriel

numpy== 1.22.0
tensorflow== 2.13.0
opencv== 4.6.0

N.B.: Lorsqu’on utilise certains paquets python comme TensorFlow, il peut y avoir très fréquemment des problèmes de compatibilité. Si vous avez des difficultés n’hésitez pas à installer des versions spécifiques des paquets. Si vous avez plusieurs projets en cours, je vous invite fortement à créer des environnements virtuels (venv).

Récupérer un modèle pré-entrainé

Téléchargement du modèle ModelNet-SSD à partir du Model Zoo (ex: SSD MobileNet v2 320×320)

Téléchargez le fichier mscoco_label_map.pbtxt qui contient les identifiants des objets reconnus par le modèle.

N.B.: dans un précédent tutoriel, nous avions utilisez le résultat du framework Caffe pour le modèle (fichiers prototxt et caffemodel). Dans cet article, nous utilisons le SavedModel de TensorFlow.

Créer un dossier TensorFlowCV, qui sera votre espace de travail. Dans ce dossier créer un dossier pretrained_models dans lequel vous pouvez décompresser le modèle téléchargé.

Vous pouvez également créer un dossier data, dans lequel vous placerez vos images ou vidéo.

Placer les fichiers du modèle dans un dossier et créer le fichier ObjectRecognition.py

Script Python pour la reconnaissance d’Objet

Tout d’abord, nous créons un flux vidéo (vs) à l’aide de la librairie imutils qui va récupérer les images de la caméra.

vs = VideoStream(src=0, resolution=(1600, 1200)).start()

Nous initialisons un réseau de neurones avec les paramètres du SSD-ModelNetV2 (net) à l’aide de la librairie TensorFlow.

model= tf.saved_model.load("./pretrained_models/ssd_mobilenet_v2_320x320_coco17_tpu-8/saved_model")

Une fonction se charge de récupérer les noms des classes reconnues par le modèle à partir du fichier pbtxt

#load class names
def read_label_map(label_map_path):

    item_id = None
    item_name = None
    items = {}
    
    with open(label_map_path, "r") as file:
        for line in file:
            line.replace(" ", "")
            if line == "item{":
                pass
            elif line == "}":
                pass
            elif "id" in line:
                item_id = int(line.split(":", 1)[1].strip())
            elif "display_name" in line: #elif "name" in line:
                item_name = line.split(":", 1)[1].replace("'", "").strip()

            if item_id is not None and item_name is not None:
                #items[item_name] = item_id
                items[item_id] = item_name
                item_id = None
                item_name = None

    return items

class_names=read_label_map("./pretrained_models/ssd_mobilenet_v2_320x320_coco17_tpu-8/mscoco_label_map.pbtxt")
class_colors = np.random.uniform(0, 255, size=(len(class_names), 3))

Nous allons, ensuite, créer une boucle qui à chaque itération va lire l’image de la caméra et la passer en entrée du réseau de neurone pour faire la détection et reconnaissance d’objet.

	#Main loop
	while True:
		# Get video sttream. max width 800 pixels 
		#img = vs.read()
		img= cv2.imread('./data/two-boats.jpg') #from image file
		#ret, img=vc.read() #from video or ip cam
		img = imutils.resize(img, width=800)

		img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
		# get height and width of image
		h, w, _ = img.shape

		input_tensor = np.expand_dims(img, 0)

		# predict from model
		resp = model(input_tensor)

Enfin, le code affiche sur l’image la boite de détection, la probabilité de reconnaissance ainsi que la position

					# write classname for bounding box
					cls=int(cls) #convert tensor to index
					label = "{}: {:.2f}%".format(class_names[cls],score * 100)
					cv2.putText(img, label, (xmin, ymin-10), cv2.FONT_HERSHEY_SIMPLEX, 1, class_colors[cls], 1)
					
					#display position
					X= (xmax+xmin)/2
					Y= (ymax+ymin)/2
					poslbl= "X: ({},{})".format(X,Y)
					cv2.circle(img, (int(X)-15, int(Y)), 1, class_colors[cls], 2)	
					cv2.putText(img, poslbl, (int(X), int(Y)),
						cv2.FONT_HERSHEY_SIMPLEX, 0.5, class_colors[cls], 2)
					
					# draw on image
					cv2.rectangle(img, (xmin, ymin), (xmax, ymax), class_colors[cls], 4)

Code complet de reconnaissance d’objet avec OpenCV et TensorFlow

#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
#  ObjectRecognitionTFVideo.py
#  Description:
#		Use ModelNetV2-SSD model to detect objects on image or video
#
#  www.aranacorp.com

# import packages
import sys
from imutils.video import VideoStream
from imutils.video import FPS
import numpy as np
import argparse
import imutils
import time
import cv2
import tensorflow as tf


# load model from path
model= tf.saved_model.load("./pretrained_models/ssd_mobilenet_v2_320x320_coco17_tpu-8/saved_model")
print("model loaded")

#load class names
def read_label_map(label_map_path):

    item_id = None
    item_name = None
    items = {}
    
    with open(label_map_path, "r") as file:
        for line in file:
            line.replace(" ", "")
            if line == "item{":
                pass
            elif line == "}":
                pass
            elif "id" in line:
                item_id = int(line.split(":", 1)[1].strip())
            elif "display_name" in line: #elif "name" in line:
                item_name = line.split(":", 1)[1].replace("'", "").strip()

            if item_id is not None and item_name is not None:
                #items[item_name] = item_id
                items[item_id] = item_name
                item_id = None
                item_name = None

    return items

class_names=read_label_map("./pretrained_models/ssd_mobilenet_v2_320x320_coco17_tpu-8/mscoco_label_map.pbtxt")
class_colors = np.random.uniform(0, 255, size=(len(class_names), 3))


if __name__ == '__main__':

	# Camera initialisation
	print("Start Camera...")
	vs = VideoStream(src=0, resolution=(1600, 1200)).start() #from usb cam
	#vs = VideoStream(usePiCamera=True, resolution=(1600, 1200)).start() #from RPi cam
	#vc = cv2.VideoCapture('./data/Splash - 23011.mp4') #from video file

	time.sleep(2.0)
	fps = FPS().start()
	
	#Main loop
	while True:
		#get image
		img = vs.read() # Get video stream
		#img= cv2.imread('./data/two-boats.jpg') #from image file
		#ret, img=vc.read() #from video or ip cam

                #process image
		img = imutils.resize(img, width=800) #max width 800 pixels 
		img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
		# get height and width of image
		h, w, _ = img.shape

		input_tensor = np.expand_dims(img, 0)

		# predict from model
		resp = model(input_tensor)

		# iterate over boxes, class_index and score list
		for boxes, classes, scores in zip(resp['detection_boxes'].numpy(), resp['detection_classes'], resp['detection_scores'].numpy()):
			for box, cls, score in zip(boxes, classes, scores): # iterate over sub values in list
				if score > 0.61: # we are using only detection with confidence of over 0.6
					ymin = int(box[0] * h)
					xmin = int(box[1] * w)
					ymax = int(box[2] * h)
					xmax = int(box[3] * w)
									
					# write classname for bounding box
					cls=int(cls) #convert tensor to index
					label = "{}: {:.2f}%".format(class_names[cls],score * 100)
					cv2.putText(img, label, (xmin, ymin-10), cv2.FONT_HERSHEY_SIMPLEX, 1, class_colors[cls], 1)
					
					#display position
					X= (xmax+xmin)/2
					Y= (ymax+ymin)/2
					poslbl= "X: ({},{})".format(X,Y)
					cv2.circle(img, (int(X)-15, int(Y)), 1, class_colors[cls], 2)	
					cv2.putText(img, poslbl, (int(X), int(Y)),
						cv2.FONT_HERSHEY_SIMPLEX, 0.5, class_colors[cls], 2)
					
					# draw on image
					cv2.rectangle(img, (xmin, ymin), (xmax, ymax), class_colors[cls], 4)
				
				
		# Show video frame
		cv2.imshow("Frame", img)
		key = cv2.waitKey(1) & 0xFF

		# Exit script with letter q
		if key == ord("q"):
			break

		# FPS update 
		fps.update()

	# Stops fps and display info
	fps.stop()
	print("[INFO] elapsed time: {:.2f}".format(fps.elapsed()))
	print("[INFO] approx. FPS: {:.2f}".format(fps.fps()))

	cv2.destroyAllWindows()
	vs.stop()
	#vc.release()

Sources d’image pour la détection d’objet

Vous pouvez utiliser ce script avec différentes sources d’image. Pour cela, il faut légèrement adapter le code précédent afin de modifier la variable « img » contenant l’image à analyser.

  • La webcam de votre ordinateur
vs = VideoStream(src=0, resolution=(1600, 1200)).start()
while True:
	frame = vs.read()

Le stream vidéo doit être arrêté à la fin du script avec vs.stop()

vc = cv2.VideoCapture('rtsp://user:password@ipaddress:rtspPort')
while True:
	ret, frame=vc.read() #from ip cam

Veillez à arrêter la capture vidéo à la fin du script avec vc.release()

  • La Picam du Raspberry Pi
vs = VideoStream(usePiCamera=True, resolution=(1600, 1200)).start()
while True:
	frame = vs.read()

Pensez à arrêter le stream à la fin du script avec vs.stop()

  • Un fichier vidéo
vc = cv2.VideoCapture('./img/Splash - 23011.mp4') #from video
while True:
	ret, frame=vc.read() #from video
  • Un fichier image
frame= cv2.imread('./img/two-boats.jpg') 

Résultats

Pour cet exemple nous envoyons en entrée du réseau de neurones une image de deux bateaux qui sont reconnus correctement. Pour obtenir des résultats légèrement différents, vous pouvez modifier le paramètre confidence pour éviter les faux positifs.

Vous pouvez tester ce code avec votre webcam ou avec des photos, par exemple, pour voir les performances du modèle et de la reconnaissance d’objet

Une fois que votre script fonctionne, vous pouvez entrainer votre modèle pour qu’il puisse détecter d’autres objets.

Paquets et Modèles

Dans ce tutoriel, nous avons utiliser le modèle pré-entrainé SSD ModelNetV2. Il est bon de noter qu’ils existent d’autres modèles de classification avec des performances et caractéristiques différentes.

  • vgg16
  • vgg19
  • resnet50
  • resnet101
  • resnet152
  • densenet121
  • densenet169
  • densenet201
  • inceptionresnetv2
  • inceptionv3
  • mobilenet
  • mobilenetv2
  • nasnetlarge
  • nasnetmobile
  • xception

N’hésitez pas à nous laisser un commentaire pour partager les modèles que vous utilisez ou connaissez et votre retour d’expérience.

Sources

Sauvegarde légère d’image du Raspberry Pi

Sauvegarde légère d’image du Raspberry Pi

Nous présentons ici une méthode pour faire une sauvegarde légère et restaurer un Raspberry Pi. Créer une sauvegarde, image de votre Raspberry Pi, est primordiale en cas de corruption de la carte SD ou défaut d’alimentation. Il arrive souvent sur les Raspberry Pi et autres ordinateur monocarte que la carte SD fasse défaut. Il faut donc faire une sauvegarde sous la forme d’un fichier image ou iso afin de pouvoir téléverser cette image sur une nouvelle carte SD et retrouver votre configuration.

Le problème est que la sauvegarde d’une image inclue toute la mémoire de la carte SD. Vous pouvez donc vous retrouver avec plusieurs fichiers de 32, 64 ou 128Gb.

Matériel

  • Raspberry Pi
  • Deux cartes SD
  • Une connexion internet

Méthode de sauvegarde d’OS

Il n’y a pas d’autre méthode aussi direct. La méthode que je vous propose consiste en différentes étapes mais vous permettra d’avoir une sauvegarde légère du Raspberry Pi et de pouvoir mettre à jour vos projets facilement.

La méthode consiste en ces différents points

  • Récupérer les informations de l’OS
  • Récupérer les info hardware (optionnel)
  • Récupérer les fichier de configuration
  • Récupérer les paquets installés
  • Récupérer les paquets Python installé

La liste n’est certainement pas complète mais avec cela, vous pourrez vous rapprochez d’une copie presque exact de ce que vous aviez

Nettoyer votre installation

sudo apt-get  --purge -y autoremove 

Vous pouvez aussi supprimer tous les logiciels dont vous ne vous êtes jamais servi

Créer un dossier de sauvegarde

Il peut prendre la forme que vous voulez. L’important est qu’il soit clair afin de vous y retrouver

  • RPiBckp
    • version
    • projects
    • config

Récupérer les informations de l’OS

Selon votre projet, il est important de connaitre la version de l’OS en effet suivant les paquets utilisées des problème de compatibilités peuvent se poser

cat /etc/os-release
cat /etc/os-release > /home/pi/RPiBckp/version/os-version.txt

Une autre information importante sont la version Kernel et configuration hardware

uname -a > /home/pi/RPiBckp/version/sys-version.txt
ls -l /lib/modules

N.B.: uname -r vous donne spécifiquement la version de Kernel. Vous pouvez retrouver le fichier d’installation dans la liste des firmwares

Récupérer les paquets installés

Pour avoir une liste des paquets installés, vous pouvez entrer la commande

dpkg --get-selections

Si vous souhaitez la liste des paquets avec le numéro de version

apt list --installed

N.B.: pour toute ces commandes vous pouvez utiliser grep pour filtrer votre recherche

Il est important de noter qu’il y a un certain nombre de paquets installés automatiquement et d’autre que vous avez installé selon votre besoin.

La liste des paquets installés automatiquement et manuellement s’obtient avec les commandes respectives

apt-mark showauto # paquets automatique
apt-mark showmanual # paquets manuel

Pour ma part, je conserve un fichier avec tous les paquets installés pour garder une trace avec toutes les versions

apt list --installed > /home/pi/RPiBckp/version/apt-list-installed.txt

un fichier avec les paquets installés manuellement

apt list --installed | grep -v automatic > /home/pi/RPiBckp/version/apt-list-manual.txt

et je créer le fichier avec seulement les nom pour lancer l’installation des paquets

apt-mark showmanual > /home/pi/RPiBckp/version/packages.txt

Je pourrai ensuite installer individuellement les bonnes versions si elles ne me conviennent pas.

Récupérer les paquets Python installés

python3 -m pip freeze
python3 -m pip freeze > /home/pi/RPiBckp/version/requirements.txt

Récupérer les fichiers de configuration

Certains fichiers de configurations peuvent être intéressant à récupérer notamment la configuration du wifi

sudo nano /etc/wpa_supplicant/wpa_supplicant.conf

cp /etc/wpa_supplicant/wpa_supplicant.conf /home/pi/RPiBckp/version/wpa_supplicant.conf

Créer un dépôt Git

Il peut être intéressant de créer un dépôt git pour chacun de vos projets soit pour la configuration d’un Raspberry Pi, soit pour un ensemble de script Python. Un projet sous git sera idéal pour faire évoluer vos projet notamment en terme de version de paquets et d’OS.

Une fois que vous avez récupéré tous les fichiers d’intérêts, il est temps de restaurer votre projet.

Installer une version de Raspbian

Vous pouvez utiliser le logiciel Raspberry Pi Imager

ou télécharger l’image désirée sur le site http://downloads.raspberrypi.org/raspbian/images/

N.B.: les versions trop anciennes d’OS peuvent ne pas être compatible avec les nouveaux matériels et avoir des soucis de sécurité

Installer une version de Kernel

Vous pouvez vérifier la version de Kernel installée avec la commande

ls -l /lib/modules

Pour installer une version spécifique de firmware du Raspberry Pi, vous pouvez retrouver la liste des firmwares à l’aide de leur numéro de version.

Vous pouvez ensuite copier le Git hash correspondant à la version désirée (ex: 5.10.63 : 64132d67d3e083076661628203a02d27bf13203c)

Et l’installer à l’aide de la commande:

sudo rpi-update <git_hash>

Exemple:

sudo rpi-update 2ef601a50b68eebeeb4dc3c6c525855961891be6

Attention: faites bien attention à la version que vous installez. La version de Kernel ne doit être modifiée que par des personnes expérimentées qui ont un soucis de compatibilité qui ne peut être résolue d’une autre manière.

Copier votre dossier de sauvegarde

Sur l’installation fraiche de Raspbian, vous pouvez copier votre dossier de sauvegarde et/ou cloner le dépôt Git. Vous pouvez ensuite installer les paquets et copier les fichiers de votre configuration précédente.

Installer les paquets requis

Il est possible d’installer un ensemble de paquet APT à partir d’un fichier texte contenant la liste des fichiers à installer

xargs -a packages.txt sudo apt-get install -y

Il est possible de faire la même chose pour installer les paquets Python

python3 -m pip install -r requirements.txt

Recopier les fichiers de configuration

Pour le fichier de configuration du wifi ou tout autre fichiervous pouvez utiliser la commande de copy ou de déplacement en mode super utilisateur (sudo)

sudo cp wpa_supplicant.conf /etc/wpa_supplicant/

Conclusion

Cette méthode ne permet pas d’obtenir une copie parfaite de votre projet mais elle permet de reproduire et de maintenir votre projet avec peu d’espace mémoire ce qui peut être un énorme avantage. Vous vous retrouverez ainsi avec un ensemble de fichier de configuration qui vous permettrons rapidement de restaurer une carte SD corrompue.

Si vous avez des idées de fichiers importants à sauvegarder ou d’autres méthodes pour restaurer une carte SD, n’hésitez pas à laisser un commentaire.

Sources

Installer Debian sur Rock Pi S

Installer Debian sur Rock Pi S

La carte Rock Pi S de chez Radxa peut tourner avec Debian, Armbian, Ubuntu ou Android. Nous allons voir dans ce tutoriel comment configurer votre micro-ordinateur avec Debian.

Matériel

  • Rock Pi S
  • Carte Micro SD
  • Câble USB
  • Ordinateur/PC

Installer l’OS

Tout d’abord, il faut installer une application qui nous permettra de flasher l’OS sur la carte SD inséré sur votre ordinateur.
Vous pouvez installer balenaEtcher (n’oubliez pas de choisir le système d’exploitation de votre ordinateur):

Nous allons télécharger un OS sous forme d’image à flasher sur votre carte SD.
Télécharger une image à flasher tel que Debian par exemple.

Après avoir installé balenaEtcher, lancez l’application et flasher votre OS sur votre carte SD. Cela peut prendre du temps :

Une fois l’OS installé, insérez la carte SD dans le Rock Pi S.

Se connecter en SSH

Pour cela, il vous faudra télécharger un logiciel d’émulation de terminal tel que PuTTY ou TeraTerm.

Ensuite il faudra brancher votre carte ainsi :

Une fois connecté, ouvrez PuTTY et connecter en SSH de la façon suivante :

Se connecter en liaison série

Pour se connecter en liaison, on ne peut pas se connecter via les ports USB et USB-C de la carte, ce qui est fort dommage. Il faut alors utiliser un adaptateur USB UART-TTL. Pour ce tuto, nous utiliserons celui de la marque Rtinle. Brancher la carte de la façon suivante :

Une fois branché, ouvrez TeraTerm et connectez vous en liaison série, avec les paramètres suivants :

Configuration de l’OS

Une fois connecté en série ou en SSH, il faudra vous connecter avec l’utilisateur par défaut avec votre émulateur de terminal :

Default User :

rock

Default Password :

rock

Ensuite, vous pouvez lancer les commandes suivantes pour mettre votre OS à jour :

sudo apt-get update && sudo apt-get upgrade 

Lire le journal système :

Il est très intéressant lorsque vous rencontré un problème de venir vérifier les messages système :

journalctl

Il est possible de passer une chaine de caractère en argument pour filtrer ce qui est affiché :

journalctl -u error

Se connecter au Wifi

  • Pour vérifier que votre carte réseau est bien détecté :
ip addr
  • Pour accéder au super-utilisateur :
 sudo su
  • Pour scanner les réseaux WIFI disponibles :
nmcli dev wifi
  • Pour se connecter à votre réseau WIFI (remplacez bien wifi_name par le nom de votre réseau et wifi_password par son mot de passe ) :
 nmcli dev wifi connect "wifi_name" password "wifi_password"

Installer un IDE Python

Un des langage de base utilisé sur Linux est Python. Vous pouvez installer l’IDE Thonny très simplement à l’aide la commande ( une fois connecté au wifi )

sudo apt install thonny

Sources

  • https://wiki.radxa.com/RockpiS/ssh
  • https://wiki.radxa.com/RockpiS/dev/serial-console
  • https://wiki.radxa.com/RockpiS
  • https://www.sigmdel.ca/michel/ha/rockpi/rockpis_01_en.html

Installer et configurer GRBL pour Ramps 1.4 (MPCNC)

Installer et configurer GRBL pour Ramps 1.4 (MPCNC)

Nous allons voir dans ce tutoriel comment configurer le firmware GRBL 0.9 pour Ramps 1.4 avec Arduino Mega 2560 et s’interfacer avec LaserGRBL. Pour contrôler votre CNC ou MPCNC avec LaserGRBL, vous avez besoin d’installer et de configurer un Firmware sur votre carte Arduino, pour qu’elle puisse interpréter correctement les ordres et commandes de votre software de gravure/découpe Laser, qu’on appelle un émetteur G-code ( G-code étant le langage de programmation pour les machines CNC ). Dans ce tutoriel nous aborderons LaserGRBL

Ce tutoriel fait suite à celui-ci : Installation et câblage d’une carte Ramps 1.4 pour une MPCNC.

Matériel

  • Arduino MEGA 2560
  • Carte RAMPS 1.4
  • 1 Laser 20W : LD4070HA
  • 5 Moteurs pas à pas : 17HS15-1504S-X1
  • 3 Pilotes de moteurs pas à pas : DRV8825

Softwares

Nettoyer l’EEPROM

Avant de de télécharger et téléverser GRBL sur votre carte, il faut s’assurer que toutes les valeurs stockées sont nettoyées, et pour cela on a besoin du code suivant pour remettre les paramètres par défaut de votre carte :

/*
 * EEPROM Clear
 *
 * Sets all of the bytes of the EEPROM to 0.
 * Please see eeprom_iteration for a more in depth
 * look at how to traverse the EEPROM.
 *
 * This example code is in the public domain.
 */

#include <EEPROM.h>

void setup() {
  // initialize the LED pin as an output.
  pinMode(13, OUTPUT);
  
  /***
    Iterate through each byte of the EEPROM storage.
    Larger AVR processors have larger EEPROM sizes, E.g:
    - Arduino Duemilanove: 512 B EEPROM storage.
    - Arduino Uno:         1 kB EEPROM storage.
    - Arduino Mega:        4 kB EEPROM storage.
    Rather than hard-coding the length, you should use the pre-provided length function.
    This will make your code portable to all AVR processors.
  ***/

  for (int i = 0 ; i < EEPROM.length() ; i++) {
    EEPROM.write(i, 0);
  }

  // turn the LED on when we're done
  digitalWrite(13, HIGH);
}

void loop() {
  /** Empty loop. **/
}

Brancher votre carte Arduino en liaison série avec son câble USB, copier et coller ce code dans votre Arduino IDE et puis uploader pour nettoyer l’EEPROM.

Modification de GRBL pour Ramps

Vous pouvez télécharger GRBL for Ramps sur ce Repository Github. Si vous ne savez pas utiliser Git, vous pouvez suivre ce tutoriel pour avoir les bases de cet outil.

Le Firmware GRBL a été modifié à certains endroits pour qu’il soit adapté à notre MPCNC. Avant d’uploader le Firmware avec Arduino IDE, voici les paramètres à vérifier par rapport à votre installation :

// Enables variable spindle output voltage for different RPM values. On the Arduino Uno, the spindle
// enable pin will output 5V for maximum RPM with 256 intermediate levels and 0V when disabled.
// NOTE: IMPORTANT for Arduino Unos! When enabled, the Z-limit pin D11 and spindle enable pin D12 switch!
// The hardware PWM output on pin D11 is required for variable spindle output voltages.
#define VARIABLE_SPINDLE // Default disabled. Uncomment to enable.<----------------------------------- Uncommented for Ramps 1.4 

Ici, on décommente la ligne #define VARIABLE_SPINDLE dans le fichier config.h pour avoir le contrôle en PWM sur le laser.

/*-----------------------------------------------------------suite du code---------------------------------------------------*/
// Define spindle enable and spindle direction output pins.
#define SPINDLE_ENABLE_DDR   DDRH
#define SPINDLE_ENABLE_PORT  PORTH
#define SPINDLE_ENABLE_BIT   6  // MEGA2560 Digital Pin 9 <---------- Modified for Ramps 1.4. Orignal was BIT 3 for Digital Pin 6
#define SPINDLE_DIRECTION_DDR   DDRE
#define SPINDLE_DIRECTION_PORT  PORTE
#define SPINDLE_DIRECTION_BIT   3 // MEGA2560 Digital Pin 5

// Define flood and mist coolant enable output pins.
// NOTE: Uno analog pins 4 and 5 are reserved for an i2c interface, and may be installed at
// a later date if flash and memory space allows.
#define COOLANT_FLOOD_DDR   DDRH
#define COOLANT_FLOOD_PORT  PORTH
#define COOLANT_FLOOD_BIT   5 // MEGA2560 Digital Pin 8
#ifdef ENABLE_M7 // Mist coolant disabled by default. See config.h to enable/disable.
#define COOLANT_MIST_DDR   DDRH
#define COOLANT_MIST_PORT  PORTH
#define COOLANT_MIST_BIT   3 // MEGA2560 Digital Pin 6 <---------- Modified for Ramps 1.4. Orignal was BIT 6 for Digital pin 9
/*-----------------------------------------------------------suite du code--------------------------------------------------*/

Ici, dans le fichier intitulé cpu_map.h, il faut bien faire attention aux pins de sortie pour le « Spindle » qui va ici correspondre à la pin pour activer ou désactiver le Laser.

#define SPINDLE_PWM_DDR		DDRB // <------------------------------ Modified for Ramps 1.4. Orignal was DDRH
#define SPINDLE_PWM_PORT    PORTB // <--------------------------- Modified for Ramps 1.4. Orignal was PORTH
#define SPINDLE_PWM_BIT		5 // MEGA2560 Digital Pin 11 <--------- Modified for Ramps 1.4. Orignal was BIT 6 for Digital Pin 9
#endif // End of VARIABLE_SPINDLE

Configuration du pinout de la carte

Toujours dans le même fichier, cpu_map.h, On modifie la pin de contrôle de la puissance du laser en PWM pour correspondre à notre câblage.

Pour comprendre un peu comment ces modifications, il faut qu’on se penche sur les schémas structurels de la carte Ramps 1.4 et de l’Arduino MEGA 2560 :

On peut remarquer que les pins digitals qui nous servent à alimenter le laser (Pin Digital 9) et celle qui sert à le contrôler (Pin Digital 11) sont définis à travers leur PORT, d’où la nécessité de les définir par leurs numéros de Port, respectivement 6 sur le PORTH et 5 sur le PORTE (PH6 et PE5 sur le schéma).
La modification PH3 pour la pin digital 6 sert juste à libérer la pin digital 9 qui utilisé de base pour un système de refroidissement qui n’est pas dans notre configuration.

Maintenant que vous avez compris les modifications apportés au Firmware, vous pouvez l’uploader sur votre carte Arduino. Attention, la compilation peut prendre plusieurs minutes, c’est normal, soyez patient.

Menu de configuration GRBL

Une fois LaserGRBL installé, ouvrez l’application puis connectez vous en liaison série USB à votre carte Arduino Mega / votre CNC :

Ensuite, cliquez sur Grbl Configuration, qui correspond aux paramètres propres à la CNC qui est connectée. Vous ne pouvez que modifier et réécrire les valeurs lorsque LaserGRBL est connecté à votre CNC.

Vous aurez accès aux paramètres de votre CNC , valeurs qui seront enregistrés sur votre carte Arduino.

N.B.: si vous utilisez plusieurs machines ou plusieurs ordinateurs, vous pouvez exporter et importer vos paramètres de configuration

Désactivation des limites de position

Tout d’abord, commencez par désactiver les Soft Limits en mettant à 0 la valeur de la ligne Soft limits enable (&20 et $21). Cela rendra les premiers tests plus simples sans que LaserGRBL pense que votre machine se trouve en dehors de ses dimensions.

Configuration des paramètres

Les paramètres importants ici tous ceux qui concernent les axes X, Y et Z.
Pour régler la valeur de travel resolution, aussi dit la résolution de déplacement de chaque axe, il faut se référer à l’équation :
Résolution de déplacement = (Pas par tour * Réduction mécanique) / Micro-pas

  • Pas par tour (Step per Revolution) : C’est le nombre de pas effectués par le moteur pour effectuer une rotation complète.(ici 200 pas par tour)
  • Réduction mécanique (Gear Reduction) : Si votre système utilise des engrenages ou des poulies pour réduire ou augmenter le couple, vous devez prendre en compte le rapport de réduction mécanique. Cela affectera la résolution de déplacement effective de l’axe. Nous utilisons des courroies qui ont pour valeur 40 : 1 de réduction mécanique.
  • Micro-pas (Microstepping) : Certains contrôleurs de moteur pas à pas prennent en charge le micro-pas, qui permet de diviser chaque pas électrique. Cela permet une meilleure résolution. Les valeurs possibles sont 1/2, 1/4, 1/8, 1/16, etc. (Ici on a 1/32).

Pour l’accélération, veuillez vous référer à la valeur donner sur la datasheet du moteur.

Notes sur le calcul des paramètres

  • Résolution

Pour un système poulie (20dents) courroie (pas 2mm) avec micro-pas (1/32), le rapport de réduction est donné par:

( 200 * 32 ) / (20*2) = 160 step/mm

Pour un système à vis sans fin avec un ratio de 8mm par revolution et micro-pas (1/32), on a

( 200 * 32 ) / 8 = 800 step/mm.

  • vitesse maximale

Pour la vitesse maximale, soit le Maximum Rate vous pouvez utiliser l’équation suivante :

Vitesse maximale = (Pas par tour * Fréquence maximale d’impulsions de pas) / (Micro-pas * 60)

Dans notre cas
Vitesse maximale = ( 200*36 000) / ( 40*60 ) = 3000 mm/min.

  • zone de travail

La taille maximale de déplacement(maximum travel) dépend de la surface réelle de travail de votre CNC. Pour la mesurer :

  • Configurez tout d’abord les paramètres précédents
  • Avec les flèches de l’interface utilisateur de LaserGRBL, déplacez la tête de votre CNC jusqu’au coin bas gauche.
  • Allumez le laser avec le bouton Focus et marquez l’endroit où il pointe, en allumant le laser avec une forte puissance par exemple.
  • répéter l’opération dans tous les coins.
  • mesurez la surface de travail avec une règle ou un mètre.

Modification et ajout de bouton sur LaserGRBL

Pour modifier un bouton, il suffit de clique-droit dessus et choisissez « Editer le bouton »

Vous pouvez modifier GCode envoyer par le bouton ainsi. Pour que le Laser Focus ainsi que Blink marche à 3% de sa puissance, vous pouvez mettre ces GCodes suivant.

; pour GCode
M3 S30
G1 F1000
; pour GCode2
M5 S0
G0

Pour créer votre propre bouton, vous pouvez faire clique-droit sur une zone vide de l’interface utilisateur où il n’y a pas de bouton et choisissez « Ajouter un bouton personnalisé ». Cela peut être utile par exemple pour ajouter de quoi manipuler l’axe Z si vous voulez changer la hauteur de l’outil de votre CNC :

  • Entrer : permet de choisir si c’est un bouton qui s’active en cliquant une fois dessus, en maintenant appuyé, qui s’enclenche et se déclenche en cliquant dessus, etc..
  • Caption : ce sera le nom afficher de votre bouton
  • Info-bulle : permet de décrire ce que fait votre bouton
  • Activé : permet de savoir quand est-ce que le bouton sera débloqué, ici Idle signifie qu’il sera actif seulement si la CNC est connecté et déverrouillé.
  • GCode : c’est là où on met les lignes de commandes qu’enverra votre bouton à votre CNC.
    Voici différents GCode pour 6 boutons pour déplacer l’axe Z avec une précision différente :
G91 Z-10 ; Monter l'axe Z de 10mm
G91 Z10 ; Descendre l'axe Z de 10mm
G91 Z-5 ; Monter l'axe Z de 5mm
G91 Z5 ; Descendre l'axe Z de 5mm
G91 Z-1 ; Monter l'axe Z de 1mm
G91 Z1 ; Descendre l'axe Z de 1mm

Sources

  • https://planet-cnc.com/how-to-setup-cnc/
  • https://blog.orientalmotor.com/motor-sizing-basics-part-3-acceleration-torque-and-rms-torque
  • https://lasergrbl.com/configuration/
  • https://docs.v1e.com/learn/gcode/
  • https://www.youtube.com/watch?v=erXw09OcdeU
Installation et câblage d’une carte Ramps 1.4 pour une MPCNC

Installation et câblage d’une carte Ramps 1.4 pour une MPCNC

Une MPCNC est l’acronyme de « Mostly Printed CNC », ce qui signifie qu’elle est principalement construite à partir de pièces imprimées en 3D. Il s’agit d’une machine CNC (Computer Numerical Control) qui permet de réaliser des opérations d’usinage, de gravure, de découpe ou de fraisage sur différents matériaux tels que le bois, le plastique ou l’aluminium. La MPCNC est conçue pour être abordable et facile à construire, grâce à son architecture modulaire et à l’utilisation de composants électroniques couramment disponibles. Elle est basée sur le principe de la fraiseuse à portique ou un Laser, où un chariot mobile se déplace le long de 3 axes (X et Y principalement, et Z pour régler la hauteur de l’outil légèrement ) tandis que l’outil effectue les opérations sur le matériau. La MPCNC peut être contrôlée par un logiciel de commande numérique, qui envoie des instructions précises aux moteurs pour déplacer les axes selon les coordonnées spécifiées.
Ici, nous nous appuyons sur la MPCNC de V1 Engineering, pour construire notre propre Graveuse et Découpe Lase. Nous aborderons essentiellement le câblage de la Machine, le guide technique pour imprimer et monter les pièces se trouvant sur le site de V1 Engineering.

La carte Ramps 1.4 est une carte d’extension électronique utilisée dans les imprimantes 3D et les machines CNC. Le terme « Ramps » est un acronyme pour « RepRap Arduino Mega Pololu Shield ». Elle est spécifiquement conçue pour fonctionner avec la plateforme Arduino Mega et offre une interface de contrôle pour les moteurs pas à pas, les capteurs, les fins de course, les ventilateurs, etc. La carte Ramps 1.4 est dotée de plusieurs emplacements pour les pilotes de moteurs pas à pas Pololu A4988 ou DRV8825, qui fournissent la puissance nécessaire pour contrôler les moteurs de la machine CNC ou de l’imprimante 3D. Elle intègre également des connecteurs pour les thermistances, les ventilateurs de refroidissement, les afficheurs LCD, les boutons de commande et d’autres périphériques. La carte Ramps 1.4 est compatible avec divers logiciels de contrôle, des firmware, tels que Marlin ou GRBL, qui permettent de gérer précisément les mouvements des moteurs et de superviser l’impression ou l’usinage en cours.

Matériel

  • Carte Ramps 1.4
  • Arduino Mega 2560
  • 5 Moteurs pas à pas : 17HS15-1504S-X1
  • 3 Pilotes de moteurs pas à pas : DRV8825
  • Alimentation Sortie 12V et 20A: S-250-12
  • 1 Laser 20W : LD4070HA
  • Des fils.

Montage Ramps 1.4 sur Arduino Mega

Après avoir monté la structure de votre MPCNC, il vous faut monter la partie électronique, et pour cela, on commence avec la Ramps 1.4. Comme décrit précédemment, c’est un Shield pour carte Arduino Mega, ce qui rend le montage assez simple. Il suffit d’empiler les broches et les pins des 2 cartes :

Ensuite on vient placer les jumpers pour les drivers. Il faut relier les pins qui se trouveront sous les drivers sur la carte tel que :

Ensuite, on passe aux pilotes des moteurs pas à pas qui permettent la communication entre les moteurs et la carte. Ils ont aussi une fonction très importante de limiter le courant dans les moteurs pour éviter les surchauffes. Il suffit de les enfoncer dans les pins juste des jumpers tel que :

Réglage du potentiomètre de chaque driver

Il est TRÈS important de faire cette étape correctement, si le courant est trop élevé, cela provoque une surchauffes moteurs qui finit par les abîmer sur des longues durées.
Commençons par calculer le courant maximum à laisser passer dans les moteurs. Pour cela il faut vous référer à l’équation qui limite le courant dans la datasheet de votre Pilote.
Ici, pour les DRV8825, on a l’équation suivantes : Limit Current = VREF x 2
VREF est la tension qu’on mesure aux bornes du pilote et qu’on règle avec le potentiomètre et Limite Current est le Courant/Phase consommé par votre moteur, valeur indiqué dans la datasheet de votre moteur pas à pas. Ici, pour les 17HS15-1504S-X1 on Courant/Phase = 1,5 A
Donc pour savoir la valeur de VREF, on a VREF = Limite Current / 2 = 1,5 / 2 = 0,75 V.
Cependant, ici, nos moteurs pas à pas ne portent pas de charges lourdes, qui nécessitent davantage de courant. 0,75 V étant le maximum, on peut réduire cette valeur pour limiter la surchauffe des moteurs, à 60%. Soit VREF(diminué) = 0,75 x 0,6 = 0,45 V.

Maintenant, après avoir branché votre carte à l’alimentation 12V ( pensez bien à régler la tension de sortie de l’alimentation avec un tournevis et en mesurant la tension aux bornes des sorties ), munissez vous d’un multimètre pour mesurer VREF aux bornes du pilote comme ceci :

Vous pouvez mesurer directement VREF entre la masse du pilote et sur le potentiomètre directement. Pour régler, il vous faudra un tournevis assez fin pour manipuler la vis du potentiomètre et changer la valeur VREF à la tension souhaitée, ici 0,45V.

Branchement des moteurs pas-à-pas

Une fois votre VREF réglé, vous pouvez brancher les moteurs pas-à-pas. On remarque alors ici sur notre machine, nous avons deux moteurs pas-à-pas pour chacun des axes X et Y, ce qui nécessite de les brancher en séries pour qu’ils puissent être contrôler par le même pilote. On peut aussi les brancher en parallèle mais nous vous déconseillons fortement car cela consommerait davantage de courant.

Vous pouvez remarquer que les moteurs pas-à-pas sont branchés en séries, ce qui implique de couper des câbles et de les resouder. Les couleurs représentés sur ce schéma sont celles des couleurs de câbles usuellement vendu avec des moteurs pas-à-pas. Faites bien attention à l’ordre des câbles lors des branchements. Aussi, on peut remarquer que l’axe Y le sur schéma n’as pas les couleurs de câbles dans le même ordre que les autres, mais un ordre inversé. C’est normal, vous pouvez inverser l’ordre des couleurs branchés sur la carte Ramps 1.4 pour inverser le sens de rotation des moteurs, pour qu’ils correspondent à votre installation. Il faudra faire des tests pour savoir s’ils tournent dans le bon sens.

Branchement du Laser

Ceci est une étape qui peut varier car il dépend de l’outil que vous brancherez sur votre MPCNC. Vous pouvez y brancher une fraiseuse par exemple.
Ici, nous prendrons comme exemple le branchement du Laser 20W LD4070HA. On l’alimentera en 12V par la pin D9 et on contrôlera la puissance du laser par la Pin Digital 11 en PWM.

Voilà maintenant le câblage électrique terminé ! Pour la partie software et firmware, vous pouvez suivre ce tutoriel.

Sources :

  • https://docs.v1e.com/electronics/ramps/
  • https://docs.v1e.com/mpcnc/intro/
  • https://docs.v1e.com/electronics/steppers/
  • https://forum.v1e.com/t/stepper-motor-voltage/18573
  • https://www.youtube.com/watch?v=89BHS9hfSUk
  • http://voidmicro.com/Products/Laser/LD4070HA-en.html?page=page_laser
Lancer un fichier Profile au démarrage de Linux

Lancer un fichier Profile au démarrage de Linux

Nous allons voir dans ce tutoriel comment créer et lancer un fichier Profile au démarrage d’une machine Linux, comme votre Raspberry Pi, afin de configurer et personnaliser le compte de votre utilisateur. Lorsque vous utilisez régulièrement, votre ordinateur Linux, il peut être utile de charger un profil au démarrage afin d’avoir un environnement qui vous correspond et qui peut vous suivre d’une machine à une autre.

N.B.: Pour obtenir le même fonctionnement qu’un fichier .profile, il est possible de créer un fichier que vous lancer au démarrage de votre système (dans le fichier rc.local ou à l’aide de crontab) avec la commande source ./myprofile

Qu’est-ce qu’un fichier profile?

Comme mentionné en introduction, un fichier profile va se lancer au démarrage de la machine. Il y a des fichiers de configuration propre au système (OS, hardware) qui vont se charger pour tous les utilisateurs et des fichiers de configuration propre à chaque compte utilisateurs qui vont se lancer à la connexion et permettre de configurer des alias, des fonctions, des chemins d’accès, etc.

Où trouver le fichier profile?

Le fichier profile le plus courant est caché et situé à la racine .profile. Si c’est un fichier que vous avez créé et que vous lancer au démarrage ou manuellement, vous pouvez l’enregistrer où vous le souhaitez.

Pour le trouver, vous pouvez utiliser la commande suivante qui permet d’afficher les fichiers cachés sur votre système

ls -a
ou
ls -al

Voici quelques fichiers de configuration qui se charge au démarrage

  • ~/.profile
  • /etc/profile
  • /etc/profile.d
  • /etc/bashbashrc
  • /etc/bash_completion

Que doit-on mettre dans le fichier profile?

Le langage utilisée dans le fichier profile est le bash. Il doit donc être adapté en fonction du shell utilisé

  • Les alias

Lorsqu’on travaille avec Linux, on a souvent à faire au terminal et au ligne de commande. Les alias permettent de raccourcir des lignes de commandes.

alias <name>='command1 arg1 arg2; command2'

N.B.: il n’y a pas d’espace autour du « = ». On peut mettre plusieurs commande à la suite avec « ; », « && » ou « | ».

alias ll='ls -l'

Vous pouvez retrouver la liste des alias en tapant la commande alias sans argument

quelques applications pratiques

alias update='sudo apt-get update && sudo apt-get upgrade'
alias histg='history | grep' # "histg cd" list all previous commands containing cd
alias aptclean='sudo apt-get -y autoremove && sudo apt-get clean'
alias syslog='cat /var/log/syslog'

Ce fichier une fois créé, peut vous suivre d’une machine à une autre et vous permettre de retrouver votre environnement.

  • les fonctions

les fonctions sont comme des alias avec des séquences de commandes qui peuvent être plus complexes

cdl(){
    cd "$@";
    ls -al;
}
  • les exports

Un peu comme les alias vous pouvez créer des variables d’environnement et donner des noms pour vos chemins d’accès, par exemple

export workdir="/home/user/work/"

pour voir l’ensemble des export : export -p

Sources