robotic microhandling con processing e arduino

Salve
voglio realizzare un braccio robotico per micromanipolazione di oggetti (da utilizzare assieme a un microscopio)
utilizzo 4 servi standard da modellismo 0-180° (HITEC HS311) movimenti avanti-indietro, up-down, destra-sinistra, get-release
Il primo prototipo utilizzava 8 pulsanti inseriti sulla breadboard per comandare di microstep i servi...funziona, ma...troppi cavi
Ora ho realizzato con processing una interfaccia grafica, ho caricato su arduino (UNO) la standard firmata
ma riesco a muovere i servi di microstep solo in senso orario con il comado arduino.analogWrite(servoPin3, 255);
non ruota in senso antiorario....qualcuno di voi ha fatto qualche progetto simile?
allego il codice di processing

//ROBOTIC MICROHANDLING
// Need G4P library download at 
// http://www.processing.org/reference/libraries/  
// Graphic Interface - G4P
// control servo on Arduino through GUI control
import processing.serial.*;
import cc.arduino.*;
import guicomponents.*;

PImage rear;

Arduino arduino; // Declare object (a variable of type arduino object)
//declare pin where servo are attached

int servoPin3  = 3;
int servoPin5  = 5;
int servoPin6  = 6;
int servoPin9  = 9;

// boolean variable coincident with the buttons
boolean up = true; 
boolean down = true;
boolean fast = true;
boolean slow = true;
boolean left = true;
boolean right = true;
boolean back = true;
boolean forward = true;
boolean release = true;
boolean take = true;  

void setup() {
  
  size(410, 607);
  rear = loadImage("realsteel.jpg");
  println(Arduino.list());
  //create a new arduino object and pass parameters( "this" refers to this sketch, name of serial port, speed)
  arduino = new Arduino(this, Arduino.list()[0], 57600);

  // attaches the servo on pin 3 to the servo object You need to set the mode of the pin that the servo is attached to, to SERVO
  arduino.pinMode(servoPin3, Arduino.SERVO);
  
  createGUI();
  customGUI();
  // Place your setup code here
}

void draw() {
  
  background(rear);
  if ( up ) {
  }
  else {

    println (" up è cambiato " + up );

    arduino.analogWrite(servoPin3, 255);

    /*
    arduino.digitalWrite(servoPin3, Arduino.HIGH);  //write a servo angle 180 to an output pin
     delay(1);
     arduino.digitalWrite(servoPin3, Arduino.LOW);
     delay(20);
     */

    up = true;
  }

  if ( down ) {
  }
  else {

    println (" down è cambiato " + down );
    // arduino.digitalWrite(servoPin3, Arduino.HIGH);  //write a servo angle 180 to an output pin
    //delay(time90);
    //arduino.digitalWrite(servoPin3, Arduino.LOW);
    // delay(20);
    down = true;
  }

  if ( fast ) {
  }
  else {

    println (" fast è cambiato " + fast );
    // arduino.digitalWrite(ledPin3, Arduino.HIGH);
    delay(1000);
    //arduino.digitalWrite(ledPin3, Arduino.LOW);
    fast = true;
  }

  if ( slow ) {
  }
  else {

    println (" slow è cambiato " + slow );
    // arduino.digitalWrite(ledPin4, Arduino.HIGH);
    delay(1000);
    // arduino.digitalWrite(ledPin4, Arduino.LOW);
    slow = true;
  }

  if ( left ) {
  }
  else {

    println (" left è cambiato " + left );
    // arduino.digitalWrite(ledPin5, Arduino.HIGH);
    delay(1000);
    // arduino.digitalWrite(ledPin5, Arduino.LOW);
    left = true;
  }

  if ( right ) {
  }
  else {

    println (" right è cambiato " + right );
    // arduino.digitalWrite(ledPin6, Arduino.HIGH);
    delay(1000);
    // arduino.digitalWrite(ledPin6, Arduino.LOW);
    right = true;
  }

  if ( back ) {
  }
  else {

    println (" back è cambiato " + back );
    // arduino.digitalWrite(ledPin7, Arduino.HIGH);
    delay(1000);
    // arduino.digitalWrite(ledPin7, Arduino.LOW);
    back = true;
  }

  if ( forward ) {
  }
  else {

    println (" forward è cambiato " + forward );
    // arduino.digitalWrite(ledPin8, Arduino.HIGH);
    delay(1000);
    //  arduino.digitalWrite(ledPin8, Arduino.LOW);
    forward = true;
  }

  if ( release ) {
  }
  else {

    println (" release è cambiato " + release );
    // arduino.digitalWrite(ledPin9, Arduino.HIGH);
    delay(1000);
    //  arduino.digitalWrite(ledPin9, Arduino.LOW);
    release = true;
  }

  if ( take ) {
  }
  else {

    println (" take è cambiato " + take );
    // arduino.digitalWrite(ledPin10, Arduino.HIGH);
    delay(1000);
    // arduino.digitalWrite(ledPin10, Arduino.LOW);
    take = true;
  }
}

// Use this method to add additional statements
// to customise the GUI controls
void customGUI() {
}

i servo non si pilotano con l'analogWrite ma con la libreria Servo.h, maggiori info nel reference

Salve
si lato arduino carico lo StandardFirmata oppure StandardFirmata_2_2_forUNO
entrambi includono #include <Servo.h> la libreria servo per arduino e quindi i servi su arduino sono gestiti bene
Lato Processing esiste solo la libreria arduino che dichiaro con (vedere anche il mio codice processing sopra)
import processing.serial.; // aggiunta comunque per dire a processing di gestire la seriale
import cc.arduino.
; // questa gestisce arduino
creo una variabile oggetto Arduino arduino;
e poi in setup() costruisco un nuovo oggetto Arduino
arduino = new Arduino(this, Arduino.list()[0], 57600);
successivamente i pin su cui sono collegati i servi vanno dichiarati con
arduino.pinMode(servoPin3, Arduino.SERVO); // al posto di OUTPUT va messo SERVO
La parte più difficile viene ora
in void draw() che in processing è l’analogo di void loop() per arduino
devo passare i comandi
Se utilizzo l’esempio di processing arduino_pwm

import processing.serial.*;

import cc.arduino.*;

Arduino arduino;

void setup() {
  size(512, 200);
  arduino = new Arduino(this, Arduino.list()[0], 57600);
}

void draw() {
  background(constrain(mouseX / 2, 0, 255));
  arduino.analogWrite(9, constrain(mouseX / 2, 0, 255));
  arduino.analogWrite(11, constrain(255 - mouseX / 2, 0, 255));
}

questo funziona…muove il servo a seconda di come muovo il mouse nella schermata size(512, 200); creata da processing
mouse a sinistra e il servo ruota a sinistra e analogamente a destra
Quindi per muovere il servo a destra ho scritto
arduino.analogWrite(servoPin3, 255);
e si muove di step a destra ogni volta che premo il pulsante sulla GUI
Ma per muoverlo a sinistra??
arduino.analogWrite(servoPin3, 0); rimane fermo
Qualche suggerimento?

se scrivi 0, il servo torna all'angolo 0° e ci rimane. se scrivi 255, dovrebbe andare all'angolo 180° e rimanerci.
quindi normalmente tu vorrai tenere il servo a 90°, ovvero 128, e poi in base a QUANTO vuoi muoverti a destra o a sinistra dai il numero.ù

Quindi quel valore è la POSIZIONE, non la velocità e direzione di rotazione.

magari ma temo non sia cosi…stò facendo delle prove ora
appena avvio l’applicazione di processing il servo va nella posizione centrale a 90°
se provo a forzarlo a mano per spostarlo non si muove da questa posizione centrale 90° quindi
ne presumo che la
arduino.pinMode(servoPin3, Arduino.SERVO);
invia correttamente alla StandardFirmata su arduino il comando di fermo
Ora… comando processing
arduino.analogWrite(servoPin3, 255);
alla prima volta che premo il pulsante sulla GUI non fa nulla al successivo che premo
muove di uno step a destra il servo ogni volta che premo il pulsante sulla GUI di processing
arduino.analogWrite(servoPin3, 0);
ruota a destra di un angolo circa 10°
arduino.analogWrite(servoPin3, 128);
ruota a sinistra a volte di pochi gradi a volte di circa 90° dopodichè si sente un ronzio come se fosse sempre alimentato
Il GND alimentazione servo (batteria 6V ) è comune al GND arduino

Come non detto… hai ragione…ora ho provato la ServoFirmata (la mia ver. è 0022)
su processing
arduino.analogWrite(servoPin3, 180);
il servo ruota a destra 180° (rimane fermo ma emette un ronzio)
se scrivo
arduino.analogWrite(servoPin3, 178);
il servo ruota a destra 180°(fermo e nessun ronzio)
arduino.analogWrite(servoPin3, 0);
il servo ruota a sinistra 0° (fermo e nessun ronzio)
arduino.analogWrite(servoPin3, 90);
il servo si muove nella posizione centrale 90°(fermo e nessun ronzio)
continuo a far prove ora devo capire come fargli fare piccoli step
Consiglio per chi volesse usare processing, arduino e servo usate ServoFirmata
StandarFirmata include la
#include <Servo.h>
ma non mi pare risponda bene come la ServoFirmata

Risolto!!
allego sotto il codice di processing per controllare il o i servi da processing usando la ServoFirmata su arduino spero possa tornare utile a qualcuno
(forse dovrei tradurlo in inglese perchè anche nel forum international mi pare brancolano nel buio)
come controprova o riprovato la StandardFirmata nulla per i servi non va bene

Ora domanda se nel ServoFirmata cambio “int value” con “float value” per passare al servo servos[PIN_TO_SERVO(pin)].write(value);
step più piccoli tipo 90.4 - 90.5 ecc. può funzionare o la libreria <Servo.h> di arduino ammette solo valori interi?
Grazie a tutti!!

allego il codice di processing

// goes from 0 degrees to 90 degrees and 90 to 180
// Need G4P library download at 
// http://www.processing.org/reference/libraries/  
// Graphic Interface - G4P
// control servo on Arduino through GUI control
import processing.serial.*;
import cc.arduino.*;
import guicomponents.*;

PImage rear;

Arduino arduino; // Declare object (a variable of type arduino object)
//declare pin where servo are attached
int pos = 90; // store position value

int servoPin3  = 3;
int servoPin5  = 5;
int servoPin6  = 6;
int servoPin9  = 9;

// boolean variable coincident with the buttons
boolean up = true; 
boolean down = true;
boolean fast = true;
boolean slow = true;
boolean left = true;
boolean right = true;
boolean back = true;
boolean forward = true;
boolean release = true;
boolean take = true;  

void setup() {
  //size(410, 380);
  size(410, 607);
  rear = loadImage("realsteel.jpg");
  println(Arduino.list());
  //create a new arduino object and pass parameters( "this" refers to this sketch, name of serial port, speed)
  arduino = new Arduino(this, Arduino.list()[0], 57600);

  // attaches the servo on pin 3 to the servo object You need to set the mode of the pin that the servo is attached to, to SERVO
  arduino.pinMode(servoPin3, Arduino.SERVO);
  // attaches the servo on pin 5 to the servo object 
  //arduino.servoAttach(servoPin5);

  createGUI();
  customGUI();
  // Place your setup code here
}

void draw() {
  // background(200, 220, 200);
  background(rear);
  if ( up ) {
  }
  else {

    println (" up è cambiato " + up );

    for (pos = 90; pos >=1; pos-=1) {    // goes from 90 degrees to 0 degrees
      // in steps of 1 degree 
      arduino.analogWrite(servoPin3, pos);
      delay(50);
    }

    up = true;
  }

  if ( down ) {
  }
  else {

    println (" down è cambiato " + down );
    
    for (pos = 0; pos < 90; pos += 1) {    // goes from 0 degrees to 90 degrees
      // in steps of 1 degree 
      arduino.analogWrite(servoPin3, pos);
      delay(50);
    }
    down = true;
  }

  if ( fast ) {
  }
  else {

    println (" fast è cambiato " + fast );
     for (pos = 90; pos < 180; pos += 1) {    // goes from 90 degrees to 180 degrees
      // in steps of 1 degree 
      arduino.analogWrite(servoPin3, pos);
      delay(50);
    }
    fast = true;
  }

  if ( slow ) {
  }
  else {

    println (" slow è cambiato " + slow );
    // arduino.digitalWrite(ledPin4, Arduino.HIGH);
    delay(1000);
    // arduino.digitalWrite(ledPin4, Arduino.LOW);
    slow = true;
  }

  if ( left ) {
  }
  else {

    println (" left è cambiato " + left );
    // arduino.digitalWrite(ledPin5, Arduino.HIGH);
    delay(1000);
    // arduino.digitalWrite(ledPin5, Arduino.LOW);
    left = true;
  }

  if ( right ) {
  }
  else {

    println (" right è cambiato " + right );
    // arduino.digitalWrite(ledPin6, Arduino.HIGH);
    delay(1000);
    // arduino.digitalWrite(ledPin6, Arduino.LOW);
    right = true;
  }

  if ( back ) {
  }
  else {

    println (" back è cambiato " + back );
    // arduino.digitalWrite(ledPin7, Arduino.HIGH);
    delay(1000);
    // arduino.digitalWrite(ledPin7, Arduino.LOW);
    back = true;
  }

  if ( forward ) {
  }
  else {

    println (" forward è cambiato " + forward );
    // arduino.digitalWrite(ledPin8, Arduino.HIGH);
    delay(1000);
    //  arduino.digitalWrite(ledPin8, Arduino.LOW);
    forward = true;
  }

  if ( release ) {
  }
  else {

    println (" release è cambiato " + release );
    // arduino.digitalWrite(ledPin9, Arduino.HIGH);
    delay(1000);
    //  arduino.digitalWrite(ledPin9, Arduino.LOW);
    release = true;
  }

  if ( take ) {
  }
  else {

    println (" take è cambiato " + take );
    // arduino.digitalWrite(ledPin10, Arduino.HIGH);
    delay(1000);
    // arduino.digitalWrite(ledPin10, Arduino.LOW);
    take = true;
  }
}

// Use this method to add additional statements
// to customise the GUI controls
void customGUI() {
}

se fa il ronzio vuol dire che sta sforzando e non va bene.. è normale che il servo non sia preciso al 100%.

non puoi usare i float, se vuoi maggiore precisione non devi dare gli angoli in °, ma usare direttamente i microsecondi del segnale. comunque non credere, i servi hanno un limite alla loro precisione in base alla loro qualità.

Perfetto !!
grazie writeMicroseconds è quello che ci vuole e ho modificato ServoFirmata cosi

/* This firmware supports as many servos as possible using the Servo library 
 * included in Arduino 0017
 *
 * TODO add message to configure minPulse/maxPulse/degrees
 *
 * This example code is in the public domain.
 */
 
#include <Servo.h>
#include <Firmata.h>

Servo servos[MAX_SERVOS];

void analogWriteCallback(byte pin, int value)
{
    if (IS_PIN_SERVO(pin)) {
        servos[PIN_TO_SERVO(pin)].writeMicroseconds(value);
    }
}

void setup() 
{
    byte pin;

    Firmata.setFirmwareVersion(0, 2);
    Firmata.attach(ANALOG_MESSAGE, analogWriteCallback);

    for (pin=0; pin < TOTAL_PINS; pin++) {
        if (IS_PIN_SERVO(pin)) {
	    servos[PIN_TO_SERVO(pin)].attach(PIN_TO_DIGITAL(pin));
        }
    }
   
    Firmata.begin(57600);
}

void loop() 
{
    while(Firmata.available())
        Firmata.processInput();
}

Concordo i servi non sono precisi L’ideale sarebbe un piezo motor, ma costa troppo