samedi 4 mai 2013

Hack d'un axe d'imprimante avec un Arduino


On commence par une vidéo du résultat obtenu : 





Voici l'axe de la tête d'impression d'une imprimante classique :

L'axe est contrôlé par un moteur à courant continu et est asservi grâce à un système de codeur linéaire. Le codeur linéaire est constitué de deux parties: une bande en plastique transparente graduée par des traits fins en noir :


Et d'un capteur optique :


La bande glisse à l'intérieur du capteur optique. 

Dans mon cas le capteur utilisé disposait de deux sorties (A et B). Cela permet de trouver le sens du mouvement. Sur la photo ci-dessous nous pouvons voir les 6 pattes du capteur optique. J'ai identifié le câblage qu'ils ont utilisé et fait un petit schéma.  Le circuit ci-dessous sert d'illustration, sur la carte de la tête d'impression il n'est pas implanté au même endroit.



Ici, nous pouvons voir le capteur situé sur la carte de la tête d'impression. C'est le même qu'au dessus. Le jeu consiste maintenant à identifier sur la tresse blanche les fils qui nous intéressent. C'est-à-dire l'alimentation, la masse, et les deux sorties du capteur. Cela doit varier en fonction des imprimantes...



Une fois les fils identifiés, nous pouvons les faire ressortir à l'arrière de l'axe :



Une fois cela fait, il faut pouvoir piloter le moteur de l'axe :


Pour cela j'ai réalisé le montage (pont en H) proposé sur ce post : http://arduino.cc/forum/index.php?topic=120408.0

J'ai donc deux fils reliés à mon Arduino pour piloter le moteur et deux pour lire les signaux du capteur.
J'ai écrit deux bibliothèques pour gérer ce projet. La première se nomme HBridge et comme son nom l'indique permet de faciliter le pilotage d'un pont en H à deux fils de commande (comme sur le schéma du lien ci-dessus). La deuxième se nomme PrinterAxis et permet de gérer l'axe de l'imprimante.  Pour utiliser les bibliothèques il faut créer un dossier portant le nom de la bibliothèque et y placer le .h et le .cpp. Ce dossier se place dans votre dossier arduino/libraries.

HBridge.h

#ifndef HBRIDGE_h
#define HBRIDGE_h
#include "Arduino.h"

/*
* Auteur: Eliott Dumeix
* Date: 04/05/2013
* Permet de contrôler un pont en H à 2 fils de commande.
*/

class HBridge {
  public:
   HBridge(int pinT1, int pinT2);
   void clockwise(byte pwm); // sens horraire
   void antiClockwise(byte pwm); // sens anti horraire
   void halt(); // stopper
   void setSpeed(int speed); // commander en vitesse (pwm) dans les deux sens
   void setMaxSpeed(int speed);
  
  private:
    const int t1;
    const int t2;
 int max_speed;
};

#endif
HBridge.cpp

#include "HBridge.h"

HBridge::HBridge(int pinT1, int pinT2): t1(pinT1), t2(pinT2), max_speed(255){
 pinMode(t1, OUTPUT);
 pinMode(t2, OUTPUT);
 halt();
} 

void HBridge::clockwise(byte pwm){
 digitalWrite(t2, LOW);
 analogWrite(t1, pwm);
}
   
void HBridge::antiClockwise(byte pwm){
    digitalWrite(t1, LOW);
 analogWrite(t2, pwm);
}
   
 
void HBridge::halt() {
    digitalWrite(t1, LOW);
    digitalWrite(t2, LOW);
}

void HBridge::setMaxSpeed(int speed) {
 max_speed = speed;
}


void HBridge::setSpeed(int speed) {
 if (speed>0) {
  if (speed>max_speed)
   analogWrite(t1, max_speed);
  else
   analogWrite(t1, speed);
 }
 else {
  if (speed<-max_speed)
   analogWrite(t2, max_speed);
  else
   analogWrite(t2, -speed);
 }
}
PrinterAxis.h
#ifndef PRINTERAXIS_h
#define PRINTERAXIS_h

#include "Arduino.h"
#include "HBridge.h"

/*
* Auteur: Eliott Dumeix
* Date: 04/05/2013
* Permet de contrôler un axe d'imprimante à encodeur linéaire.
* Encodeur 2 voies.
*/

class PrinterAxis {
 public:
  PrinterAxis(HBridge &motorRef, int pinA, int pinB);
  void step(int steps, int dir); // bouger de n pas, dir=RIGHT ou LEFT
  void goTo(int nGoal);
  void count();
  
  const int RIGHT;
  const int LEFT;
  
 private:
  const int A, B; // pin de l'encoder, channel A et B
  HBridge &motor; // Handle pour contrôler le moteur
  int n;
  int pos; // sauvegarde position 
  static const int val[2][2]; // attribue une valeur à la combinaison pin A et B
  static const int right[4];  // permet de retrouver si le chariot se déplace vers la droite
         // l'ancienne valeur attribuée, permet de déduire le sens du chariot
  // paramètres pour le correcteur PI
  int error_sum ;
  int error_fluc;
  float kp, ki;
};

#endif


PrinterAxis.cpp
#include "PrinterAxis.h"

const int PrinterAxis::right[4] = {2, 0, 3, 1};
const int PrinterAxis::val[2][2] = {{0, 1}, {2, 3}};

PrinterAxis::PrinterAxis(HBridge &motorRef, int pinA, int pinB)
    : motor(motorRef), A(pinA), B(pinB), RIGHT(1), LEFT(-1),
    n(0), kp(2), ki(0.005){
    pinMode(A, INPUT);
    pinMode(B, INPUT);
 pos = val[digitalRead(A)][digitalRead(B)];
 error_sum =0;
 error_fluc= 0;
}
    
void PrinterAxis::step(int steps, int dir) {
    int goal_n = n + steps*dir; // position désirée
 int pwm;
 
 int error = goal_n - n;
 while(error != 0) {
  count();
  error = goal_n -n;
  error_sum += error;
  count();
  pwm = error*kp + ki*error_sum;
  motor.setSpeed(pwm);
 }
 count();
 motor.halt();
 for(int i=0;i<200;i++)
  count();
}
    
void PrinterAxis::goTo(int nGoal) {
    if (nGoal==n) return;
  step(abs(nGoal-n), nGoal-n>0 ? RIGHT : LEFT);
}
    
void PrinterAxis::count() {
 byte v = val[digitalRead(A)][digitalRead(B)];
    if (v != pos) {
        if (right[v]==pos)
   n++;
        else
   n--;
    }
    pos = v; // sauvegarde ancienne position
}
Maintenant il ne reste plus qu'a utiliser les bibliothèques afin d'avoir un code propre :
#include <PrinterAxis.h>
#include <HBridge.h>

const int pin_channelA = 2;
const int pin_channelB = 3;
const int pin_t1 = 10;
const int pin_t2 = 9;

HBridge motor(pin_t1, pin_t2);
PrinterAxis axis(motor, pin_channelA, pin_channelB);

void setup() {
  TCCR1B = TCCR1B & 0b11111000 | 0x03;
  motor.setMaxSpeed(150);
}


void loop() {
  for (int i=0; i<20;i++) {
    axis.step(i*100, axis.RIGHT); 
    axis.step(i*100, axis.LEFT);
  }
}


1 commentaire: