Weekend Project: 7 Segmentanzeige mit Servomotoren

Im nachfolgenden Weekend Project möchte ich gerne aufzeigen wie man sich eine eigene, große 7 Segmentanzeige erstellen kann.

7 Segmentanzeige mit Servomotoren - "Ziffer 3"
7 Segmentanzeige mit Servomotoren – „Ziffer 3“

Ich habe dieses Projekt zuerst in einem Instagram Beitrag gesehen und fand dieses cool, daher wollte ich dieses gerne nachbauen und natürlich auf meinem Blog einen Beitrag dazu schreiben.

7 Segmentanzeige mit Servomotoren - Ziffern 0 & 1
Dieses Video ansehen auf YouTube.

 

Was ist eine 7 Segmentanzeige?

Mit einer 7 Segmentanzeige kann man die Zahlen von 0 bis 9 und einfache Buchstaben anzeigen.

7 Segmentanzeige am MakerUNO
7 Segmentanzeige am MakerUNO

Ich habe bereits im Tutorial Arduino Lektion 62: 7 Segmentanzeige eine 7 Segmentanzeige vorgestellt. 

Materialien & Werkzeuge

Materialien

Folgende Materialien werden benötigt:

  • 2x 3mm, DIN A4 Sperrholz,
  • Holzleiste, 20 cm Lang, 10 mm Stark
  • eventuell, Farbe für die Displayfläche,

Werkzeuge

  • Laubsäge,
    • Laubsägeblätter, fein
  • Heißklebepistole,
  • Holzleim,
  • Papierkleber, 
  • kleiner, Kreuzschraubendreher 
  • kleiner, Schlitzschraubendreher

elektrische Bauelemente

Vorlage

Zunächst einmal habe ich mir eine Vorlage im Zeichenprogramm paint.net erzeugt und diese Ausgedruckt dann auf das Sperrholz geklebt.

Vorlage für eine 7 Segmentanzeige auf Sperrholz
Vorlage für eine 7 Segmentanzeige auf Sperrholz

Ich habe dafür den Papierkleber der Firma „Pritt“ benutzt.
Diese ist deutlich besser als die günstigen.

Die Vorlage kannst du dir unter folgendem Link herunterladen:

 

Aufbau der 7 Segmentanzeige mit Sperrholz

Im folgenden Video zeige ich, wie ich die 7 Segmentanzeige mit Sperrholz erstellt habe.

Zunächst einmal habe ich jedes Segment mit der Laubsäge ausgesägt und danach auf das korrekte Maß geschliffen.  Danach wurde eine kleine 2cm lange Holzleiste montiert, damit dieses besser hält habe ich jeweils ein 2mm Loch hineingebohrt und ein 3mm x 12mm Kreuzschraube inkl. Holzleim verwendet. Wenn alle 7 Segmente montiert wurden dann wurden die Servomotoren mit der Heißklebepistole festgeklebt und diese danach auf die übrige Sperrholzplatte montiert. Zum Schluß habe ich die Segmente angestrichen.

DIY - 7 Segment Anzeige, Schritt 1 - Aufbau
Dieses Video ansehen auf YouTube.

Anschließen der 7 Servomotoren

Für den Betrieb der Servos verwende ich das PWMServoDriverShield vom Typ „PCA9685„. Dieses kann man bei ebay.de für knapp  5€ inkl. Versandkosten erwerben.

PWMServoDriverShield – Typ „PCA9685“

Das Shield hat den Vorteil das man die Servos per I2C ansprechen kann und somit die digitalen Pins des Microcontrollers frei hat. Ein weiterer großer Vorteil ist das die Boards kaskadiert werden können somit hat man die Möglichkeit nicht nur 16 Servos zu betreiben sondern bis zu 6x 16 Stück = 96 Stück.

PCA9685 16 Kanal Servo Driver Shield
PCA9685 16 Kanal Servo Driver Shield

Auf der Rückseite des Modules sind die maximalen Lasten für das Modul aufgedruckt.

PCA9685 16 Kanal Servo Driver Shield - Rückseite
PCA9685 16 Kanal Servo Driver Shield – Rückseite

Das Modul verfügt über 16 Steckplätze für Servomotoren, diese sind in der korrekten Pinanordnung so das man den Stecker des Servos direkt drauf stecken kann.

16 Kanal Servo Modul PCA9685 mit Servo
16 Kanal Servo Modul PCA9685 mit Servo

Des Weiteren verfügt das Modul über 6 Pins welche mit dem Microcontroller verbunden werden.

Je nach verwendeten Microcontroller muss das Modul anders angeschlossen werden. Hier nun die 3 Möglichkeiten für die gängigen Microcontroller der Arduino Baureihe:

Arduino UNO

  • VCC an 5V
  • GND an GND
  • SDA an analog A4
  • SCL an analog A5
Servo Driver Modul PAC9685 am Arduino UNO
Servo Driver Modul PAC9685 am Arduino UNO

Arduino Mega 2560 R3

  • VCC an 5V
  • GND an GND
  • SDA an digital 20
  • SCL an digital 21
Servo Driver Modul PAC9685 am Mega
Servo Driver Modul PAC9685 am Mega

Arduino Leonardo

  • VCC an 5V
  • GND an GND
  • SDA an SDA
  • SCL an SCL
Servo Driver Modul PAC9685 am Arduino Leonardo
Servo Driver Modul PAC9685 am Arduino Leonardo

Spannungsversorgung der Servos

Die Servos werden über einen Separaten Anschluß auf dem Modul mit Spannung versorgt. Die beiden Pins VCC & GND dienen „nur“ zum betrieb des Modules.

PAC9685 Schraubklemme für Spannungsversorgung der Servos
PAC9685 Schraubklemme für Spannungsversorgung der Servos

Programmieren des PAC9685 Servo Driver Shield

Damit wir das Modul verwenden können benötigen wir zusätzlich eine Bibliothek, diese können wir in der Arduino IDE bequem über den „Bibliotheksverwalter“ installieren.  

Die benötigte Bibliothek heißt „Adafruit PWM Servo Driver Library“ und kann über das Eingabefeld mit der Zeichenkette „pwm servo“ gefunden werden.

Arduino IDE - Bibliotheksverwalter "Adafruit PWM Servo Driver Library"
Arduino IDE – Bibliotheksverwalter „Adafruit PWM Servo Driver Library“

Wenn die Bibliothek installiert wurde kann es mit der Programmierung schon beginnen.

Einfaches Beispiel mit einem Servo

Als erstes wollen wir einen Servo betreiben und diesen von 0° bis 180° und zurück bewegen lassen.

#include <Wire.h> // OneWire Bibliothek
#include <Adafruit_PWMServoDriver.h> //Bibliothek für das PAC9585 Modul

//erzeugen einer Instanz für die Kommunikation
Adafruit_PWMServoDriver pwm = Adafruit_PWMServoDriver(); 

// Minimum der Pulselänge 
const int SERVOMIN = 125;
// Maximum der Pulselänge
const int SERVOMAX = 575;

//Port an welchem der Servo angeschlossen ist
const int SERVO_PORT = 0;
//Pause zwischen den einzelnen Schritten
const int PAUSE = 25;

void setup() {
  //beginn der Kommunikation
  pwm.begin();  
  //setzen der PWM Frequenz auf 60Hz
  pwm.setPWMFreq(60);
}

void loop() {
  //Schleife von 0..180
  for(int angle = 0;angle<180;angle++){
      //setzen des aktuellen Wertes von "angle" an dem Servo
      //dabei muss der aktuelle Winkel auf die Pulslänge gemappt werden. 
      pwm.setPWM(SERVO_PORT, 0, map(angle,0, 180, SERVOMIN,SERVOMAX));
      //eine kleine Pause
      delay(PAUSE);
  }

  //Schleife von 180..0
  for(int angle = 180;angle>=0;angle--){
      //setzen des aktuellen Wertes von "angle" an dem Servo
      //dabei muss der aktuelle Winkel auf die Pulslänge gemappt werden. 
      pwm.setPWM(SERVO_PORT, 0, map(angle,0, 180, SERVOMIN,SERVOMAX));
      //eine kleine Pause
      delay(PAUSE);
  }
}
Video
PWM Servo Driver Shield PAC9685 mit einem Servo
Dieses Video ansehen auf YouTube.

Sketch für die 7 Segmentanzeige

interne Klasse „Segment“

Da ich bedingt durch die künste nicht ganz gerade Sägen zu können etwas Toleranz in jedem Segment benötige habe ich mir die interne Klasse „Segment“ erzeugt.

Diese Klasse erhält

  • den Port an welchem der Servo angeschlossen ist,
  • den Namen,
  • den Wert „maxAngle“ für den untersten Wert,
  • den Wert „minAngle“ für den obersten Wert
class Segment{

 private:
  String name;
  int port;
  int maxAngle;
  int minAngle;

 public:
   Segment(String n, int p,int maxA, int minA){
     name = n;
     port = p;
     maxAngle = maxA;
     minAngle = minA;
   }

   String getName(){ return name; }
   int getPort(){ return port; }
   int getMaxAngle(){ return maxAngle; }
   int getMinAngle(){ return minAngle; }
};

Zunächst einmal werden wir also die Servos an den einzelnen Ports mit einer neuen Instanz der Klasse „Segment“ definieren.

Segment segmentA = Segment("Segment A", 0, 180, 90);
Segment segmentB = Segment("Segment B", 1, 180, 100);
Segment segmentC = Segment("Segment C", 2, 160, 60);
Segment segmentD = Segment("Segment D", 3, 160, 60);
Segment segmentE = Segment("Segment E", 4, 170, 60);
Segment segmentF = Segment("Segment F", 5, 140, 60);
Segment segmentG = Segment("Segment G", 6, 160, 90);

Ich verwende hier die Beschriftung A-G diese ist für die Definition der einzelnen Segmente einer 7 Segmentanzeige üblich.

7Segmentanzeige - Definition Segmente
7Segmentanzeige – Definition Segmente

Nun müssen wir noch in der Funktion „setup“ das PWM Modul „starten“ und die Frequenz für die Kommunikation festlegen, bei den von mir verwendeten Servos liegt diese bei 60Hz.

void setup() {
  Serial.begin(9600);
  Serial.println("16 channel Servo test!");

  pwm.begin();  
  pwm.setPWMFreq(60); 
}

In der Funktion „loop“ werden nun die einzelnen Funktionen zum anzeigen einer Zahl aufgerufen. Ich habe dieses einmal beispielhaft für die Zahlen 0 & 1 getan.

void loop() {
  displayNum0();
  delay(PAUSE);
  displayNum1();
  delay(PAUSE);
}

In den Funktionen selber wird zunächst ein Reset ausgeführt, dieses sorgt dafür das alle Servos in den Zustand „nicht angezeigt“ gehen (quasi im Winkel von 180°).

void reset(){
  resetSegment(segmentA);
  delay(PAUSE_KL);
  resetSegment(segmentB);
  delay(PAUSE_KL);
  resetSegment(segmentC);
  delay(PAUSE_KL);
  resetSegment(segmentD);
  delay(PAUSE_KL);
  resetSegment(segmentE);
  delay(PAUSE_KL);
  resetSegment(segmentF);
  delay(PAUSE_KL);
  resetSegment(segmentG);
}

Da ich doppelten Quellcode vermeiden möchte habe ich mir wiederum eine extra Funktion geschrieben in welcher ich den Port übergebe und diese mir den Servo auf den benötigten Winkel setzt.

void resetSegment(Segment segment){
  moveServo("reset ->",segment.getName(),segment.getPort(), angleToPulse(segment.getMaxAngle()));
}

Hier kommt auch schon die nächste Funktion „moveServo“ hat 3 Parameter, 

  • die Aktion, für die Ausgabe auf dem Seriellen Monitor der Arduino IDE,
  • den Port, an welchem der Servo angeschlossen ist,
  • der Winkel, in welchem Winkel der Servo versetzt werden soll
void moveServo(String action, String name, int port, int angle){
  Serial.print(action);
  Serial.println(name);  
  pwm.setPWM(port, 0, angleToPulse(angle));
}

Da das Modul PAC9685 mit Pulsen anstadt Winkeln arbeitet müssen wir zunächst den gewünschten Winkel in ein Pulse umwandeln, dazu nutzen wir die Funktion „map“. Wir wissen das bei Pulse „125“ der minimale Wert (also 0°) und bei „575“ der maximale Wert erreicht (also 180°) ist.

int angleToPulse(int ang){
   return map(ang,0, 180, SERVOMIN,SERVOMAX);
}

Nehmen wir einmal Beispielhaft die Zahl „0“, hier müssen alle Segmente aufgerichtet werden außer das Segment „G“. Wie erwähnt wird zunächst ein Reset ausgeführt, danach wird jedes einzelne Segment aufgerichtet. Zwischen den einzelnen Segmenten habe ich eine kleine Pause eingefüht, dieses musste ich machen da es wohl Zeitliche Probleme gibt.

void displayNum0(){
  reset();
  moveUp(segmentA);
  delay(PAUSE_KL);
  moveUp(segmentB);
  delay(PAUSE_KL);
  moveUp(segmentC);
  delay(PAUSE_KL);
  moveUp(segmentD);
  delay(PAUSE_KL);
  moveUp(segmentE);
  delay(PAUSE_KL);
  moveUp(segmentF);
}

Für die Zahl „1“ würden dann nur das Segment „B“ & „C“ aktiviert usw.

kompletter Sketch

Hier nun der komplette Sketch. Im unteren Bereich dieses Tutorials findest du den Sketch zum bequemen Download.

#include <Wire.h>
#include <Adafruit_PWMServoDriver.h>

Adafruit_PWMServoDriver pwm = Adafruit_PWMServoDriver();

#define SERVOMIN  125 // this is the 'minimum' pulse length count (out of 4096)
#define SERVOMAX  575 // this is the 'maximum' pulse length count (out of 4096)

const int PAUSE = 1000;
const int PAUSE_KL = 250;

class Segment{

 private:
  String name;
  int port;
  int maxAngle;
  int minAngle;

 public:
   Segment(String n, int p,int maxA, int minA){
     name = n;
     port = p;
     maxAngle = maxA;
     minAngle = minA;
   }

   String getName(){ return name; }
   int getPort(){ return port; }
   int getMaxAngle(){ return maxAngle; }
   int getMinAngle(){ return minAngle; }
};

Segment segmentA = Segment("Segment A", 0, 180, 90);
Segment segmentB = Segment("Segment B", 1, 180, 100);
Segment segmentC = Segment("Segment C", 2, 160, 60);
Segment segmentD = Segment("Segment D", 3, 160, 60);
Segment segmentE = Segment("Segment E", 4, 170, 60);
Segment segmentF = Segment("Segment F", 5, 140, 60);
Segment segmentG = Segment("Segment G", 6, 160, 90);


void setup() {
  Serial.begin(9600);
  Serial.println("16 channel Servo test!");

  pwm.begin();  
  pwm.setPWMFreq(60);  // Analog servos run at ~60 Hz updates
}

void loop() {
  displayNum0();
  delay(PAUSE);
  displayNum1();
  delay(PAUSE);
}

void displayNum0(){
  reset();
  moveUp(segmentA);
  delay(PAUSE_KL);
  moveUp(segmentB);
  delay(PAUSE_KL);
  moveUp(segmentC);
  delay(PAUSE_KL);
  moveUp(segmentD);
  delay(PAUSE_KL);
  moveUp(segmentE);
  delay(PAUSE_KL);
  moveUp(segmentF);
}

void displayNum1(){
  reset();
  moveUp(segmentB);
  delay(PAUSE_KL);
  moveUp(segmentC);
}

void displayNum2(){
  reset();
  moveUp(segmentA);
  delay(PAUSE_KL);
  moveUp(segmentB);
  delay(PAUSE_KL);
  moveUp(segmentG);
  delay(PAUSE_KL);
  moveUp(segmentE);
  delay(PAUSE_KL);
  moveUp(segmentD);
  delay(PAUSE_KL);
}

void displayNum3(){
  reset();
  moveUp(segmentA);
  moveUp(segmentB);
  moveUp(segmentG);
  moveUp(segmentC);
  moveUp(segmentD);
}

void displayNum4(){
  reset();
  moveUp(segmentF);
  moveUp(segmentG);
  moveUp(segmentB);
  moveUp(segmentC);
}

void displayNum5(){
  reset();
  moveUp(segmentA);
  moveUp(segmentF);
  moveUp(segmentG);
  moveUp(segmentC);
  moveUp(segmentD);
}

void displayNum6(){
  reset();
  moveUp(segmentA);
  moveUp(segmentF);
  moveUp(segmentG);
  moveUp(segmentE);
  moveUp(segmentD);
  moveUp(segmentC);
}

void displayNum7(){
  reset();
  moveUp(segmentA);
  moveUp(segmentB);
  moveUp(segmentC);
}

void displayNum8(){
  reset();
  moveUp(segmentA);
  moveUp(segmentB);
  moveUp(segmentC);
  moveUp(segmentD);
  moveUp(segmentE);
  moveUp(segmentF);
  moveUp(segmentG);
}

void displayNum9(){
  reset();
  moveUp(segmentA);
  moveUp(segmentB);
  moveUp(segmentC);
  moveUp(segmentG);
  moveUp(segmentF);
}

void reset(){
  resetSegment(segmentA);
  delay(PAUSE_KL);
  resetSegment(segmentB);
  delay(PAUSE_KL);
  resetSegment(segmentC);
  delay(PAUSE_KL);
  resetSegment(segmentD);
  delay(PAUSE_KL);
  resetSegment(segmentE);
  delay(PAUSE_KL);
  resetSegment(segmentF);
  delay(PAUSE_KL);
  resetSegment(segmentG);
}

void resetSegment(Segment segment){
  moveServo("reset ->",segment.getName(),segment.getPort(), segment.getMaxAngle());
}

void moveUp(Segment segment){
  moveServo("moveUp ->",segment.getName(),segment.getPort(), segment.getMinAngle());
}

void moveDown(Segment segment){
  moveServo("moveDown ->",segment.getName(),segment.getPort(), segment.getMaxAngle());
}

void moveServo(String action, String name, int port, int angle){
  Serial.print(action);
  Serial.println(name);  
  pwm.setPWM(port, 0, angleToPulse(angle));
}

int angleToPulse(int ang){
   return map(ang,0, 180, SERVOMIN,SERVOMAX);
}

Download

 

 

 

Ein Gedanke zu „Weekend Project: 7 Segmentanzeige mit Servomotoren

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.