Fabrication industrielle
Internet des objets industriel | Matériaux industriels | Entretien et réparation d'équipement | Programmation industrielle |
home  MfgRobots >> Fabrication industrielle >  >> Manufacturing Technology >> Processus de fabrication

Construire un servomoteur linéaire de précision avec retour de position - Guide étape par étape

Dans ce tutoriel, nous allons apprendre à fabriquer un servo-actionneur linéaire. Contrairement aux actionneurs linéaires classiques qui se déplacent dans une direction particulière lorsqu'une tension est appliquée, ce servo-actionneur linéaire sur mesure fournit des mouvements précis et répétables qui peuvent être facilement contrôlés.

On l'appelle un servo-actionneur car il dispose d'un système de boucle de rétroaction grâce auquel nous pouvons contrôler avec précision le mouvement de sortie de l'actionneur.

Vous pouvez regarder la vidéo suivante ou lire le didacticiel écrit ci-dessous.

Vue d'ensemble

L'entrée pour contrôler ce servo-actionneur linéaire peut être analogique ou numérique. Dans le cas d'une entrée analogique, il peut s'agir de n'importe quel type de potentiomètre comme illustré ici. Un potentiomètre linéaire, un potentiomètre rotatif commun ou par exemple un joystick qui est encore un potentiomètre rotatif et ainsi de suite.

Dans le cas d'une entrée numérique, nous pouvons contrôler l'actionneur avec un émetteur RC. Bien sûr, pour cette configuration, nous avons également besoin d'un récepteur RC qui sert d'entrée à l'actionneur.

Pour ces deux modes d'entrée analogique et numérique, nous n'avons besoin que de 3 fils pour établir une connexion, dont 2 pour alimenter le périphérique d'entrée et le 3ème pour le signal d'entrée.

Une fonctionnalité intéressante de ce servo-actionneur linéaire sur mesure est que nous pouvons définir une position de début et de fin personnalisée pour la tige de sortie ainsi qu'ajuster la sensibilité ou la rapidité avec laquelle l'actionneur répondra à notre entrée. 

Cependant, ma fonctionnalité préférée est la possibilité de contrôler cet actionneur à partir d’un PC ou d’un ordinateur portable via une communication par port série. Nous pouvons saisir des valeurs en millimètres via le moniteur Arduino IDE Serial et l'actionneur se déplacera vers cette position.

Ce qui est encore plus cool, nous pouvons effectuer des mouvements répétables, ou stocker les positions, en tapant « enregistrer » sur le moniteur série à chaque position souhaitée, puis dire à l'actionneur de répéter les mouvements en boucle, en tapant « exécuter » sur le moniteur série.

Laissez-moi maintenant vous expliquer tout ce que vous devez savoir sur ce servo-actionneur linéaire sur mesure, comment il fonctionne et comment je l'ai conçu, afin que vous puissiez également en construire un vous-même. 

Comment ça marche

Ainsi, le système de contrôle en boucle fermée est basé sur le capteur de position rotatif magnétique AS5600 et le contrôle PID mis en œuvre pour piloter le moteur à courant continu.

En fait, j'utilise la même carte de contrôleur de servomoteur personnalisée que celle que j'ai créée dans ma vidéo précédente, qui comprend son propre microcontrôleur et tout le reste pour transformer facilement n'importe quel moteur à courant continu en un servomoteur autonome.

Vous pouvez consulter ce didacticiel pour une explication détaillée du fonctionnement d'un servomoteur et d'un système de contrôle en boucle fermée.  

Très rapidement, un servomoteur est un système de contrôle en boucle fermée dans lequel le signal d'entrée, ou la position souhaitée, est comparé à la position réelle du moteur que nous obtenons du capteur de retour de position.

La différence qui se produit, appelée erreur, est ensuite traitée dans le contrôleur qui commande au moteur de se déplacer jusqu'à ce qu'il atteigne la position souhaitée. 

Ainsi, ce servo-actionneur linéaire a le même principe de fonctionnement qu'un servomoteur, mais avec une étape supplémentaire consistant à convertir le mouvement de rotation du moteur en un mouvement linéaire à l'aide d'un mécanisme à vis mère.

Conception de servomoteur linéaire

Voici le modèle 3D de ce servo-actionneur linéaire, d'où nous pouvons voir comment tout fonctionne.

Le capteur de position rotatif magnétique AS5600 est situé à l'arrière de l'actionneur et assure le suivi de la rotation de la vis mère. La vis mère que j'utilise a un pas de 8 mm, ce qui signifie qu'à chaque rotation complète, l'écrou de la vis mère effectue un mouvement linéaire de 8 mm.

L'AS5600 est un encodeur 12 bits, ce qui signifie qu'il peut produire 4 096 positions par tour. Si on divise 8 par 4096, on obtient une résolution de 0,001953 mm. Il s’agit du plus petit changement de position que l’encodeur AS5600 puisse détecter. C'est assez impressionnant je trouve. 

Le moteur à courant continu que j'utilise est un moteur 12 V avec réducteur inclus qui produit 480 tr/min. Si nous divisons les 480 par 60, nous obtenons une valeur de 8 tours par seconde, et si nous multiplions ce nombre par 8, car la vis mère a un pas de 8 mm, nous obtenons une vitesse linéaire de 64 mm/s de l'actionneur.

J'ai trouvé que c'était sur place, car la course maximale de cette tige d'actionneur est de 150 mm, cela prendrait donc environ 2,5 secondes du début à la fin à la vitesse maximale, ou environ 3 secondes si l'on inclut l'accélération et la décélération. Par conséquent, j'ai utilisé un rapport d'engrenage de 1:1 pour entraîner la vis mère. 

La conception de l'ensemble de l'actionneur linéaire est basée sur la taille du circuit imprimé du contrôleur de servomoteur personnalisé ainsi que de la vis mère et de l'écrou de la vis mère, bien sûr. Le PCB avait une dimension de 40x40mm, c'était donc la taille minimale du bloc-cylindres.

L'écrou de la vis mère de 8 mm avait une dimension extérieure de 22 mm, c'est pourquoi j'ai conçu la tige en fonction de cela. L'écrou et la tige sont reliés par quatre boulons M3 et des inserts filetés. Au sommet de la tige, il y a un roulement qui coulisse sur le bloc-cylindres et qui sert à guider la tige et à l'empêcher de tourner. 

Au niveau du chapeau de cylindre de sortie, nous avons 4 petits roulements qui guident la tige hors du bloc cylindre.

Dans l'ensemble, je pense que l'actionneur linéaire s'est révélé suffisamment compact compte tenu de tous les composants utilisés.

J'ai également réussi à installer un micro-interrupteur de fin de course à l'intérieur du bloc-cylindres, qui est utilisé pour la prise d'origine et le réglage de la position de départ de l'actionneur.

Téléchargement du modèle 3D

Vous pouvez visualiser et explorer le modèle 3D de ce servoactionneur linéaire sur mesure directement sur votre navigateur Web avec Onshape. (vous avez besoin d'un compte Onshape pour cela, vous pouvez créer un compte gratuit pour un usage domestique)

Vous pouvez obtenir les fichiers STL nécessaires à l'impression 3D, ainsi que le fichier STEP de ce modèle 3D auprès de Cults3D.

Une autre chose à mentionner ici est que vous pouvez facilement augmenter la longueur de course maximale de cet actionneur linéaire, en augmentant simplement la longueur du bloc-cylindres et de la tige. J'ai choisi ces dimensions car je voulais que toutes les pièces tiennent sur une imprimante 3D avec un lit d'impression plus petit de 220x220mm. La plus grande partie ici est la tige, qui mesure 215 mm de long.

Impression 3D

Ma nouvelle Creality Ender-3 V3 SE a fait un excellent travail en l'imprimant dans une orientation horizontale le long de l'axe Y. Bien que nous devions faire un peu d'envoi, imprimer la tige dans cette orientation contribuera à un fonctionnement plus fluide et à une tige plus solide.

Lors de l'impression 3D, il est important d'utiliser la fonction d'expansion horizontale de votre logiciel de découpage afin de compenser l'expansion du filament et d'obtenir des pièces dimensionnellement plus précises.

J'ai utilisé une valeur de –0,1 mm, mais vous devriez faire quelques tests d'impression pour voir quelle valeur conviendra à votre imprimante 3D. 

J'ai imprimé le bloc-cylindres le long de l'axe Z pour éviter d'imprimer beaucoup de matériel de support. Le Creality Ender-3 V3 SE a également fait un excellent travail pour cette impression.

J'ai été agréablement surpris par la qualité d'impression offerte par cette imprimante 3D compte tenu de son prix. La configuration de l'imprimante 3D est très simple, elle dispose d'un nivellement automatique du lit, d'une extrudeuse directe, d'une excellente qualité d'impression et de vitesses d'impression accrues allant jusqu'à 250 mm/s. Tout cela pour un peu moins de 200 $ en fait l'une des meilleures imprimantes 3D pour ceux qui ont un budget limité.

Découvrez cette imprimante 3D sur la Creality Store ou Amazon . Consultez également mon avis détaillé sur mon site Web.

Assemblage

Quoi qu'il en soit, voici toutes les pièces imprimées en 3D, nous pouvons donc maintenant commencer par assembler l'actionneur linéaire.

Liste des pièces

Vous pouvez obtenir les composants nécessaires à ce projet de servomoteur linéaire à partir des liens ci-dessous :

Mécanique :

Électronique :

Divulgation :ce sont des liens d'affiliation. En tant qu'associé Amazon, je gagne des revenus grâce aux achats éligibles.

Assemblage du mécanisme à vis mère

Tout d’abord, nous devons installer la vis mère en place dans le bloc de base du cylindre. Pour cela, nous devons d'abord insérer cet écrou imprimé en 3D qui a le même filetage que la vis mère.

Il est un peu difficile de visser l’écrou sur la vis mère car il est bien ajusté, mais c’est ce dont nous avons besoin ici. Cet écrou maintient toute la force lorsque la tige pousse, donc plus l'ajustement est serré, plus la force pourra retenir. En plus de cela, l'écrou dispose également d'un trou pour insérer un insert fileté pour le fixer à l'arbre avec une vis sans tête.

La vis mère est maintenue en place dans le bloc de base du cylindre à l'aide de deux roulements à billes de 22 mm de diamètre extérieur.

À l’arrière se trouve l’engrenage qui entraîne la vis mère. Cet engrenage possède également un filetage correspondant et deux trous pour des inserts filetés permettant de le fixer à la vis mère avec des vis sans tête.

Cette connexion est également critique car elle transfère tout le couple du moteur à la vis mère, elle ne doit donc pas glisser. 

Pour réaliser ce sous-ensemble, il faut d'abord installer les inserts filetés en place sur le pignon et l'écrou, ainsi que certains sur le bloc cylindre.

Nous vissons l'engrenage et l'écrou dans le sens opposé mais pas trop serré car cela ajoute des forces axiales aux roulements. Ensuite, à l'aide de vis sans tête, nous pouvons fixer l'écrou et l'engrenage à la vis mère.

Une fois fixée, on peut remarquer que la vis mère n'est pas encore fixée en place. Nous devons ajouter cette plaque au bloc-cylindres pour garantir que les roulements resteront en place dans le bloc-cylindres.

Ceci termine ce sous-ensemble; la vis mère est désormais fermement en place tout en pouvant tourner librement. 

Ensuite, nous pouvons préparer la tige. La tige est creuse sur toute sa longueur pour accueillir la vis mère. Pour connecter l'écrou de la vis mère et la tige, nous devons d'abord installer des inserts filetés. 

Sur le côté supérieur de la tige, nous devons installer le roulement de guidage avec un diamètre extérieur de 13 mm et un diamètre intérieur de 6 mm.

Nous plaçons le roulement sur un arbre creux de 6 mm imprimé en 3D et le fixons à la tige avec une vis à tête fraisée M3 de 10 mm de longueur. La tige est maintenant prête et nous pouvons voir comment elle va glisser dans les rails de guidage du cylindre.

Ensuite, nous devons fixer le cylindre au bloc de base du cylindre. Mais avant de faire cela, nous devons installer le micro-interrupteur de fin de course en place.

Tout d’abord, nous devons y souder les fils, au niveau de la connexion NC. Les fils doivent mesurer environ 15 cm de long. Les fils passent à travers un trou en haut du cylindre, puis nous pouvons fixer le micro-interrupteur de fin de course au cylindre à l'aide de deux boulons M2 de 8 mm de longueur.

Vous aurez spécifiquement besoin de ce micro fin de course pour que le roulement de guidage le déclenche juste au bon moment, sans heurter autre chose.

Si vous ne trouvez pas le modèle exact de fin de course, vous pouvez bien entendu modifier les trous et le mécanisme. 

Afin de fixer le cylindre au bloc de base, nous devons installer ici des inserts filetés. Ensuite, nous pouvons le fixer en place à l'aide de deux boulons M4 d'une longueur de 25 mm. Nous devrions insérer uniquement les deux boulons supérieurs à ce moment-là.

Les deux inférieurs seront installés un peu plus tard lors de l'installation de la boîte de vitesses et du couvercle du PCB car les mêmes trous sont utilisés pour fixer le couvercle. 

Ensuite, nous pouvons visser la tige dans la vis mère. Le roulement de guidage doit se situer entre les rails de guidage du cylindre.

En faisant tourner l'engrenage à l'arrière, la tige reculera jusqu'à ce qu'elle atteigne le micro-interrupteur de fin de course. 

Ensuite, nous pouvons fixer le bouchon du cylindre en place. Le capuchon du cylindre pourra accueillir quatre petits roulements d'un diamètre extérieur de 9 mm. Les arbres de ces roulements peuvent être imprimés en 3D.

Nous devons être prudents lors de leur insertion, car la partie où vont ces arbres est assez petite et pourrait facilement se casser. Cela m'est arrivé plusieurs fois, alors assurez-vous qu'ils sont faciles à installer. Ces roulements soutiendront et guideront la tige pour un fonctionnement plus fluide.

Le capuchon du cylindre est fixé en place avec quatre boulons M4.

Installation du moteur à courant continu

Ok, nous pouvons ensuite insérer le moteur à courant continu en place. Nous sécurisons le moteur à courant continu avec six boulons M3. Ensuite, nous pouvons installer l'engrenage sur l'arbre du moteur.

Pour fixer l'engrenage en place, nous utilisons deux inserts filetés et des vis sans tête. 

Une fois les engrenages correctement appariés, nous pouvons procéder à la fixation des engrenages et du couvercle du PCB à l'arrière de l'actionneur linéaire. Pour cela, nous devons d'abord installer quelques inserts filetés supplémentaires dans le bloc de base du cylindre.

Ensuite, nous pouvons connecter les fils au moteur à courant continu. Dans mon cas, je les ai directement soudés au moteur DC.

La longueur des fils doit être d'environ 20 cm. Il y a un trou dans le bloc de base du cylindre à travers lequel nous devons faire passer les fils du moteur à courant continu et du fin de course.

Ensuite, nous devons également les passer à travers deux supports sur le couvercle, ce qui garantira qu'ils restent éloignés de l'équipement. 

À ce stade, nous pouvons fixer le couvercle au bloc de base. Pour cela, nous devons d'abord insérer les deux boulons M4 sur le côté inférieur, mais pas jusqu'au bout.

Nous devons laisser environ 2 mm ou 3 mm pour pouvoir placer le support du couvercle entre les deux, puis fixer ces boulons avec le couvercle.

Toute cette opération est un peu compliquée, mais il fallait qu'il en soit ainsi parce que je voulais que le couvercle soit le plus petit possible et qu'il ne fasse qu'une seule impression, et les supports de PCB bloquaient le passage des boulons.

Installation du PCB du servocontrôleur personnalisé

Quoi qu'il en soit, une fois que nous avons terminé avec le couvercle, nous pouvons installer la carte de contrôleur de servomoteur personnalisée en place. Comme je l'ai dit, c'est le même contrôleur de ma vidéo précédente dans laquelle je vous ai montré comment transformer n'importe quel moteur à courant continu en servomoteur.

Le composant principal ici est le codeur de position rotatif magnétique AS5600, qui assure le suivi de la position angulaire de l'aimant fixé sur l'arbre de sortie. Dans ce cas, nous fixerons l'aimant à l'engrenage de sortie sur la vis mère. L'aimant est parfaitement aligné avec le capteur AS5600 lorsque le PCB est mis en place.

Pour fixer le PCB, nous devons d'abord insérer des écrous M2 dans les fentes des supports, puis serrer le PCB avec quatre boulons M2.

Il ne reste plus qu'à connecter les fils en place. Les fils du moteur à courant continu vont au bornier du moteur et la polarité doit également être vérifiée pour correspondre au programme du contrôleur.

En fait, avant de connecter le moteur au PCB, nous pouvons lui appliquer une certaine tension pour vérifier si le mécanisme de la vis mère fonctionne correctement.

En ce qui concerne les fils des fins de course, comme je n'ai pas de broches dédiées à cet effet, j'ai soudé le fil de terre au plot de masse du condensateur électrolytique, et le fil de connexion NC à la broche SCK, qui est la broche numérique numéro 13 du microcontrôleur ATMEGA328.

Le bornier d'alimentation est juste à côté du côté du couvercle, il y a donc un trou à travers lequel j'ai connecté un connecteur d'alimentation de 5,5 mm.

J'ai également ajouté un dissipateur thermique au pilote du moteur DC. Enfin, nous pouvons mettre le couvercle à pression sur la face arrière et c'est tout, nous avons terminé ce projet. 

Nous pouvons désormais connecter n'importe quel type de potentiomètre ou un récepteur RC aux broches d'entrée appropriées, et nous pouvons contrôler la position de l'actionneur linéaire avec.

Comme je l'ai déjà mentionné, dans ma vidéo précédente, j'ai expliqué en détail le fonctionnement de ce contrôleur, son schéma de circuit et comment j'ai réalisé le PCB.

Vous devriez donc consulter ce tutoriel si vous souhaitez créer cette carte contrôleur. 

Schéma du circuit

Très rapidement, le composant principal est le capteur magnétique AS5600, qui assure le suivi de la position de la sortie de l'actionneur. Les données du capteur vont dans le cerveau de cette carte de servocontrôleur, le microcontrôleur Atmega328, qui fait le calcul et indique au pilote de moteur à courant continu DRV8871 comment piloter le moteur à courant continu.

Le pilote de moteur CC DRV8871 peut gérer jusqu'à 3,6 A de courant de crête. Pour alimenter la carte, nous pouvons utiliser du 12 V qui est ensuite ramené à 5 V avec un régulateur de tension ASM1117 pour l'Atmega328 et les autres composants 5 V. Il y a un commutateur DIP à deux canaux à travers lequel nous sélectionnons le mode d'entrée de l'actionneur, soit analogique, soit numérique, ou via la communication du port série.

L'un des potentiomètres du trimmer est utilisé pour régler la sensibilité de l'actionneur, et le bouton-poussoir SDM est utilisé pour régler les positions de début et de fin.

J'ai commandé le PCB chez PCBWay. Ici, nous pouvons simplement télécharger le fichier Gerber, choisir les propriétés de notre PCB et le commander à un prix raisonnable.

J'ai conçu le PCB pour qu'il ait 4 couches, celles du milieu sont pour GND, ce qui augmente un peu le prix. Je n'ai modifié aucune des propriétés par défaut, à l'exception de la couleur du PCB que j'ai choisi comme blanc, et je coche que j'accepte le changement de finition de surface en Or par immersion, le cas échéant, sans frais supplémentaires.

Vous pouvez trouver et télécharger le Gerber depuis la communauté de partage de projets PCBWay à travers laquelle vous pouvez également commander directement le PCB.

Quoi qu'il en soit, vous pouvez également réaliser ce projet d'actionneur linéaire même sans ce servocontrôleur personnalisé, bien sûr.

Vous pouvez utiliser le capteur AS5600 sur une carte de dérivation en combinaison avec une carte Arduino pour contrôler le moteur à courant continu.

Code

Jetons maintenant un coup d'œil au code de ce servomoteur linéaire :

/*
 Linear Servo Actuator - Arduino Code
 by Dejan, www.HowToMechatronics.com
 Libraries:
 AS5600 encoder: https://github.com/RobTillaart/AS5600
 PID conroller: https://github.com/br3ttb/Arduino-PID-Library/blob/master/PID_v1.h
*/
#include "AS5600.h"
#include "Wire.h"
#include <PID_v1.h>
AS5600 as5600; // use default Wire
double Pk1 = 0.65; //speed it gets there
double Ik1 = 0;
double Dk1 = 0.1;
//Define Variables we'll be connecting to
double Setpoint, Input, Output;
PID myPID(&Input, &Output, &Setpoint, Pk1, Ik1, Dk1, DIRECT);
#define motor_IN1 5
#define motor_IN2 6
#define ch1 2
#define setButton 7
#define inputSwitch 3
#define modeSwitch 4
#define limitSwitch 13
int ch1Value;
long encoderValue, desiredValue, pwmValue;
String serialInput = ""; // string to hold input
int serialIntInput;
double totalDistance = 0;
long startPosition = 358;
long endPosition = 6750;
long rangeAdjustment = 0;
float sensitivityAdjustment = 0;
float angle = 0;
float angleValue = 0;
float rodPosition;
float positionsArray[100];
int positionsCounter = 0;
long quadrantNumber = 2;
long previousQuadrantNumber = 3;
long numberOfTurns = 0;
float totalAngle = 0;
char incomingByte = 0;
int intInput = 0;
void setup() {
 Serial.begin(115200);
 Serial.println(__FILE__);
 Serial.print("AS5600_LIB_VERSION: ");
 Serial.println(AS5600_LIB_VERSION);
 Wire.begin();
 pinMode(motor_IN1, OUTPUT);
 pinMode(motor_IN2, OUTPUT);
 // Activate the Arduino internal pull-up resistors
 pinMode(setButton, INPUT_PULLUP);
 pinMode(inputSwitch, INPUT_PULLUP);
 pinMode(modeSwitch, INPUT_PULLUP);
 pinMode(limitSwitch, INPUT_PULLUP);
 // PID Setup
 myPID.SetMode(AUTOMATIC);
 myPID.SetOutputLimits(-255, 255);
 myPID.SetSampleTime(20);
 // --- HOMING ----
 // Move backward until you ...
 while (digitalRead(limitSwitch) != 1) {
 digitalWrite(motor_IN1, LOW);
 analogWrite(motor_IN2, 70);
 encoderValue = as5600.readAngle();
 }
 while (digitalRead(limitSwitch) != 0) {
 analogWrite(motor_IN1, 50);
 digitalWrite(motor_IN2, LOW);
 }
 digitalWrite(motor_IN1, LOW);
 digitalWrite(motor_IN2, LOW);
 startPosition = as5600.readAngle() * 0.087890625;
 endPosition = 6000;
 Setpoint = startPosition;
 // --- HOMING End ---
}
void loop() {
 // Read encoder value - current position
 rodPosition = as5600.readAngle() / 0.001953125; // in millimters - The lead screw is 8mm per rotation, and the encoder RAW value is 4096 per roration, so 8/4096 to get the value in milimiters
 // Serial communication mode - Read data from the serial monitor
 if (digitalRead(modeSwitch) == 0) {
 while (Serial.available() > 0) {
 serialInput = Serial.readString();
 serialInput.trim();
 // If "save" string is sent through the serial monitor, save the current rodPosition into the array
 if (serialInput == "save") {
 positionsArray[positionsCounter] = totalDistance;
 delay(1000);
 positionsCounter++;
 }
 // Clear the saved positions
 if (serialInput == "clear") {
 // Clear the array data to 0
 memset(positionsArray, 0, sizeof(positionsArray));
 positionsCounter = 0;
 }
 // Convert the String to Integer and use it as a Setpoint for the PID control
 serialIntInput = serialInput.toInt();
 if (serialIntInput != 0) {
 if (serialIntInput < 0) {
 serialIntInput = 0;
 }
 if (serialIntInput > 150) {
 serialIntInput = 150;
 }
 Setpoint = serialIntInput * 45; // convert mm into degrees (1mm linear movement equals 45 degrees rotational movement)
 }
 }
 
 // Run stored positions
 if (serialInput == "run") {
 while (serialInput != "stop") {
 for (int i = 0; i <= positionsCounter - 1; i++) {
 if (serialInput == "stop") {
 break;
 }
 while (positionsArray[i] > totalDistance + 25 || positionsArray[i] < totalDistance - 25 || pwmValue != 0) {
 // Desired position / setpoint for the PID contorller
 Setpoint = positionsArray[i];
 // Read encoder - use that value as an Input for the PID control
 readEncoder();
 // Run motor - PID controller inside
 runMotor();
 
 }
 delay(2000); // Delay between steps 
 // Check the serial monitor for a stop command
 while (Serial.available() > 0) {
 serialInput = Serial.readString();
 serialInput.trim();
 }
 }
 }
 }
 }
 // Potentiometer and RC Receiver control mode
 else if (digitalRead(modeSwitch) == 1) {
 if (digitalRead(inputSwitch) == 0) { // Analog input - Potentiometer
 // Get value from potentiometer
 desiredValue = analogRead(A0);
 if (desiredValue < 15) {
 desiredValue = 15;
 }
 if (desiredValue > 1008) {
 desiredValue = 1008;
 }
 Setpoint = map(desiredValue, 15, 1008, startPosition, endPosition);
 
 } else if (digitalRead(inputSwitch) == 1) { // Digital input - RC transmitter
 desiredValue = pulseIn(ch1, HIGH, 30000); // Read RC receiver as input
 if (desiredValue < 1000 || desiredValue > 2000) {
 desiredValue = 1000;
 }
 Setpoint = map(desiredValue, 1000, 2000, startPosition, endPosition);
 }
 }
 
 // Confine the minimum and maximum values of the setpoint
 if (Setpoint > endPosition) {
 Setpoint = endPosition;
 }
 if (Setpoint < startPosition) {
 Setpoint = startPosition;
 }
 // Adjusting sensitivity
 //Pk1 = analogRead(A2) * 0.002; // Adjust the PID gain term 
 //myPID.SetTunings(Pk1, Ik1, Dk1);
 // Read encoder - use that value as an input for the PID control
 readEncoder();
 // Run motor
 runMotor();
 // Set start and end positions by pressing the "set" button
 if (digitalRead(setButton) == LOW) {
 delay(3000);
 if (digitalRead(setButton) == LOW) {
 endPosition = totalDistance;
 while (digitalRead(setButton) != HIGH)
 ;
 } else {
 startPosition = totalDistance;
 }
 }
}
void readEncoder() {
 // Convert encoder RAW values into angle values for keeping track of the angular position of the shaft
 encoderValue = as5600.readAngle() * 0.087890625;
 // Quadrant 1
 if (encoderValue >= 0 && encoderValue <= 90) {
 quadrantNumber = 1;
 }
 // Quadrant 2
 if (encoderValue >= 90 && encoderValue <= 180) {
 quadrantNumber = 2;
 }
 // Quadrant 3
 if (encoderValue >= 180 && encoderValue <= 270) {
 quadrantNumber = 3;
 }
 // Quadrant 4
 if (encoderValue >= 270 && encoderValue <= 360) {
 quadrantNumber = 4;
 }
 if (quadrantNumber != previousQuadrantNumber) {
 // Transition from 4th to 1st quadrant
 if (quadrantNumber == 1 && previousQuadrantNumber == 4) {
 numberOfTurns++;
 }
 // Transition from 1st to 4th quadrant
 if (quadrantNumber == 4 && previousQuadrantNumber == 1) {
 numberOfTurns--;
 }
 previousQuadrantNumber = quadrantNumber;
 }
 if (totalDistance >= 0) {
 totalDistance = (numberOfTurns * 360) + encoderValue;
 } else {
 totalDistance = (numberOfTurns * 360) + encoderValue;
 }
 // Establish Input value for PID
 Input = totalDistance; // current value of the position
}
void runMotor() {
 // Run PID process to get Output value
 myPID.Compute();
 // Move right
 if (Output > 1) {
 pwmValue = Output;
 if (pwmValue < 50 && pwmValue > 15) {
 pwmValue = pwmValue + 40;
 }
 if (pwmValue <= 15) {
 pwmValue = 0;
 }
 analogWrite(motor_IN1, pwmValue);
 digitalWrite(motor_IN2, LOW);
 }
 // Move left
 else if (Output < 1) {
 pwmValue = abs(Output);
 if (pwmValue < 50 && pwmValue > 15) {
 pwmValue = pwmValue + 40;
 }
 if (pwmValue <= 15) {
 pwmValue = 0;
 }
 digitalWrite(motor_IN1, LOW);
 analogWrite(motor_IN2, pwmValue);
 }
 // Do not move
 else if (Output > -1 && Output < 1) {
 pwmValue = 0;
 digitalWrite(motor_IN1, LOW);
 digitalWrite(motor_IN2, LOW);
 }
}
Code language: PHP (php)

Description du code

Ainsi, nous démarrons la boucle en lisant la valeur de l'encodeur ou la position actuelle de l'actionneur et la convertissons en millimètres.

// Read encoder value - current position
 rodPosition = as5600.readAngle() / 0.001953125; // in millimters - The lead screw is 8mm per rotation, and the encoder RAW value is 4096 per roration, so 8/4096 to get the value in milimiters
Code language: PHP (php)

Ensuite, si nous sommes en « mode de communication série », nous lisons les données entrantes que nous saisissons sur le moniteur série. Si l'entrée est « enregistrer », nous stockons l'actionneur de position actuelle, ou si elle est « effacer », nous effaçons toutes les positions déjà stockées.

// Serial communication mode - Read data from the serial monitor
 if (digitalRead(modeSwitch) == 0) {
 while (Serial.available() > 0) {
 serialInput = Serial.readString();
 serialInput.trim();
 // If "save" string is sent through the serial monitor, save the current rodPosition into the array
 if (serialInput == "save") {
 positionsArray[positionsCounter] = totalDistance;
 delay(1000);
 positionsCounter++;
 }
 // Clear the saved positions
 if (serialInput == "clear") {
 // Clear the array data to 0
 memset(positionsArray, 0, sizeof(positionsArray));
 positionsCounter = 0;
 }Code language: JavaScript (javascript)

Si l'entrée est un entier ou un nombre, de 0 à 150, nous utilisons cette valeur comme point de consigne.

// Convert the String to Integer and use it as a Setpoint for the PID control
 serialIntInput = serialInput.toInt();
 if (serialIntInput != 0) {
 if (serialIntInput < 0) {
 serialIntInput = 0;
 }
 if (serialIntInput > 150) {
 serialIntInput = 150;
 }
 Setpoint = serialIntInput * 45; // convert mm into degrees (1mm linear movement equals 45 degrees rotational movement)
 }
 }Code language: JavaScript (javascript)

Nous entrons les valeurs en millimètres, mais pour suivre l'arbre en rotation, nous utilisons des degrés, nous convertissons donc les valeurs en millimètres en valeurs en degrés en multipliant par 45. En effet, pour un mouvement linéaire de 1 mm, la vis mère doit tourner de 45 degrés. Si vous avez un pas différent sur votre vis mère, ce numéro doit être différent. 

Si nous tapons "run", à l'aide de quelques boucles while et for, le programme parcourra les positions stockées à plusieurs reprises.

// Run stored positions
 if (serialInput == "run") {
 while (serialInput != "stop") {
 for (int i = 0; i <= positionsCounter - 1; i++) {
 if (serialInput == "stop") {
 break;
 }
 while (positionsArray[i] > totalDistance + 25 || positionsArray[i] < totalDistance - 25 || pwmValue != 0) {
 // Desired position / setpoint for the PID contorller
 Setpoint = positionsArray[i];
 // Read encoder - use that value as an Input for the PID control
 readEncoder();
 // Run motor - PID controller inside
 runMotor();
 
 }
 delay(2000); // Delay between steps 
 // Check the serial monitor for a stop command
 while (Serial.available() > 0) {
 serialInput = Serial.readString();
 serialInput.trim();
 }
 }
 }
 }Code language: JavaScript (javascript)

Par contre, si nous sommes en mode de contrôle Potentiomètre et récepteur RC, nous vérifions si nous avons une entrée analogique ou numérique.

// Potentiometer and RC Receiver control mode
 else if (digitalRead(modeSwitch) == 1) {
 if (digitalRead(inputSwitch) == 0) { // Analog input - Potentiometer
 // Get value from potentiometer
 desiredValue = analogRead(A0);
 if (desiredValue < 15) {
 desiredValue = 15;
 }
 if (desiredValue > 1008) {
 desiredValue = 1008;
 }
 Setpoint = map(desiredValue, 15, 1008, startPosition, endPosition);
 
 } else if (digitalRead(inputSwitch) == 1) { // Digital input - RC transmitter
 desiredValue = pulseIn(ch1, HIGH, 30000); // Read RC receiver as input
 if (desiredValue < 1000 || desiredValue > 2000) {
 desiredValue = 1000;
 }
 Setpoint = map(desiredValue, 1000, 2000, startPosition, endPosition);
 }
 }Code language: JavaScript (javascript)

S'il est analogique, nous lisons l'entrée analogique du potentiomètre et utilisons cette valeur comme point de consigne ou comme position souhaitée pour l'actionneur. De même, si l'entrée est numérique, nous lisons les données entrantes du récepteur RC et utilisons cette valeur comme point de consigne. 

Ensuite, nous appelons les fonctions personnalisées readEncoder() et runMotor() pour lire la position actuelle de l'actionneur et exécuter le contrôle PID. Avec la fonction readEncoder(), nous lisons la valeur actuelle du capteur en valeurs d'angle, et avec ces instructions if, nous gardons une trace dans quel quadrant se trouve la position actuelle de l'arbre.

void readEncoder() {
 // Convert encoder RAW values into angle values for keeping track of the angular position of the shaft
 encoderValue = as5600.readAngle() * 0.087890625;
 // Quadrant 1
 if (encoderValue >= 0 && encoderValue <= 90) {
 quadrantNumber = 1;
 }
 // Quadrant 2
 if (encoderValue >= 90 && encoderValue <= 180) {
 quadrantNumber = 2;
 }
 // Quadrant 3
 if (encoderValue >= 180 && encoderValue <= 270) {
 quadrantNumber = 3;
 }
 // Quadrant 4
 if (encoderValue >= 270 && encoderValue <= 360) {
 quadrantNumber = 4;
 }
 if (quadrantNumber != previousQuadrantNumber) {
 // Transition from 4th to 1st quadrant
 if (quadrantNumber == 1 && previousQuadrantNumber == 4) {
 numberOfTurns++;
 }
 // Transition from 1st to 4th quadrant
 if (quadrantNumber == 4 && previousQuadrantNumber == 1) {
 numberOfTurns--;
 }
 previousQuadrantNumber = quadrantNumber;
 }
 if (totalDistance >= 0) {
 totalDistance = (numberOfTurns * 360) + encoderValue;
 } else {
 totalDistance = (numberOfTurns * 360) + encoderValue;
 }
 // Establish Input value for PID
 Input = totalDistance; // current value of the position
}Code language: HTML, XML (xml)

Grâce à ces informations, nous pouvons suivre la façon dont l’arbre tourne et quand il effectuera un tour complet. L'angle total est la valeur d'entrée du contrôleur PID. 

En utilisant l'entrée analogique du potentiomètre trimmer, nous pouvons ajuster le gain proportionnel du contrôleur PID, et enfin nous exécutons le processus PID pour obtenir une valeur de sortie.

// Adjusting sensitivity
 //Pk1 = analogRead(A2) * 0.002; // Adjust the PID gain term 
 //myPID.SetTunings(Pk1, Ik1, Dk1);Code language: JSON / JSON with Comments (json)
void runMotor() {
 // Run PID process to get Output value
 myPID.Compute();
 // Move right
 if (Output > 1) {
 pwmValue = Output;
 if (pwmValue < 50 && pwmValue > 15) {
 pwmValue = pwmValue + 40;
 }
 if (pwmValue <= 15) {
 pwmValue = 0;
 }
 analogWrite(motor_IN1, pwmValue);
 digitalWrite(motor_IN2, LOW);
 }
 // Move left
 else if (Output < 1) {
 pwmValue = abs(Output);
 if (pwmValue < 50 && pwmValue > 15) {
 pwmValue = pwmValue + 40;
 }
 if (pwmValue <= 15) {
 pwmValue = 0;
 }
 digitalWrite(motor_IN1, LOW);
 analogWrite(motor_IN2, pwmValue);
 }
 // Do not move
 else if (Output > -1 && Output < 1) {
 pwmValue = 0;
 digitalWrite(motor_IN1, LOW);
 digitalWrite(motor_IN2, LOW);
 }
}Code language: JavaScript (javascript)

Nous utilisons cette valeur de sortie pour piloter les moteurs à courant continu avec un signal PWM, à gauche ou à droite, ou en position immobile en fonction de la valeur de sortie du contrôleur PID, ou en fonction de l'erreur entre la position souhaitée et la position réelle lue par l'encodeur.

Les trois termes du contrôleur PID, proportionnel, intégral et dérivé, sont définis en haut, et en les ajustant, nous pouvons obtenir différentes réponses de sortie.

double Pk1 = 0.65; //speed it gets there
double Ik1 = 0;
double Dk1 = 0.1;Code language: JavaScript (javascript)

La qualité, la façon dont l'actionneur fonctionnera ou répondra à nos entrées dépend directement de ces valeurs.

Tests

Ici, je teste la précision de l'actionneur. Il se remet décemment en place. Ensuite, j'ai commencé à déplacer la tige d'un millimètre à la fois. Le premier mouvement était d'environ 0,8 mm au lieu de 1 mm, mais les 4 suivants étaient suffisamment proches de 1 mm.  Ensuite, le mouvement de 4 mm était d'environ 0,15 mm. 

Il faut remarquer que la tige a un jeu d'environ 0,25 mm. Ce jeu se situe entre la vis mère et l’écrou de la vis mère. En plus de cela, nous avons probablement un jeu dans les engrenages imprimés en 3D ainsi que dans les engrenages du moteur à courant continu lui-même.  

Si nous appliquons une force à la tige et testons la précision maintenant, bien sûr, nous obtiendrons une erreur encore plus grande, mais cela peut être amélioré en peaufinant le contrôleur PID. 

Néanmoins, ce serait tout pour ce tutoriel. J'espère que vous l'avez apprécié et que vous avez appris quelque chose de nouveau.


Processus de fabrication

  1. Les opérations effectuées sur fraiseuse
  2. Transformez (presque) n'importe quelle surface en bouton tactile avec MPR121
  3. Nox – Un robot errant dans la maison (ROS)
  4. À quoi s'attendre d'un distributeur automatique de boissons gazeuses ?
  5. Multiplexeur de chargeur de batterie intelligent avec écran intelligent
  6. Test de fiabilité des PCB flexibles :à quoi prêter une attention particulière ?
  7. Le bras robotique industriel - Un boom de la fabrication
  8. Galoches
  9. Comment faire fondre du métal dans une fonderie