Ρομποτάκια R4 - δεν κινούνται!

Ξεκίνησε από mandarinos, 29 Απρ 2025, 09:46:02 ΠΜ

« προηγούμενο - επόμενο »

mandarinos

Τα ρομποτάκια R4 (υποτίθεται υλικό γιά διδασκαλία στο Γυμνάσιο), κατάφερε κανείς:

- να τα συναρμολογήσει;
- να τα κινήσει;

Ακολουθώντας πιστά τις οδηγίες του σχετικού εγχειριδίου, συναρμολόγησα ένα - υποθέτω επιτυχώς. (Το βλέπετε στη σχετική φωτογραφία.)
Έχετε υπ' όψη σας ότι το εγχειρίδιο έχει λάθη: (α) ένα πρωθύστερο, ότι δοκιμάζουμε τους σερβομηχανισμούς πρίν συνδέσουμε τον βραχίονα (!), και (β) ότι γιά τη σύνδεση του βραχίονα και των σερβομηχανισμών προτείνει κάτι πολύ λεπτές βιδούλες, οι οποίες όμως σπάνε! Ταυτόχρονα, περισσεύουν επίσης κάτι άλλες βιδούλες, λεπτές κι' αυτές, αλλά με "καπελλάκι". (Στο κίτ γενικώς περισσεύουν αρκετές βίδες.) Πιστεύω ότι αυτές είναι οι σωστές, αλλά δεν απεικονίζονται αυτές στα σχήματα των οδηγιών γιά συναρμολόγηση.

Πάμε, τώρα, στα δύσκολα.
- Η εφαρμογή που κινεί το ρομποτάκι, δεν υπάρχει στο Google Play Store, αλλά την παίρνεις (ως αρχείο) με αλληλογραφία με την εταιρεία των ρομπότ, την PolyTech. (Όπως και όλα τα σχετικά εγχειρίδια του ρομπότ R4, καθώς και του κίτ με το Arduino.)
- Την περνάς στο κινητό (με καλώδιο USB - ίσως και μέσω BlueTooth, από φορητό που έχει τέτοια μονάδα), οκ.
- Στο κινητό, ενεργοποιείς το BlueTooth, καθώς και την τοποθεσία (location), οπότε μάλλον ενεργοποιείται αυτόματα και το Quick Share. (Αλλοιώς, με το χέρι.)

Κι εδώ, ...δεν γίνεται τίποτε!!!

Το BlueTooth όντως ανιχνεύει τη μονάδα BlueTooth του ρομπότ (είναι αυτή, με το χαρακτηριστικό BT24 - βλέπε φωτογραφία), αλλά το ρομπότ ούτε κουνάει, ούτε μιλάει, ούτε λαλάει! (Μου θυμίζει τη φράση του Ροΐδη, ότι "εν αντιθέσει προς τους κύνας, η γαλή είναι ανεπίδεκτος εντολών"! :)  )
(Υπ' όψιν, το BlueTooth ανιχνεύει κι άλλες μονάδες, πχ τους διαδραστικούς των διπλανών αιθουσών, ακόμη και smart watches που φοράνε οι μαθητές. Αλλά μόνο το BT24 μας ενδιαφέρει.)

Πάω, λοιπόν, στο ChatGPT (γιά να ξεπεράσω το αδιέξοδο), και μου προτείνει την εφαρμογή nRF Connect (free, υπάρχει στο Play Store), η οποία θεωρητικώς "κάνει παπάδες" με το BlueTooth. Τη φοράω κι αυτή στο κινητό, όντως δουλεύει - και πολύ καλύτερα απ' το σκέτο BlueTooth (όντως ...δημιουργεί ιερείς! :)  ), μέχρι και ένδειξη γιά τα ντεσιμπέλ του σήματος βγάζει, ανιχνεύει μερικές δεκάδες συσκευών, σου λέει ποιές είναι near (κοντά), οπότε (μετά την ενεργοποίησή της), ξεκινάω την εφαρμογή κινήσεων του ρομπότ (μπάς και)...

...αλλά πάλι τίποτε!!!

Και στο σημείο αυτό, κόλλησα.

Επειδή άρχισαν να περνάνε διάφορες περίεργες σκέψεις απ' το μυαλό μου (βρέ, μπάς και θέλει παρακάλια; τίποτε ξόρκια, ίσως; :)  ), σας ερωτώ, λοιπόν, καλοί μου άνθρωποι: κατάφερε κανείς να το κινήσει, το απαίσιο ρομποτάκι; Αν ναι, θα εκτιμήσω στον υπέρτατο βαθμό τις όποιες συμβουλές σας!

exanemou

Το συναρμολόγησα μεχρι τους βραχιονες.
Που βρίσκω τους οδηγούς για το R4;

mandarinos

#2
Στέλνεις email στην εταιρεία που τα προμήθευσε (PolyTech, έχει στοιχεία επικοινωνίας επάνω στα χαρτόνια των κίτς), τους λές τί ζητάς, και σου στέλνουν έναν σύνδεσμο γιά το δικό τους drive στη Google. Απ' όπου κατεβάζεις ένα τεράστιο πακέτο από επεξηγηματικά φιλμάκια, εγχειρίδια, την εφαρμογή που κινεί το ρομπότ (γιά Android), και προγράμματα γιά το Arduino. (Αυστηρά γιά "drivers" -όπως τους εννοούμε στα ΛΣ- δεν θα το έλεγα, αλλά δές παρακάτω.)

Τώρα, εκείνο που θέλει, είναι πρώτα να του περάσεις του ρομπότ ένα πρόγραμμα γιά το Arduino Uno (μέσω USB). (Με αφαιρεμένη τη μονάδα BlueTooth και τον διακόπτη λειτουργίας σε off.) Το οποίο πρόγραμμα ρυθμίζει ποιές ακίδες αντιστοιχούν σε ποιόν σερβομηχανισμό, το baud rate του BlueTooth, κλπ.
Μετά, το αποσυνδέεις από το USB, ξαναβάζεις τη μονάδα BlueTooth (BT24 λέγεται, μπλέξιμο κι εδώ με το πρωτόκολλο του BlueTooth, υποστηρίζει το BLE, αλλά όχι το παλιότερο HC_05, λέει...), το βάζεις μπρός, και -όντως- δέχεται εντολές από το πρόγραμμα χειρισμού στο κινητό ή στο tablet.

Ωστόσο, προσωπικά δεν βρήκα άκρη ποιό πρόγραμμα να περάσω, γι' αυτό δεν έγραψα ακόμη τίποτε εδώ. Δύο ΤΝ (ChatGPT και Grok) μου απάντησαν με έτοιμο πρόγραμμα, ωστόσο με συμβούλευσαν να κάνω δοκιμές (που πάντα τις κάνω), διότι δεν είναι σίγουρες γιά την αντιστοιχία των ακίδων.
Δεν ξέρω αν λέει το εγχειρίδιο κάτι, δεν το κοίταξα ακόμη - πλήν του προγράμματος δοκιμής μετά τη συναρμολόγηση (που το παραθέτει το εγχειρίδιο), που όντως δουλεύει όπως λέει.

Το πρόγραμμα της ChatGPT (που πρόλαβα και το δοκίμασα) κάνει το εξής παλαβό: ό,τι και να πατάω (στην εφαρμογή του κινητού) από τα βελάκια της κίνησης, ενεργοποιείται ο σερβομηχανισμός "αριστερά-δεξιά" της δαγκάνας! Οι δέ ρόδες, ασυγκίνητες!

Μπλέξιμο!... Και να πείς δεν ξέρω τί μου γίνεται, να μή μπορώ να συνδέσω τους κοννέκτορες στη σωστή θέση; :)  Απλά, συνεχίζω τις δοκιμές.

Αν κάποιος θέλει να δοκιμάσει αλλάζοντας τις παραμέτρους, σας ανεβάζω εδώ το πρόγραμμα στο επόμενο post.

Υγ 1: Δεν χρειάζεται απαραίτητα το nRF Connect. Δουλειά γίνεται και με τη λειτουργία σύνδεσης BlueTooth που έχει το ίδιο το κινητό τηλέφωνο.)
Υγ 2: Ά, συγνώμη, έχει όντως ένα πακέτο drivers γιά Ms-Windows, το οποίο παραλαμβάνεις από το drive, μαζί με τα υπόλοιπα αρχεία. Δεν ξέρω σε τί χρησιμεύει, διότι με τα Ακατονόμαστα έχω πάρει διαζύγιο! :)

mandarinos

Πρόγραμμα από την ChatGPT (με επιφύλαξη - δεν δουλεύει, θέλει αλλαγές παραμέτρων· όποιος ξέρει, τις κάνει και μας ενημερώνει) :

#include <Servo.h>

// Create servo objects
Servo leftFront;
Servo leftRear;
Servo rightFront;
Servo rightRear;

// Define pins (change if needed)
const int LF_PIN = 3;  // PM1
const int LR_PIN = 5;  // PM2
const int RF_PIN = 6;  // PM3
const int RR_PIN = 9;  // PM4

void setup() {
  Serial.begin(9600);

  // Attach servos
  leftFront.attach(LF_PIN);
  leftRear.attach(LR_PIN);
  rightFront.attach(RF_PIN);
  rightRear.attach(RR_PIN);
}

void loop() {
  if (Serial.available()) {
    char command = Serial.read();
    handleCommand(command);
  }
}

void handleCommand(char cmd) {
  switch (cmd) {
    case 'F': // Forward
      setAll(180, 0);
      break;
    case 'B': // Backward
      setAll(0, 180);
      break;
    case 'L': // Turn left
      setAll(0, 0);
      break;
    case 'R': // Turn right
      setAll(180, 180);
      break;
    case 'S': // Stop
      setAll(90, 90);
      break;
  }
}

// Set speed for left and right side
void setAll(int leftSpeed, int rightSpeed) {
  leftFront.write(leftSpeed);
  leftRear.write(leftSpeed);
  rightFront.write(rightSpeed);
  rightRear.write(rightSpeed);
}

mandarinos

Αυτό το πρόγραμμα γιά Arduino Uno γιά δοκιμή, που ανέφερα, είναι ένα που λέγεται R4_Servo_Setup.ino . Υπάρχει μέσα στο πακέτο αρχείων. Όπου έχει κι ένα ακόμη, το: R4_Final_ardicon.ino ...

...το οποίο ίσως είναι αυτό που ψάχνω, και λόγω αμέλειας καθυστέρησα βλακωδώς να βρω την άκρη! (Το πρόγραμμα δοκιμών το έκανα copy-paste από το εγχειρίδιο, σελίδες 52-53 του .pdf . Δεν έψαξα τα directories των αρχείων που παρέλαβα.)

Καλή τύχη στις δοκιμές! (Εγώ θα κάνω από Δευτέρα.)

Foto

Επειδή έχω δουλέψει με άλλες κατασκευές με arduino, τα προβλήματα είναι συνήθως δυο:
1. Δεν υπάρχει η σωστή βιβλιοθήκη για το εξαρτημα πχ το servo, επειδή αλλάξανε τσιπάκια.
2. Τα τσιπάκια συνδέονται με κάποιο interface πχ το SPI. και ανάλογα με το πως συνδέονται ρεύματα στα ποδαράκια του τσιπ, προκύπτει ο αριθμός του, που πρέπει να μπει στο πρόγραμμα. Έτσι βρίσκει το εξάρτημα ο οδηγός του. Έτσι μπορούν να υπάρχουν δύο ή περισσότερα εξαρτήματα.

Άρα ας γίνει έλεγχος για αυτα τα δύο κσι μετά βλέπουμε.
Υπάρχει δε και πρόγραμμα scan που το φορτώνουμε και μας λέει ποιες πόρτες έχουν κάτι, δηλαδή ποιοι αριθμοί δουλεύουν στη συγκεκριμένη σύυνδεσμολογία. Αυτού του είδους τα προγράμματα βρίσκονται στα παραδείγματα, τα έχει δηλαδή το IDE του arduino.

mandarinos

#6
Λοιπόν. Το πρόγραμμα που το κινεί, είναι όντως το R4_Final_ardicon.ino .

Μόνο που θα χτυπήσει ο compiler (και μόλις στη δεύτερη γραμμή προγράμματος), αν πάτε να το περάσετε έτσι, ως έχει. Χρειάζεται πρώτα να εγκαταστήσετε μιά συγκεκριμένη βιβλιοθήκη.

Στο Arduino IDE, ανοίγετε: Tools / Manage Libraries, και στη μπάρα εισόδου κειμένου σημειώνετε:

Adafruit PWM Servo Driver

Τη βρίσκει, την εγκαθιστάτε, και κάνετε επανεκκίνηση της εφαρμογής. Μετά, compilation και ταυτόχρονο πέρασμα του προγράμματος στο ρομποτάκι μέσω καλωδίου USB, κατά τα γνωστά. (Διακόπτης λειτουργίας του ρομπότ στο off, μονάδα BlueTooth βγαλμένη.) Θα δουλέψει - τουλάχιστον στα περισσότερα! (Η δαγκάνα δουλεύει οκ.)

...........................

Διότι παραμένει ένα τελευταίο προβληματάκι: όταν δίνω εντολή να στρίψει, όντως στρίβει. Αλλά δεν υπακούει στην κίνηση μπρός-πίσω. Οι τροχοί (με την εντολή μέσα από την εφαρμογή) φαίνεται πως όντως πάνε να κινηθούν, αλλά σταματάνε επί τόπου.
Πού θα πάει, όμως; θα το λύσω κι αυτό, παρεκτός αν με προλάβετε!

...........................

Παραθέτω εδώ το πρόγραμμα λειτουργίας, γιά να μην ψάχνετε στα αμέτρητα συνοδευτικά αρχεία. Ένα copy / paste, και είσαστε εντάξει.

Καλή διασκέδαση με το ρομπότ!

/*
 Λειτουργία Έξυπνου αυτοκίνητου με την εφαρμογή ARDicon.
 Έξυπνο αυτοκίνητο ελέγχου ρομποτικού βραχίονα.
*/
#include <Wire.h>
#include <Adafruit_PWMServoDriver.h>
Adafruit_PWMServoDriver pwm = Adafruit_PWMServoDriver(0x47);
#include <Servo.h>
//#include <IRremote.h>
//int RECV_PIN = A0;
int echoPin = 13;  // Ορισμός μονάδα υπερήχων ECHO στο D13
int trigPin = 12;  // Ορισμός μονάδα υπερήχων TRIG στο D12

#define IR_Go 70
#define IR_Back 21
#define IR_Left 68
#define IR_Right 67
#define IR_Stop 64

#define SensorLeft 6    // καρφίτσα εισαγωγής του αριστερού αισθητήρα
#define SensorMiddle 7  // καρφίτσα εισαγωγής του μεσαίου αισθητήρα
#define SensorRight 8  // καρφίτσα εισαγωγής του δεξιού αισθητήρα
unsigned char SL;      // κατάσταση αριστερού αισθητήρα
unsigned char SM;      // κατάσταση μεσαίου αισθητήρα
unsigned char SR;      // κατάσταση δεξιού αισθητήρα

Servo myservo1;
Servo myservo2;
Servo myservo3;

int k1 = 80, k2 = 120, k3 = 90;  // αρχικοποίηση της τιμής γωνίας των σερβομηχανισμών
int M1[20], M2[20], M3[20];
int i = 0, j = 0, t = 0, speed = 1500, turnSpeed = 2000;
char blue_val;

void setup() {
  Serial.begin(9600);  //set baud rate to 9600
  pwm.begin();
  pwm.setPWMFreq(60);
  myservo1.attach(11);
  myservo2.attach(10);
  myservo3.attach(9);
  myservo1.write(k1);
  delay(1000);
  myservo3.write(k3);
  delay(1000);
  pinMode(trigPin, OUTPUT);
  pinMode(echoPin, INPUT);
  pinMode(SensorLeft, INPUT);
  pinMode(SensorMiddle, INPUT);
  pinMode(SensorRight, INPUT);
  stop();
  //IrReceiver.begin(RECV_PIN);  // ενεργοποίηση του δέκτη IR
}

void loop() {
  if (Serial.available() > 0) {  // Λήψη σημάτων Bluetooth
    blue_val = Serial.read();
    Serial.println(blue_val);
    switch (blue_val) {
      case 'F': advance(); break;  // Αν λάβει εντολή 'F', κάνει κίνηση μπροστά

      case 'B': back(); break;  // Αν λάβει εντολή 'B', κάνει κίνηση πίσω

      case 'L': turnL(); break;  // Αν λάβει εντολή 'L', στροφή αριστερά

      case 'R': turnR(); break;  // Αν λάβει εντολή 'R', στροφή δεξιά

      case 'S': stop(); break;  // Αν λάβει εντολή 'S', σταματάει

      case 'a': speeds_a(); break;  // Αν λάβει εντολή 'a', επιταχύνει

      case 'd': speeds_d(); break;  // Αν λάβει εντολή 'd', επιβραδύνει

      case 'f': servo2up(); break;  // // Ο βραχίονας ανυψώνεται

      case 'b': servo2down(); break;  // // Ο βραχίονας χαμηλώνει

      case 'l': servo3left(); break;  // Ο βραχίονας στρέφεται προς τα αριστερά

      case 'c': servo3center(); break;  // Ο βραχίονας παίρνει κεντρική θέση

      case 'r': servo3right(); break;  // Ο βραχίονας στρέφεται προς τα δεξιά

      case 'Q': servo1on(); break;  // Η δαγκάνα ανοίγει

      case 'E': servo1off(); break;  // Η δαγκάνα κλείνει

      case 't': read_servo(); break;  // Αν λάβει εντολή 't', καταγράφει κίνηση

      case 'i': do_servo(); break;  // Αν λάβει εντολή 'i', εκτελεί κίνηση

      case 'Y': avoid(); break;  // Αν λάβει εντολή 'Y' είσοδο στη λειτουργία αποφυγής εμποδίων

      case 'X': tracking(); break;  // Αν λάβει εντολή 'X' είσοδος σε λειτουργία παρακολούθησης γραμμής

      case 'U': follow(); break;  // Αν λάβει εντολή 'U' είσοδος στη λειτουργία παρακολούθησης υπερήχων
      case 'G': Fall(); break;  // Αν λάβει εντολή 'G' εισέλθει σε κατάσταση αντι-πτώσης
      default: break;
    }
  }
}

// Μέθοδοι κίνησης//

void advance()  // Κίνηση μπροστά
{
  pwm.setPWM(0, 0, speed);
  pwm.setPWM(1, 0, 0);
  pwm.setPWM(2, 0, speed);
  pwm.setPWM(3, 0, 0);
  pwm.setPWM(4, 0, speed);
  pwm.setPWM(5, 0, 0);
  pwm.setPWM(6, 0, speed);
  pwm.setPWM(7, 0, 0);
}

void turnR()  // Στροφή δεξιά
{
  pwm.setPWM(0, 0, turnSpeed);
  pwm.setPWM(1, 0, 0);
  pwm.setPWM(2, 0, turnSpeed);
  pwm.setPWM(3, 0, 0);
  pwm.setPWM(4, 0, 0);
  pwm.setPWM(5, 0, turnSpeed);
  pwm.setPWM(6, 0, 0);
  pwm.setPWM(7, 0, turnSpeed);
}

void turnL()  // Στροφή αριστερά
{
  pwm.setPWM(0, 0, 0);
  pwm.setPWM(1, 0, turnSpeed);
  pwm.setPWM(2, 0, 0);
  pwm.setPWM(3, 0, turnSpeed);
  pwm.setPWM(4, 0, turnSpeed);
  pwm.setPWM(5, 0, 0);
  pwm.setPWM(6, 0, turnSpeed);
  pwm.setPWM(7, 0, 0);
}

void stop()  // Σταματάει
{
  pwm.setPWM(0, 0, 0);
  pwm.setPWM(1, 0, 0);
  pwm.setPWM(2, 0, 0);
  pwm.setPWM(3, 0, 0);
  pwm.setPWM(4, 0, 0);
  pwm.setPWM(5, 0, 0);
  pwm.setPWM(6, 0, 0);
  pwm.setPWM(7, 0, 0);
}

void back()  // Κίνηση προς τα πίσω
{
  pwm.setPWM(0, 0, 0);
  pwm.setPWM(1, 0, speed);
  pwm.setPWM(2, 0, 0);
  pwm.setPWM(3, 0, speed);
  pwm.setPWM(4, 0, 0);
  pwm.setPWM(5, 0, speed);
  pwm.setPWM(6, 0, 0);
  pwm.setPWM(7, 0, speed);
}

//Μεθοδοι ελέγχου ταχύτητας//

//Επιτάχυνση
void speeds_a() {
 speed=1500;
}

//Επιβράδυνση
void speeds_d() {
  speed=750;
}

//Μέθοδοι ελέγχου βραχίωνα//
void servo1on() {  // Η δαγκάνα ανοίγει
  while (k1 != 20) {
    k1 -= 1;
    myservo1.write(k1);
    delay(5);
  }
}

void servo1off() {  // Η δαγκάνα κλείνει
  bool servo1off_flag = 1;
  while (k1 != 80) {
    k1 += 1;  // έλεγχος της ακρίβειας περιστροφής
    myservo1.write(k1);
    delay(5);  // έλεγχος της ταχύτητας περιστροφής του σερβο

  }
}

void servo2up() {  // ο ρομποτικός βραχίονας ανυψώνεται
  while (k2 != 120) {
    k2 += 1;  // έλεγχος της ακρίβειας περιστροφής
    myservo2.write(k2);
    delay(10);  // έλεγχος της ταχύτητας περιστροφής του σερβο
  
  }
}

void servo2down() {  // ο ρομποτικός βραχίονας χαμηλώνει
  while (k2 != 40) {
    k2 -= 1;  // έλεγχος της ακρίβειας περιστροφής
    myservo2.write(k2);
    delay(10);  // έλεγχος της ταχύτητας περιστροφής του σερβο
  
  }
}

void servo3left() {  // ο ρομποτικός βραχίονας στρέφεται αριστερόστροφα
  while (k3!=180) {
    k3 += 1;  // έλεγχος της ακρίβειας περιστροφής
    myservo3.write(k3);
    delay(10);  // έλεγχος της ταχύτητας περιστροφής του σερβο
  }
}

void servo3center() {  // ο ρομποτικός βραχίονας στέκεται στην κεντρική θέση 
  while (k3!=90) {
    if (k3 > 90) {
    k3 -= 1;
    }
    if (k3 < 90) 
    {k3 += 1;}
      // έλεγχος της ακρίβειας περιστροφής
    myservo3.write(k3);
    delay(10);  // έλεγχος της ταχύτητας περιστροφής του σερβο

  }
}

void servo3right() {  // ο ρομποτικός βραχίονας στρέφεται δεξιόστροφα

  while (k3!=10) {
    k3 -= 1;  // έλεγχος της ακρίβειας περιστροφής
    myservo3.write(k3);
    delay(10);  // έλεγχος της ταχύτητας περιστροφής του σερβο
  }
}

//Μεθόδοι Μνήμης//
void read_servo() {
  M1[i] = myservo1.read();  // αποθήκευση της τιμής της γωνίας των σερβομηχανισμών σε πίνακα
  delay(100);              // χρόνος καθυστέρησης για να αποθηκεύτεί η τιμή της γωνίας
  M2[i] = myservo2.read();
  delay(100);
  M3[i] = myservo3.read();
  delay(100);
  i++;    // i προσθέτει 1 κάθε φορά που αποθηκεύεται i
  j = i;  // ορίστε την τιμή του i στο j
  delay(200);
}

void do_servo() {
  i = 0;
  t = 1;
  k1 = myservo1.read();  // διαβάζει τις τιμές των γωνιών και τις θέτει στην ανάλογη μεταβλητή
  k2 = myservo2.read();
  k3 = myservo3.read();

  while (t) {
    for (int k = 0; k < j; k++) {  // επανάληψη j φορές
      if (k1 < M1[k]) {            // εάν η τρέχουσα τιμή γωνίας του σερβομηχανισμού 1 είναι μικρότερη από την τιμή του πίνακα 1
        while (k1 < M1[k]) {      // ο σερβομηχανισμός περιστρέφεται στη θέση όπου είναι αποθηκευμένος στον πίνακα
          myservo1.write(k1);      // servo 1 εκτελεί την κίνηση
          k1++;                    // K1 προσθέτει 1
          delay(10);              // καθυστέρηση για 10ms / έλεγχος της ταχύτητας περιστροφής του σερβομηχανισμού
        }
      } else {                // όταν η τιμή της γωνίας του σερβομηχανισμού 1 είναι μεγαλύτερη από την τιμή που έχει αποθηκευτεί στον πίνακα 1
        while (k1 > M1[k]) {  // ο σερβομηχανισμός περιστρέφεται στη θέση όπου είναι αποθηκευμένος στον πίνακα
          myservo1.write(k1);  // servo 1 εκτελεί την κίνηση
          k1--;                // k1 αφαιρεί 1
          delay(10);          // καθυστέρηση για 10ms / έλεγχος της ταχύτητας περιστροφής του σερβομηχανισμού
        }
      }
      // το ίδιο παρακάτω
      if (k2 < M2[k]) {
        while (k2 < M2[k]) {
          myservo2.write(k2);
          k2++;
          delay(10);
        }
      } else {
        while (k2 > M2[k]) {
          myservo2.write(k2);
          k2--;
          delay(10);
        }
      }

      if (k3 < M3[k]) {
        while (k3 < M3[k]) {
          myservo3.write(k3);
          k3++;
          delay(10);
        }
      } else {
        while (k3 > M3[k]) {
          myservo3.write(k3);
          k3--;
          delay(10);
        }
      }

      if (Serial.available() > 0) {  // για την έξοδο από τον βρόχο
        if (Serial.read() == 't') {  // λαμβάνει 'i' τότε 't'
          t = 0;                    // θέτει το 't' σε 0, έξοδος απο τον βρόχο
          break;
        }
      }
    }
  }
}

//Μεθοδος αποφυγής εμποδίων//

int Ultrasonic_Ranging() {
  digitalWrite(trigPin, LOW);
  delayMicroseconds(2);
  digitalWrite(trigPin, HIGH);
  delayMicroseconds(10);
  digitalWrite(trigPin, LOW);
  int distance = pulseIn(echoPin, HIGH);  // Ανάγνωση της διάρκειας των υψηλών επιπέδων
  distance = distance / 58;              // Μετατροπή του χρόνου παλμού σε απόσταση
  delay(50);
  return distance;
}

void avoid() {  //αυτόνομη κίνηση, αποφυγή εμποδίων με υπερήχους
  bool avoid_flag = 1;
  while (avoid_flag) {
    int distance = Ultrasonic_Ranging();
    Serial.print("distance=");
    Serial.println(distance);
    if (distance < 30) {    // υποθέτοντας ότι η μπροστινή απόσταση είναι μικρότερη από 30 cm
      if (distance < 15) {  // υποθέτοντας ότι η μπροστινή απόσταση είναι μικρότερη από 15 cm
        stop();
        delay(100);
        back();
        delay(300);
      } else {  // όταν 10 < απόσταση < 30, στροφή δεξιά
        stop();
        delay(100);
        turnR();
        delay(500);
      }
    } else {  // όταν η απόσταση > 30, κίνηση μπροστά
      advance();
    }
    blue_val = Serial.read();
    if (blue_val == 'S') {
      stop();
      avoid_flag = 0;
    }
  }
}

//Μέθοδος ακολούθησης γραμμής
void tracking(void) {
  bool tracking_flag = 1;
  while (tracking_flag) {
    SL = digitalRead(SensorLeft);
    SM = digitalRead(SensorMiddle);
    SR = digitalRead(SensorRight);
    if (SM == HIGH) {
      if (SL == LOW && SR == HIGH) {  // Αν ανιχνευτεί μαύρο στα δεξιά και λευκό στα αριστερά, στρίβει δεξιά
        turnR();
      } else if (SR == LOW && SL == HIGH) {  // αν ανιχνευτεί μαύρο στα αριστερά και λευκό στα δεξιά, στρίβει αριστερά
        turnL();
      } else {  // Αν ανιχνευτεί λευκό και στις δύο άκρες, κινείται ευθεία
        advance();
      }
    } else {
      if (SL == LOW && SR == HIGH) {  // Αν ανιχνευτεί μαύρο στα δεξιά και λευκό στα αριστερά, στρίβει δεξιά
        turnR();
      } else if (SR == LOW && SL == HIGH) {  // Αν ανιχνευτεί μαύρο στα αριστερά και λευκό στα δεξιά, στρίβει αριστερά
        turnL();
      } else {  // Αν όλοι οι σένσορες ανιχνεύουν λευκό, το αυτοκίνητο σταματάει
        stop();
      }
    }
    blue_val = Serial.read();
    if (blue_val == 'S') {
      stop();
      tracking_flag = 0;
    }
  }
}

//Μέθοδος αισθητήρα υπέρηχων
void follow() {
  bool follow_flag = 1;
  while (follow_flag) {
    int distance = Ultrasonic_Ranging();
    if (distance < 15) {  // Αν η απόσταση είναι μικρότερη απο 15 εκατοστά, κίνηση προς τα πίσω
      back();
    } else if (distance >= 15 && distance < 20) {  // Αν η απόσταση είναι μεταξύ 15 και 20 εκατοστά, σταμάτα
      stop();
    } else if (distance >= 20 && distance < 40) {  // Αν η απόσταση είναι μεταξύ 20 και 40 εκατοστά, κίνηση μπροστά
      advance();
    } else {
      stop();  // αλλιώς σταμάτα
    }
    blue_val = Serial.read();
    if (blue_val == 'S') {
      stop();
      follow_flag = 0;
    }
  }
}

//Μέθοδος αντι-πτώσης
void Fall(void) {
  bool Fall_flag = 1;
  while (Fall_flag) {
    SL = digitalRead(SensorLeft);
    SM = digitalRead(SensorMiddle);
    SR = digitalRead(SensorRight);
    if (SM == HIGH || SL == HIGH || SR == HIGH) {
      back();
      delay(500);
      turnL();
      delay(500);
    } else {
      advance();
    } 
    blue_val = Serial.read();
    if (blue_val == 'S') {
      stop();
      Fall_flag = 0;
    }
  }
}

mandarinos

Δεν ξέρω αν η εφαρμογή κίνησης του ρομπότ γιά Android συσκευές, η R4.bit.V2.1.apk, είναι copyrighted, γι' αυτό δεν την ανεβάζω εδώ ως επισυναπτόμενο. (Ώστε να μην ψάχνετε τα συνοδευτικά αρχεία.)

mandarinos

Λύθηκε (εν μέρει) και το μυστήριο με τους τροχούς! Όταν έδινα τις εντολές "μπρός" / "πίσω", το ένα ζευγάρι εκινείτο προς τη μία κατεύθυνση, και το άλλο στην αντίθετη! Γι' αυτό το ρομποτάκι δεν κουνιόταν, κι έμενε επί τόπου.

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


Εν πάσει περιπτώσει, μιά προσωρινή λύση είναι:

- Να βάλετε τους βραχυκυκλωτήρες (jumpers) ΟΧΙ όπως δείχνει το εγχειρίδιο, αλλά όπως στην επισυναπτόμενη φωτογραφία.
- Οι δέ συνδέσεις των τροχών (διπολικοί κοννέκτορες, καλώδια μαύρο-κόκκινο) πάνε ως εξής - βλέπουμε, σαν να οδηγούμε αυτοκίνητο:
        - Μπρός δεξιά, στη σύνδεση 4.
        - Μπρός αριστερά, στη σύνδεση 1.
        - Πίσω δεξιά, στη σύνδεση 3 (στη μέση).
        - Πίσω αριστερά, στη σύνδεση 2.

Το πίσω μέρος είναι εκεί, όπου βρίσκεται η μπαταριοθήκη. Η αρίθμηση των κοννέκτορς πάει: όπως βλέπουμε στη φωτογραφία, από αριστερά ο 1 και τέρμα δεξιά ο 5. (Ο 5 είναι γιά την τροφοδοσία από τις μπαταρίες.)

Με τη λύση αυτή, η κίνηση δουλεύει όπως πρέπει, αλλά κατοπτρικά: (Εννοώ, στα χειριστήρια της εφαρμογής στο κινητό.)
- Το "μπρός" γίνεται "πίσω", και το "πίσω" γίνεται "μπρός".
- Το "αριστερά" γίνεται "δεξιά", καί το "δεξιά" γίνεται "αριστερά".

Κάντε και τις δικές σας δοκιμές με τις συνδέσεις και τα jumpers, να δούμε πού βρίσκεται το απόλυτα σωστό.

Υγ: Μάλλον θέλουν κάποια αλλαγή και οι παράμετροι του προγράμματος του Arduino, διότι στις λοιπές λειτουργίες του προγράμματος στο κινητό, όπως αποφυγή εμποδίου, κλπ, φέρεται ανεξέλεγκτα. Στη δέ αποφυγή πτώσης, που το έβαλα επάνω στο γραφείο γιά δοκιμή, γκρεμοτσακίστηκε. (Αλλα -λόγω πείρας- περίμενα ως πιθανή μιά τέτοια δυσλειτουργία, κι έβαλα προκαταβολικά το χέρι μου από κάτω.)


mandarinos

#9
Μάλλον τελειώσαμε!

Συνδέστε τους σερβομηχανισμούς των εμπρός τροχών στους ακροδέκτες 2 και 3 (όπως φαίνεται η αρίθμηση σε προηγούμενη φωτογραφία, κι όπως εμφαίνεται στη σημερινή επισυναπτόμενη), και τους πίσω στους 1 και 4.
Τους συνέδεσα ως εξής:
- Πίσω δεξιά στον 4.
- Πίσω αριστερά στον 1.
- Εμπρός αριστερά στον 3.
- Εμπρός δεξιά στον 2.

(Τελικώς, δεν νομίζω ότι έχει σημασία αν πχ στην 1 είναι συνδεδεμένος ο πίσω αριστερά, ή ο πίσω δεξιά, διότι η διάταξη μου φαίνεται συμμετρική. Αλλά -αν τύχει να συνδέσετε "κουτουρού"- οπωσδήποτε δοκιμάστε τη σωστή λειτουργία.)

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

Από τις λειτουργίες της εφαρμογής που το καθοδηγεί, όποια έχει δοκιμαστεί και δουλεύει (εγγυημένα!) είναι σημειωμένη με τσεκάρισμα στη screen capture του κινητού μου.
Απομένουν μονάχα δύο. Δεν γνωρίζω ακόμη τί ακριβώς κάνουν, αλλά δοκιμάστε κι εσείς κάτι!

mandarinos

Η σωστά τσεκαρισμένη screen capture είναι η εδώ επισυναπτόμενη.

Αυτά που γράφει "επιτάχυνση" / "επιβράδυνση" δουλεύουν μέν, αλλά οι αλλαγές είναι σχεδόν μή παρατηρήσιμες.

exanemou

Παράθεση(β) ότι γιά τη σύνδεση του βραχίονα και των σερβομηχανισμών προτείνει κάτι πολύ λεπτές βιδούλες, οι οποίες όμως σπάνε! Ταυτόχρονα, περισσεύουν επίσης κάτι άλλες βιδούλες, λεπτές κι' αυτές, αλλά με "καπελλάκι"
καλησπέρα επειδή δυσκολεύομαι αφάνταστα στον βραχίονα να βιδώσω τις  Μ1,4 βίδες (δεν βιδώνουν καθόλου) μπορείς να γράψεις ποιές βίδες χρησιμοποίησες εναλλακτικά; Τις Μ1,2;
ευχαριστώ

mandarinos

Χρησιμοποίησα πάλι αυτές που σπάνε (όσες περίσσεψαν), αλλά με τρομερή προσοχή.

Αυτές είναι διαμέτρου μισού χιλιοστού, νομίζω. Αν υπάρχει πουθενά κανένα τρυπανάκι γιά ηλεκτρονικά, ανοίξτε τρύπες του ενός χιλιοστού, και βάλτες τις άλλες με το "καπελλάκι" - που είναι λιγάκι παχύτερες. (Αυτό θα έκανα εγώ.)

(Δυστυχώς, δεν έχω διαθέσιμο παχύμετρο.)


mandarinos

Απομένει ακόμη ένα θέμα με το ρομποτάκι R4: το καλιμπράρισμα του βραχίονα.

Συγκεκριμένα, όταν ανοίγεις τον διακόπτη τροφοδοσίας, ο βραχίονας κινείται σε τυχαίες θέσεις. Κανονικά, θα έπρεπε να πάει ακριβώς στη μέση, και να έχει περιθώριο ελευθερίας + - 90 μοίρες αριστερά-δεξιά.
Βέβαια, επειδή ο σερβομηχανισμός δεν ξέρει ποιά είναι η "θέση μηδέν", λογικά πρέπει να μπορούμε να την ορίσουμε εμείς - μιά κι έξω· δηλαδή, να περαστεί σε κάποια μόνιμη μνήμη.

Τα ίδια θα έλεγα και γιά την κίνηση πάνω-κάτω.

Δεν ξέρω τί φταίει, και δεν έχω βρεί ακόμη την άκρη. Πολύ, δέ, φοβάμαι, ότι θ' αργήσω να βρω απάντηση. Αν μπορεί κάποιος στο μεταξύ, ας μας πεί.

Υγ: Η κίνηση της δαγκάνας (ο τρίτος σερβομηχανισμός) δεν είναι πρόβλημα, αφού η δαγκάνα είναι δεσμοδρομική.