Friday 8 January 2016

έξοδος 0-10V με arduino, 2η έκδοση

Η 2η έκδοση είναι βελτιωμένη στα σημεία.
Κυρίως, αντιμετωπίζει το θέμα της αντιστροφής της εξόδου που είχε η πρώτη έκδοση, που έπρεπε να αντιμετωπιστεί με software, (χρειαζόταν να δοθεί analogWrite(pin, 255) για να βγάλει μηδενική τάση).

Το νέο σχέδιο έχει ως ακολούθως:

και όπως φαίνεται, έχει προστεθεί ένα transistor-based inverter.

Στο σημείο Α έχουμε την παλμοσειρά που παράγει το arduino με πλάτος 5V.
Στο σημείο Β υπάρχει η παλμοσειρά ανεστραμμένη, πάλι  με 5V πλάτος.
Στο σημείο C υπάρχει η παλμοσειρά με πλάτος 12V αλλά ξανά ανεστραμμένη, δηλαδή με ίδια φάση όπως παράγεται στο σημείο Α.
Στο σημείο D έχουμε την μεταβλητή τάση εξόδου, η τιμή της οποίας εξαρτάται από το το duty cycle του αρχικού παλμού.

Το παρακάτω βίντεο δείχνει την παραγόμενη παλμοσειρά (σημείο A) και το βολτάζ (σημείο D) στην έξοδο του low pass.
Σε αντίθεση με την προηγούμενη έκδοση, σήμερα το βολτάζ που έχουμε στην έξοδο είναι ευθέως ανάλογο του duty cycle και όχι αντιστρόφως ανάλογο, όπως ήταν χτες.

Επίσης έχει προστεθεί ένα ενδεικτικό led στο pin 9 η ένταση του οποίου μεταβάλετε με βάση τo duty cycle.
H συσκευή στο breadboard είναι ως εξής:


Μεταξύ άλλων διακρίνονται τα δύο τρανζίστορ που φτιάχνουν τον διπλό inverter.
Α, και έβαλα και ένα ενδεικτικό LED στο pin 9 (συνδεδεμένο στην γείωση μέσω μία μικρής αντίστασης (470Ω, θα ήθελε μικρότερη αλλά τέτοιες είχα πρόχειρες...)

Το λογισμικό είναι και αυτό ελαφρά τροποποιημένο και έχει ως εξής:
char  fromConsole;
int   i,j;
void setup() {
  // put your setup code here, to run once:
  setPwd(0);
  Serial.begin(9600);
  delay(1000);
  sunRize();
  sunSet();
}
void setPwd (int value) {
     analogWrite(10, value);
     analogWrite(9, value); //led
}
void sunSet(){
      for (i=64;i>=0;i--){
      j=i*4; if (j<0) j=0; if (j>255) j=255;
      setPwd(j);
      Serial.println(j);
      delay (150);
    }
}
void sunRize(){
    for (i=0;i<=64;i++){
      j=i*4; if (j<0) j=0; if (j>255) j=255;
      setPwd(j);
      Serial.println(j);
      delay (150);
    }
}
void loop() {
  //check if a character on serial
  if (Serial.available()) {
    fromConsole=Serial.read();
    switch (fromConsole) {
      case '0':
        Serial.println("I received 0, setting PWD to 0, ie output 0V");
        setPwd(0);
        break;
      case '1':
        Serial.println("I received 1, setting PWD to 64, ie output to 1/4:");
        setPwd(64);
        break;
      case '2':
        Serial.println("I received 2, setting PWD to 128, ie output to 2/4:");
        setPwd(128);
        break;
      case '3':
        Serial.println("I received 3, setting PWD to 192, ie output to 3/4:");
        setPwd(192);
        break;
      case '4':
        Serial.println("I received 4, setting PWD to 255, ie output to 4/4:");
        setPwd(255);
        break;
      case '5':
        Serial.println("I received 5, doing a sunrize sequence");
        sunRize();
        break;
      case '6':
        Serial.println("I received 6, doing a sunset sequence");
        sunSet();
        break;
      default:
        Serial.println("Undefined button pressed");
        break;
      }
    }
  else {
    delay (500);
  }

}
Θέλω να πιστεύω πως με αυτή την καταχώριση το θέμα του ελέγχου ενός ballast με μεταβλητή τάση 0-10V έχει λήξει.

BR,
GT


--------------------

UPDATE!
κάθε άλλο παρά λήξαν αποδείχτηκε το θέμα ελέγχου ενός Ballast 0-10V για τον απλό λόγο πως όταν έγινε δοκιμή με πραγματικό ballast, βρέθηκε πως το ballast έδινε τάση (δεν λάμβανε) και για χειροκίνητο έλεγχο αρκούσε μία μεταβλητή αντίσταση...
Δυστυχώς είχαμε λάθος specs και αυτό που φτιάχτηκε ναι μεν μπορεί να βγάλει ρυθμιζόμενη τάση 0/10V ελεγχόμενη από πρόγραμμα, αλλά δεν μπορεί να χρησιμοποιηθεί για να ελέγξει την φωτεινότητα μίας λάμπας που έχει συνδεθεί σε ένα ballast τύπου  πχ Osram Quicktronic Deluxe.

Θεωρητικά θα έπρεπε να βάλουμε ψηφιακά ποτενσιόμετρα, που να συνδέονται με I2C, να ψάξουμε για βιβλιοθήκες ή να γράψουμε πολύπλοκα προγράμματα κλπ κλπ

Αλλά επειδή είμαστε σε κρίση, είπαμε αντί για όλα αυτά, να το φτιάξουμε να δουλεύει κάνοντας μία μικρή αλλαγή στο τρέχον κύκλωμα, που πλέον έχει ως εξής:


Αυτό δουλεύει δοκιμασμένα κανονικά και με πρόγραμμα απλό όπως στο παράδειγμα από πάνω.
Αν κάποιος το δοκιμάσει με κάποιο άλλο ballast και δεν δουλεύει, ας μου στείλει ένα μήνυμα μήπως μπορέσουμε να το φτιάξουμε.

Αλλά με Ballast Osram Quicktronic που έγινε δοκιμή, δουλεύει κανονικά.

Αξίζει να σημειωθεί ότι ένα arduino mini έχει 6 εξόδους PWM που σημαίνει ότι χωρίς δυσκολία ένα arduino θα μπορούσε να ελέγξει 6 ballasts. Βεβαίως τότε το challenge θα ήταν το UI.

Ίσως αργότερα, συνδυάζοντας το παραπάνω με ένα Raspberry Zero, να φτιαχτεί ένα IoT dimmer με UI ελεγχόμενο από smartphone.

(αν και δεν βλέπω μεγάλη χρησιμότητα, ίσως σαν άσκηση στη διασύνδεση Raspberry/Arduino και IoT Stacκ...)

Thursday 7 January 2016

Half-a-day project:προγραμματιζόμενη έξοδος 0-10V με arduino

Βρέθηκα να συζητάω για το πώς θα μπορούσε να φτιαχτεί ένα σύστημα που να βγάζει προγραμματιζόμενα μία μεταβλητή τάση από 0 έως 10V.

Σκέφτηκα ότι δεν δεν πρέπει να είναι τίποτα δύσκολο, σίγουρα θα έχει φτιαχτεί πολλές φορές και αν το "γκουγκλάρω" σίγουρα θα βρεθεί κάτι.
Αλλά δεν βρήκα! Βρήκα ένα κάρο κουβέντες αλλά όχι κάποια σαφή πρόταση..

πχ στο arduino forum υπάρχει η συζήτηση 
Topic: analog out 0-10V With Arduino for lighting control (Read 22823 times)" που όμως εκεί γίνεται κουβέντα για OpAmps, LMs, ADCs κλπ κλπ χωρίς να έχουν καταλήξει κάπου ή να υπάρχει κάτι συγκεκριμένο.
To ίδιο εδώ, (0-10V needed) σε ένα παλιό forum για PICs, ξαναρωτάνε τα ίδια πράγματα 10 χρόνια μετά το αρχικό post...
ή εδώ, και εδώ πάλι κουβέντες για OpAmps, που πρέπει να είναι non-inverting, να οδηγηθούν από μία αναλογική έξοδο, να είναι rail-to-rail, να μην χρειάζονται συμμετρική τροφοδοσία κλπ κλπ κλπ

Μου έκανε εντύπωση που δεν βρήκα μία ξεκάθαρη λύση, ένα step-by-step guide και είπα να το ψάξω να δω αν είναι τελικά τόσο δύσκολο ή τόσο πολύπλοκο.

Ας δούμε τι χρειαζόμαστε:

θέλουμε μία τάση που να κυμαίνεται από 0 έως 10V για να οδηγήσει κάποιο άλλο σύστημα, κυρίως dimmers.

H τάση που θα παίρνουμε θέλουμε να μεταβάλλεται προγραμματιζόμενα, πχ η μετάβαση από 0 στα 10V να γίνεται ομαλά και να ολοκληρώνεται σε μισή ώρα, το σύστημα να κρατάει τα 10V για 12 ώρες και μετά να μειώνεται ομαλά η τάση έως ότου φτάσει τα 0V.

τα προβλήματα που έχουμε είναι:

  1. τα arduino δεν έχουν μετατροπέα ψηφιακού σε αναλογικό.
  2. αν προσθέσουμε ή αν φτιάξουμε ένα D-to-A με αντιστάσεις και πάλι δεν μπορούμε να βγάλουμε 10V, μπορούμε να βγάλουμε έως 5 (-ακραία-)
  3. θα μπορούσαμε να διπλασιάσουμε την τάση με ένα τελεστικό ενισχυτή (OpAmp) με θετική ανάδραση και gain 2 αλλά είναι πολύπλοκη λύση και δημιουργεί άλλα θέματα όπως τροφοδοσίας του OpΑmp, κόστος, πολυπλοκότητα κατασκευής κ.α.

Βεβαίως το Arduino έχει μία συνάρτηση analogWrite() που όμως δίνει έξοδο Pulse Width Modulation και όχι αναλογική:
Το σήμα PWM μπορεί να γίνει εύκολα αναλογικό προσθέτοντας ένα low pass φίλτρο που απαρτίζεται από μία αντίσταση και ένα πυκνωτή, οι τιμές των οποίων μπορούν να υπολογιστούν με το εργαλείο που εμφανίζεται χαμηλά σε αυτό το λινκ.

Καλά όλα αυτά, στο δια ταύτα όμως:

Αυτό που έκανα εγώ (και που είναι τόσο απλό που σίγουρα θα έχει ξαναγίνει αλλά δεν μπόρεσα να το βρω στο google και για αυτό γράφω αυτό εδώ...) είναι αντί να κάνω το PWM σήμα αναλογικό και μετά να το ενισχύσω για να πάρει τιμές από 0 έως 10V, ή να δοκιμάσω να ελέγξω ένα variable voltage regulator, αυτό που έκανα είναι να μετασχηματίσω το πλάτος του PWM σήματος από 0-5V σε 0-10V και μετά να κάνω το σήμα αναλογικό χρησιμοποιώντας ένα φίλτρο RC.

Επίσης, επειδή για λόγους απλότητας με βόλευε να αντιστρέψω το σήμα, κάνω αντιστροφή της τιμής του PWM σε επίπεδο λογισμικού, με χρήση του τελεστή ~ (bitwise NOT). Ή απλούστερα, λέω ότι το νούμερο 255 αντιστοιχεί σε 0V και το  νούμερο 0 αντιστοιχεί σε 10V με όλα τα ενδιάμεσα να μοιράζονται ομαλά. 
Αν σε κάποια άλλη εφαρμογή αυτό δεν παίζει, τότε μπορεί να μπει ένα δεύτερο transistor που θα κάνει μία ακόμα αντιστροφή επαναφέροντας το PWM στην αρχική του μορφή.
Στην εφαρμογή που περιγράφω δεν μας πειράζει αν είναι ανάποδα το PWM, το ελέγχουμε από το software.

Οπότε:

το κύκλωμα είναι αυτό:



Τροφοδοτείται από 12VDC, και το arduino παίρνει ρεύμα από το RAW. To τρανσιστορ είναι ένα BC547 (ξέχασα να το σημειώσω στο χαρτί).

Η υλοποίηση σε breadboard είναι αυτή:


έχω χρησιμοποιήσει ένα Arduino Pro Mini που προγραμματίζεται μέσω σειριακής πόρτας, η πορτοκαλί πλακετίτσα που φαίνεται αριστερά του arduino είναι για τον προγραμματισμό/debugging και μετά αφαιρείται.

Ακολουθούν δύο βίντεο. Και στα δύο τρέχω μία διαδικασία Sunrize/Sunset, δηλαδή ξεκινώ από την κατάσταση που δίνει έξοδο 0 Volt, πάω στο max και μετά ξανακατεβαίνω σταδιακά στα 0V.

Στο πρώτο φαίνεται τα σήματα PWM όπως βγαίνουν από το arduino (κίτρινο) και από το transistor (μπλε), έχοντας συνδέσει τον παλμογράφο στα σημεία Α & Β αντίστοιχα:
Το ύψος του παλμού είναι ανάλογο της τάσης του και βλέπουμε το σήμα στο Α (κίτρινο) να έχει πλάτος 5V ενώ το σήμα στο Β έχει 11.2V.

Στο δεύτερο βίντεο φαίνεται η μεταβολή της τάσης (Μπλε, σημείο C) καθώς αλλάζει το duty cycle του σήματος PWM στο σημείο B (κίτρινο).

Η μέγιστη τάση που βγάζει το σύστημα είναι η τάση τροφοδοσίας μειωμένη κατά ~ 0.7V.
Αν η μέγιστη τάση που χρειαζόμαστε είναι μικρότερη, τότε μπορούμε να μην φτάσουμε στο 100% duty cycle αλλά να σταματήσουμε πχ στο 90%.
με αυτό τον τρόπο ακόμα και αν το σύστημα μπορεί να βγάλει 11.2V, για εμάς η μέγιστη έξοδος θα είναι 10V.

O κώδικας που χρησιμοποιήθηκε είναι αυτός:

char  fromConsole;
int   i,j;
void setup() {
  // put your setup code here, to run once:
  analogWrite(10, 255);
  Serial.begin(9600);
  delay(1000);
  sunRize();
  sunSet();
}
void sunRize(){
      for (i=16;i>=0;i--){
      j=i*16; if (j<0) j=0; if (j>255) j=255;
      analogWrite(10, j);
      Serial.println(j);
      delay (500);
    }
}
void sunSet(){
    for (i=0;i<=16;i++){
      j=i*16; if (j<0) j=0; if (j>255) j=255;
      analogWrite(10, j);
      Serial.println(j);
      delay (500);
    }
}
void loop() {
  //check if a character on serial
  if (Serial.available()) {
    fromConsole=Serial.read();
    switch (fromConsole) {
      case '0':
        Serial.println("I received 0, setting PWD to 255, ie output 1:");
        analogWrite(10, 255);
        break;
      case '1':
        Serial.println("I received 1, setting PWD to 192, ie output to 1/4:");
        analogWrite(10, 192);
        break;
      case '2':
        Serial.println("I received 2, setting PWD to 128, ie output to 2/4:");
        analogWrite(10, 128);
        break;
      case '3':
        Serial.println("I received 3, setting PWD to 64, ie output to 3/4:");
        analogWrite(10, 64);
        break;
      case '4':
        Serial.println("I received 4, setting PWD to 0, ie output to 4/4:");
        analogWrite(10, 0);
        break;
      case '5':
        Serial.println("I received 5, doing a sunrize sequence");
        sunRize();
        break;
      case '6':
        Serial.println("I received 6, doing a sunset sequence");
        sunSet();
        break;
      default:
        Serial.println("Undefined button pressed");
        break;
      }
    }
  else {
    delay (500);
  }

}
Αυτά...
  








Sunday 3 January 2016

τηλεχειριστήριο τηλεόρασης με τα απολύτως απαραίτητα

Λοιποοοον....

βρέχει, κάνει κρύο, υπάρχει και λίγος επιπλέον χρόνος λόγω αργιών των ημερών (Πρωτοχρονιά 2016 έφτιαξα τα παρακάτω, 2 του μήνα που έγραψα αυτό το άρθρο, άντε και καλή χρονιά...), ευκαιρία για ένα μικρό και πρόχειρο "weekend project"!

Δεν ξέρω αν το έχετε προσέξει αλλά τα Remote Controls των τηλεοράσεων βρίσκονται να έχουν όλο και περισσότερα κουμπιά πάνω τους.
Κάποτε, ή είχαν τα άκρως απαραίτητα ή ήταν συνηθισμένο να είναι καλυμμένα τα κουμπιά που έδιναν "advanced" λειτουργικότητα τύπου προγραμματισμού καναλιών, teletext κλπ

Τώρα, ένα τυπικό Remote Control είναι έτσι:

Ίσως για τους νέους και για όποιον τα έχει συνηθίσει να είναι ΟΚ, αλλά για κάποιους μεγαλύτερους στην ηλικία (αν είστε πολύ νέοι σκεφτείτε πχ την γιαγιά σας...) όλα αυτά τα κουμπιά ίσως να είναι πρόβλημα.

πχ, για κάποιον που έχει μία γνώση από αεροπλάνα (πραγματική ή μέσω εξομοιωτών), αυτό το cockpit από ένα super cub φαίνεται πως έχει τα άκρως απαραίτητα

 αλλά για τον μέσο οδηγό αυτοκινήτου που έχει συνηθίσει να βλέπει ένα κοντέρ και άντε μία βελόνα που να δείχνει πόση βενζίνη έχει και μερικά ενδεικτικά λαμπάκια, η παραπάνω εικόνα είναι η επιτομή του χάους...

Το ίδιο συμβαίνει και με όσους που αυτό που θέλουν να κάνουν με το τηλεχειριστήριο είναι να πηγαίνουν πάνω/κάτω κανάλια, να αυξομειώνουν την ένταση της φωνής και -eventually- να κλείνουν την τηλεόραση.

Δηλαδή 5 λειτουργίες, 5 κουμπιά. Γιατί να έχουν μπροστά τους 50 κουμπιά????

Με αυτό το σκεπτικό είπα να δω αν είναι εύκολο να φτιάξω ένα απλό τηλεχειριστήριο.

Η ιδέα ήταν να βρω τους κωδικούς που αποστέλνονται όταν πατάω τα κουμπιά Κανάλι+/-, φωνή+/- και Σβήσιμο στο μεγάλο τηλεχειριστήριο της τηλεόρασης  και να φτιάξω μία μικρή συσκευή που να έχει μόνο 5 κουμπιά που όταν πατιούνται να στέλνεται ο αντίστοιχος κωδικός ώστε η τηλεόραση να μπορεί να δουλέψει σαν να πατιόνταν τα αντίστοιχα πλήκτρα στο μεγάλο τηλεχειριστήριο.

Σε πρώτη φάση λοιπόν έπρεπε να διαβάσω τι στέλνει το δικό μου τηλεχειριστήριο.

Για να το κάνω αυτό χρησιμοποίησα ένα δέκτη υπερύθρων με 3 pins, όπως φαίνεται εδώ:
Για να διαβάσω το κώδικα που στέλνεται όταν πατιέται ένα κουμπί, θα έπρεπε να γραφτεί ένα πρόγραμμα που να διαβάσει τις παλμοσειρές, να τις αποκωδικοποιήσει, κλπ κλπ

Ένα -πολύ βασικό- πλεονέκτημα του οικοσυστήματος "arduino" είναι πως έχει γραφτεί πολύ λογισμικό και όταν πας να φτιάξεις κάτι, μπορείς να χτίσεις πάνω σε δουλειά που έχουν κάνει κάποιο άλλοι πριν από εσένα.

Πχ, για την διαχείριση κωδικών υπέρυθρης επικοινωνίας έχουν γραφτεί πολλές βιβλιοθήκες πχ

Εγώ αποφάσισα να χρησιμοποιήσω την δεύτερη.
Συνέδεσα την έξοδο του δέκτη υπερύθρων στο pin 10 και έτρεξα το πρόγραμμα που έρχεται σαν παράδειγμα με την βιβλιοθήκη, το IRanalyze.

Οι παλμοσειρές που λαμβάνει ο δέκτης των υπερύθρων, στον παλμογράφο φαίνονται ως εξής:
(πλήκτρο P+)

(πλήκτρο P-)

Χονδρικά, θα μπορούσαμε να το σκεφτούμε κάτι σαν bar code ζωγραφισμένο στον χρόνο με υπέρυθρο φως (γουάου!)

Φορτώνοντας στο arduino το πρόγραμμα/παράδειγμα IRanalyze, πήρα και τα παρακάτω αποτελέσματα:
1. Πατώντας το κουμπί P+ (για μετάβαση στο επόμενο πρόγραμμα)
Αυτό που μας ενδιαφέρει είναι αυτά που έχω μαρκάρει:
το πρώτο είναι η κωδικοποίηση που χρησιμοποιεί ο κατασκευαστής. Στην προκειμένη περίπτωση είναι "RC5". Το δεύτερο είναι ο κωδικός που αντιστοιχεί σε αυτή την λειτουργία (εδώ 1060) και η τρίτη παράμετρος είναι το μήκος του κωδικού σε παλμούς (bits).
2. Πατώντας το πλήκτρο P- (=μετάβαση στο προηγούμενο μενού) τα στοιχεία που λαμβάνουμε έχουν ως εξής:
Το μόνο που αλλάζει είναι ο κωδικός που για την λειτουργία P- είναι 1061
Τρέχοντας την ανάλυση και για τα άλλα κουμπιά, κατέληξα στο εξής:

  1. Αύξηση της έντασης, πλήκτρο V+, κωδικός 1050
  2. Μείωση της έντασης, πλήκτρο V-, κωδικός 1051
  3. Μετάβαση στο επόμενο πρόγραμμα, πλήκτρο P+, κωδικός 1060
  4. Μετάβαση στο προηγούμενο πρόγραμμα, πλήκτρο P-, κωδικός 1061
  5. Άναμμα/Σβήσιμο, πλήκτρο "Power", κωδικός 104C
(σημείωση: οι παραπάνω κωδικοί είναι σε δεκαεξαδικό, που σημαίνει ότι το 104C είναι έγκυρος αριθμός και αντιστοιχεί σε δεκαδικό 4172)

ΟΚ, σε αυτή την φάση είχα τους κωδικούς, αυτό που χρειαζόμουν ήταν να βάλω 5 διακοπτάκια που να διαβάζονται από το arduino και να στέλνω με υπέρυθρο τον αντίστοιχο κωδικό όταν πατηθεί κάποιο πλήκτρο.

Για την αποστολή του κωδικού χρησιμοποίησα ένα υπέρυθρο LED. Για να έχω την μέγιστη απόδοση, το οδήγησα με ένα NPN transistor γενικής χρήσης, το BC547 ήταν υπέρ αρκετό, μέσω αυτού του κυκλώματος:

Το ρεύμα που περνά με αυτό τον τρόπο από το LED είναι λίγο εκτός προδιαγραφών αλλά λόγω του ότι περνάνε παλμοί πολύ μικρής διάρκειας, δεν υπάρχει πρόβλημα.

Αν λόγω κάποιου λάθους (στην σύνδεση ή στο πρόγραμμα) το led μείνει αναμμένο για πάνω από δευτερόλεπτο, τότε μπορεί και να καεί, οπότε λίγο προσοχή.

Το φως που παράγει το υπέρυθρο LED είναι προφανώς αόρατο στο ανθρώπινο μάτι. Για λόγους ελέγχου, θα μπορούσε είτε προσωρινά να αντικατασταθεί με ένα απλό LED (ώστε να μπορέσουμε να δούμε ότι "ψιλοανάβει" όταν πατάμε ένα κουμπί) ή να το δούμε μέσα από μία ψηφιακή φωτογραφική μηχανή που έχει ηλεκτρονικό "ματάκι". Τότε το υπέρυθρο φως παρουσιάζεται σαν ένα απαλό μωβ, και με αυτό τον τρόπο μπορούμε να δούμε ότι το σύστημα δουλεύει.

Για μπαταρία χρησιμοποίησα δύο λιθίου 3V ("κουμπιά") σε σειρά, πιασμένες με μονωτική ταινία. Αν είχα (που δεν είχα πρόχειρο) κάποιο arduino στα 3.3V τότε θα μπορούσα με μερικές αλλαγές να χρησιμοποιήσω μία μόνο μπαταρία.


Καθώς η τάση της (διπλής) μπαταρίας είναι κάτι παραπάνω από 6V, το Arduino τροφοδοτείται από την είσοδο "RAW".

Σε αυτή την φάση, το πρόγραμμα που πρέπει να χρησιμοποιηθεί είναι σαφές (θα το δούμε παρακάτω) και το hardware θα μπορούσε και αυτό να είναι απλό, σαν και αυτό που φαίνεται στο παρακάτω διάγραμμα:

Το πρόβλημα είναι πως αν φτιαχτεί έτσι, το σύστημα θα είναι πάντα αναμμένο (power on) και θα τρώει τις μπαταρίες σαν στραγάλια... άρα κάτι άλλο έπρεπε να γίνει.

Το πιο απλό θα ήταν να μπουν διπλά push buttons έτσι ώστε το πάτημα ενός πλήκτρου κλείνει δύο διακόπτες, ο ένας να δίνει ρεύμα στο arduino και ο άλλος να δείχνει ποιό κουμπί έχει πατηθεί:

σε αυτή την περίπτωση θα έπρεπε να αντιμετωπίσουμε κάποια θέματα:
  1. τα διακοπτάκια που είχα ήταν "μονά", οπότε δεν μπορούσα εύκολα να φτιάξω το παραπάνω
  2. ακόμα και αν μπορούσα να βρω "διπλά" διακοπτάκια, το κύκλωμα θα ήταν πιο πολύπλοκο και θα κόστιζε περισσότερο.
  3. δεν θα ήταν "elegant"
Οπότε έπρεπε να βρεθεί μία άλλη λύση.

Εδώ να αναφέρω και ένα άλλο θέμα που με απασχόλησε και αυτό είναι ο χρόνος εκκίνησης του Arduino ή πιο απλά ο χρόνος που απαιτείται για να "μπουτάρει" το arduino.

Το arduino είναι ένας (πολύ) μικρός ηλεκτρονικός υπολογιστής και όταν παίρνει ρεύμα, τρέχει ένα πρόγραμμα που είναι περασμένο στην μόνιμη μνήμη του, το bootloader. Αυτό μπορεί να δημιουργήσει μία καθυστέρηση μερικών δευτερολέπτων από την στιγμή που πάρει ρεύμα το σύστημα μέχρι την στιγμή που θα αρχίσει να τρέχει το πρόγραμμα που του έχουμε περάσει.
Προφανώς, μία τέτοια καθυστέρηση θα έκανε το τηλεχειριστήριο άχρηστο. 
Στα "πρώτης γενιάς" arduino ( Uno κλπ) η καθυστέρηση μπορεί να ήταν 6-10 δευτερόλεπτα. Δεν χρησιμοποίησα κάποιο τέτοιο αλλά ακόμα και αν χρησιμοποιούσα, θα μπορούσα να αλλάξω το bootloader με κάποιο άλλο ώστε να ξεκινάει γρήγορα.
Εγώ έτυχε να χρησιμοποιήσω ένα pro micro (το οποίο το βλέπω από το περιβάλλον προγραμματισμού σαν το μοντέλο "Arduino Leonardo"). 
Χρησιμοποιώ τέτοια ή και το ακόμα φτηνότερο αλλά ίδιων διαστάσεων pro mini γιατί 
  1. είναι μικρά 
  2. υπάρχουν στο ebay σε γελοιωδώς χαμηλές τιμές, πχ ένα pro mini μπορεί να κάνει 1 κάτι ευρώ (το pro micro είναι λίγο παραπάνω). 

Το μέγεθός τους φαίνεται στην παρακάτω φωτογραφία: 

Το Arduino Pro Micro λοιπόν, είχε χρόνο εκκίνησης (μετρημένο με τον παλμογράφο) 65ms που θεωρήθηκε πως δεν δημιουργεί πρόβλημα στην συγκεκριμένη χρήση, οπότε προχωράμε με το πλάνο, δηλαδή να μπουτάρει το σύστημα όταν πατιέται ένα πλήκτρο του τηλεχειριστηρίου καθώς με αυτόν τον τρόπο θα έχουμε την ελάχιστη δυνατή κατανάλωση ρεύματος.

Ομολογουμένως μου πήρε λίγη ώρα να βρω μία πιθανή λύση αλλά τελικά κατέληξα να χρησιμοποιήσω το παρακάτω:
Χρειάστηκαν 5 επιπλέον διοδάκια. Η ιδέα είναι ότι πατώντας ένα πλήκτρο το pin της εισόδου συνδέεται με κάτι σαν την γείωση, και το arduino παίρνει ρεύμα μέσω μίας διόδου που έχει σαν αποτέλεσμα να μην συνδέονται με το "σαν γείωση" τα υπόλοιπα pins....

OK, δουλεύει, είναι λίγο kludge-ώδες αλλά εμένα μου φαίνεται όμορφο, το πρόβλημα είναι ότι τα διοδάκια κάνουν μία πτώση τάσης που λόγω του λίγου ρεύματος είναι περίπου μισό Volt (αλλιώς θα ήταν 0,7V), που σημαίνει ότι το σήμα που πάει στα pins δεν είναι η γείωση (0 volt) αλλά μία ΑΡΝΗΤΙΚΗ τάση μισού volt... αυτό είναι στα όρια των προδιαγραφών (σελ. 383, Absolute Maximum Ratings, "Voltage on any Pin except RESET and VBUS with respect to Ground(8):-0.5V to VCC+0.5V")  και η κατάσταση θα μπορούσε να βελτιωθεί αν χρησιμοποιηθούν διοδάκια Schottky που έχουν πολύ μικρή πτώση τάσης (ονομαστική 0,2V αντί για 0,7V που έχει η 1Ν4148). Δυστυχώς εγώ είχα απλά πυριτίου 1N4148, θα ήταν σωστότερο να μπουν schottky πχ τύπου 1Ν5817

Αλλά για την ώρα και έτσι δουλεύει.

Οπότε συνεχίζουμε.

Το τελικό σχεδιάγραμμα ήταν αυτό:

Εδώ τελειώσαμε με το hardware.

To software που τρέχει το παραπάνω είναι αυτό:
#include <IRLib.h>
IRsend My_Sender;
void setup()
{
  int i;
  for (i=2;i<=6;i++){
    pinMode(i, INPUT);     //set pins 2-6 as inputs
    digitalWrite(i, HIGH); //and enable internal pull-up resistors
  }
}
void loop() {
    if (!digitalRead(2)){ // button P+
My_Sender.send(RC5,0x1060, 13);
      delay(300);
    } else if (!digitalRead(3)){ // button P-
        My_Sender.send(RC5,0x1061, 13);
      delay(300);
    } else if (!digitalRead(4)){ // button Vol-
        My_Sender.send(RC5,0x1051, 13);
      delay(100);
    } else if (!digitalRead(5)){ // button Vol+
        My_Sender.send(RC5,0x1050, 13);
      delay(100);
    } else if (!digitalRead(6)){ // button ON/OFF
        My_Sender.send(RC5,0x104C, 13);
      delay(400);
    }
}
Τα πράγματα που πρέπει να ειπωθούν για το πρόγραμμα είναι τα εξής:
  1. η πολυπλοκότητα εμπεριέχεται στην βιβλιοθήκη IRLib στην οποία ορίζεται το αντικείμενο IRsend. Εμείς δεν είμαστε εκτεθειμένοι σε αυτή την πολυπλοκότητα λόγω του ότι χρησιμοποιούμε το οικοσύστημα Arduino. Αν θέλαμε να το γράψουμε από την αρχή κατευθείαν σε κάποιο microcontroller, θα χρειαζόταν πολύ παραπάνω χρόνος και γνώση.
  2. για να έχουμε το δυνατόν απλούστερο κύκλωμα, έχουν ενεργοποιηθεί oι εσωτερικές pull-up αντιστάσεις που έχει ο microcontroller που είναι η καρδιά του arduino. Οι pull-up αντιστάσεις χρειάζονται έτσι ώστε όταν το pin είναι στο αέρα, να εμφανίζεται σαν να είναι συνδεδεμένο στο Vcc και έτσι η συνάρτηση digitalRead(x) να επιστρέφει τιμή "true"
  3. έχω βάλει μία καθυστέρηση που μπαίνει όταν πατιέται ένα πλήκτρο και έχει να κάνει με τον ρυθμό επανάληψής του όταν κρατιέται πατημένο. Οι τιμές δόθηκαν κατόπιν δοκιμών.
Η κατασκευή σε breadboard έχει ως εξής:




τα μέρη έχουν αριθμηθεί ως εξής:
  1. τα διακοπτάκια. Κάπου εκεί γύρω είναι και τα διοδάκια, φαίνεται ένα στην πάνω αριστερή γωνία του breadboard. Στο prototype τα κουμπάκια τα πατάω με ένα στυλό γιατί αλλιώς υπάρχει κίνδυνος να ξηλώσω τα καλώδια!
  2. το arduino
  3. to transistor που οδηγεί το LED υπερύθρων
  4. το LED υπερύθρων που είπα πριν
  5. ο δέκτης των υπερύθρων που είχα αναφέρει στην αρχή, τον έχω αφήσει συνδεδεμένο, στο τελικό δεν χρειάζεται ή ενδεχομένως να χρειαστεί αν θέλουμε ο προγραμματισμός να γίνεται από τον τελικό χρήστη ("on the field") αλλά τότε θα πρέπει να αλλαχτεί το πρόγραμμα και ίσως να πρέπει να μπει ένας επιπλέον διακόπτης που θα ενεργοποιεί τον προγραμματισμό.
  6. η μπαταρία
όλο το παραπάνω θα μπορούσε να χωρέσει σε ένα κουτί μεγέθους κουτιού σπίρτων, αλλά θα ήταν πιο πρακτικό να έμπαινε σε κάτι μεγαλύτερο ώστε 1)να μην χάνεται εύκολα και 2)να μπορεί αν το χειριστεί κάποιος πιο εύκολα, το κουτί σπίρτων παραείναι μικρό.

Σκέφτηκα ότι θα μπορούσα να το προσαρμόσω σε ένα περίβλημα παλιού χαλασμένου ποντικιού και τότε ίσως να μπορούσα να χρησιμοποιήσω και τα microswitches που θα είχε πάνω το ποντίκι, πχ το δεξί/αριστερό κουμπί του ποντικιού θα μπορούσαν να αλλάζουν κανάλι ενώ το roller θα μπορούσε να ανεβοκατεβάζει την ένταση. κλπ

Το αφήνω σε κάποιον άλλο να φτιάξει το (5) που ανέφερα παραπάνω και ίσως να το βάλει σε κάποια συσκευασία που να επιτρέπει να χρησιμοποιηθεί κανονικά (σε κάποιο κουτί από τσιγάρα, από mouse ή κάποιο 3d printed ίσως???)


Ελπίζω το παραπάνω να σας φάνηκε χρήσιμο.
Ερωτήσεις/σχόλια κλπ mostly welcome.

BR,
GT

  







Saturday 30 November 2013

Pebble Programming: Greek Fuzzy Time Watchface

Hi there!

I got a Pebble smartwatch couple of weeks ago.

To my relief, it was all I thought it would have been. Slick, comfortable, and most of all, PROGRAMMABLE!

The SDK needed for programming the device, comes for free, you don't have to pay any subscription or license and programming is done in plain C (not C++, C#, Objective C and the likes). Programming in ANSI C has some air of nostalgia, it took me back 20+ years!

The PebbleOS itself is small and manageable, making it easy for novices to start tinkering.

The SDK comes with a few examples to help you get the grips of programming the Pebble, one of which is a "fuzzy clock" that tells the time in the way humans used to do when the clocks and watches had handles instead of digital displays.

Playing around, I changed it to tell the time in Greek, using latin characters (Greek fonts are not included and it takes a bit of playing around to make the Pebble work with non latin characters. That said, if you need to add non latin characters, you will find all the needed info in the official Pebble forum).
The greek fuzzy time facewatch is like this:
The greek fuzzy time watchface can be downloaded from here. This link includes the complete project along with the source code and binary.

If you want just the binary, you can get it here.
Just a word of caution though, it has been compiled using SDK 2.0 BETA 2, I don't know it it runs on Pebbles with previous version of firmware but if it doesn't, you can always compile it yourselves using the files of the first link.

The code itself is very simple and the bit that does the actual time conversion has as follows:

#include "string.h"
static const char* const HOURS[] ={
  "Dodeka",
  "Mia",
  "Dyo",
  "Tris",
  "Tesseris",
  "Pente",
  "Exi",
  "Efta",
  "Okto",
  "Ennia",
  "Deka",
  "Enteka"
  };
static const char* const MINUTES[] = {
  " akribos",
  " kai pente",
  " kai deka",
  " kai tetarto",
  " kai eikosi",
  " kai eikosipente",
  " kai misi",
  " para eikosipente",
  " para eikosi",
  " para tetarto",
  " para deka",
  " para pente"
};

static size_t append_string(char* buffer, const size_t length, const char* str) {
  strncat(buffer, str, length);
  size_t written = strlen(str);
  return (length > written) ? written : length;
}

void fuzzy_time_to_words(int hours, int minutes, char* words, size_t length) {
    int fuzzy_hours = hours;
    int fuzzy_minutes = ((minutes + 2) / 5);
    if (fuzzy_minutes ==12) { fuzzy_minutes =0; fuzzy_hours++;}
    if (fuzzy_minutes>6) {    //increase hour and use "para"
        fuzzy_hours++;
    }    
    if (fuzzy_hours>12){
        fuzzy_hours-=12;
    }
    size_t remaining = length;
    memset(words, 0, length);
    remaining -= append_string(words, remaining, HOURS[fuzzy_hours]);
    remaining -= append_string(words, remaining, MINUTES[fuzzy_minutes]);
}
In a coming post I will go through the process of adding greek fonts.

Thanks for reading,
G.


UPDATE:
Fixed a minor bug that produced wrong readings at x:58 and x:59. Correction is shown above in bold.

Downloadable archive and binary have also been fixed.