Problema libreria personale

Ciao a tutti,

ho provato a scrivere una libreria personale per la gestione dei servo motori con il microcontrollore della Pololu.

Il file .h è il seguente:

/*Libreria per la gestione dei servo motori mediante il microcontrollore
Micro Maestro http://www.pololu.com/catalog/product/1350 

Library useful to handle servo motors trough Micro Maestro Microcontroller 

Created by Daniele Caso, 25 October 2013


*/

#ifndef MicroMaestroHandle_h 
#define MicroMaestroHandle_h



#include <Arduino.h>
#include <SoftwareSerial.h>

 class MicroMaestroHandle {
     
   public:
        MicroMaestroHandle(int baudrate, int servoControllerResetPin, int servoControllerRxPin, int servoControllerTxPin, int minServoMillis, int maxServoMillis, int numServo); 
        
        void maestro_init_serial();
        void maestro_hard_reset();
        // Servo commands
        void maestro_set_target(byte servo, int angle);
        void maestro_set_target(byte device, byte servo, int angle);
        void maestro_set_speed(byte servo, int speedVal);
        void maestro_set_speed(byte device, byte servo, int speedVal);
        void maestro_set_acceleration(byte servo, byte accel);
        void maestro_set_acceleration(byte device, byte servo, byte accel);
        void maestro_go_home();
        void maestro_go_home(byte device);
        void maestro_set_servo_off(byte servo);
        void maestro_set_servo_off(byte device, byte servo);
        void maestro_set_all_servos_off();
        int maestro_get_position(byte servo);
        int maestro_get_position(byte device, byte servo);
        byte maestro_get_moving_state();
        byte maestro_get_moving_state(byte device);
        int maestro_get_errors();
        int maestro_get_errors(byte device);
        void maestro_send_command(byte cmd, byte device);
        void maestro_send_command(byte cmd, byte servoChannel, byte device);
        void maestro_send_command(byte cmd, byte servoChannel, int target, byte device);
        int maestro_receive_int();
        byte maestro_receive_byte();



        
     
//-----------------------------------------------------------------------
//-----------------------------------------------------------------------
//-----------------------------------------------------------------------

   private:
        byte _serialBytes[4];
        byte _serial1Bytes[1];
        byte _serial2Bytes[2];
        int _baudrate;
        int _servoControllerResetPin;
        int _servoControllerRxPin; 
        int _servoControllerTxPin; 
        int _minServoMillis;
        int _maxServoMillis;
	int _numServo;
	SoftwareSerial MaestroSerial;
 	int _microSeconds;
};
  




#endif

mentre il .cpp è il seguente:

#include "MicroMaestroHandle.h"
#include <SoftwareSerial.h>
#include <Arduino.h>

#define MAESTRO_USE_SOFT_SERIAL
#define MAESTRO_START_TRANSMISSION() noInterrupts()
#define MAESTRO_END_TRANSMISSION()   interrupts()
#define MAESTRO_USE_RST_PIN



MicroMaestroHandle::MicroMaestroHandle(int baudrate, int servoControllerResetPin, int servoControllerRxPin, int servoControllerTxPin, int minServoMillis, int maxServoMillis, int numServo){

	_baudrate = baudrate;
	_servoControllerResetPin = servoControllerResetPin;
	_servoControllerRxPin = servoControllerRxPin;
	_servoControllerTxPin = servoControllerTxPin;
	_minServoMillis = minServoMillis;
	_maxServoMillis = maxServoMillis;
	_numServo = numServo;
	MaestroSerial = SoftwareSerial(_servoControllerRxPin, _servoControllerTxPin);

	
	} 




void MicroMaestroHandle::maestro_init_serial(){

  
  #ifdef MAESTRO_USE_SOFT_SERIAL
  // talking to Pololu Serial Servo Controller
  pinMode(_servoControllerRxPin, INPUT);
  pinMode(_servoControllerTxPin, OUTPUT);
  digitalWrite(_servoControllerTxPin, HIGH); // keeps pololu board from getting spurious signal. Serial is idle high.
  #endif

#ifdef MAESTRO_USE_RST_PIN
  pinMode(_servoControllerResetPin,OUTPUT);
  maestro_hard_reset(); // reset the servo controller before speaking to it
#endif

  MaestroSerial.begin(_baudrate); // init the serial communication to the board
  delay(5); // give a little time to the Maestro to breeze 
  
#ifdef MAESTRO_DETECT_BAUDRATE
  MaestroSerial.print(0xAA, BIN);    //start byte to init baudrate
#endif
}

void MicroMaestroHandle::maestro_hard_reset(){
#ifdef MAESTRO_USE_RST_PIN
  digitalWrite(_servoControllerResetPin, LOW);
  delay(50);
  digitalWrite(_servoControllerResetPin, HIGH);
#endif
}


void MicroMaestroHandle::maestro_set_target(byte servoChannel, int angle){

	_microSeconds = (map(angle, 0, 180, _minServoMillis, _maxServoMillis)*4); //Mappa il valore di "target" tra _minServoMillis e _maxServoMillis
	maestro_send_command(0x84, servoChannel, _microSeconds, 0);
}

void MicroMaestroHandle::maestro_set_target(byte device, byte servoChannel, int angle){
	
        _microSeconds = (map(angle, 0, 180, _minServoMillis, _maxServoMillis)*4); //Mappa il valore di "target" tra _minServoMillis e _maxServoMillis
	maestro_send_command(0x04, servoChannel, _microSeconds, device);
}

void MicroMaestroHandle::maestro_set_speed(byte servo, int speedVal){

	maestro_send_command(0x87, servo, speedVal, 0);
}

void MicroMaestroHandle::maestro_set_speed(byte device, byte servo, int speedVal){
	
	maestro_send_command(0x07, servo, speedVal, device);
}

void MicroMaestroHandle::maestro_set_acceleration(byte servo, byte accel){

  maestro_send_command(0x89, servo, accel, 0);


}

void MicroMaestroHandle::maestro_set_acceleration(byte device, byte servo, byte accel){
	maestro_send_command(0x09, servo, accel, device);

}

void MicroMaestroHandle::maestro_go_home(){
	maestro_send_command(0xA2, 0);

}

void MicroMaestroHandle::maestro_go_home(byte device){
	maestro_send_command(0x22, device);

}

void MicroMaestroHandle::maestro_set_servo_off(byte servo){
	maestro_set_target(servo, 0);

}


void MicroMaestroHandle::maestro_set_servo_off(byte device, byte servo){
	maestro_set_target(device, servo, 0);
}


void MicroMaestroHandle::maestro_set_all_servos_off(){

	for(int i = 0; i<_numServo; i++){
    	maestro_set_servo_off(i);
  }

}

int MicroMaestroHandle::maestro_get_position(byte servo){

		maestro_send_command(0x90, servo, 0);
	  return maestro_receive_int();
}

int MicroMaestroHandle::maestro_get_position(byte device, byte servo){

  maestro_send_command(0x10, servo, device);
  return maestro_receive_int();
}

byte MicroMaestroHandle::maestro_get_moving_state(){

  maestro_send_command(0x93, 0);
  return maestro_receive_byte();
}

byte MicroMaestroHandle::maestro_get_moving_state(byte device){

  maestro_send_command(0x13, device);
  return maestro_receive_byte();
}

int MicroMaestroHandle::maestro_get_errors(){

  maestro_send_command(0xA1, 0);
  return maestro_receive_int();
}

int MicroMaestroHandle::maestro_get_errors(byte device){

  maestro_send_command(0x21, device);
  return maestro_receive_int();
}

..... CONTINUA

Quando cerco di compilare ricevo il seguente errore:

Arduino: 1.5.4 (Mac OS X), Board: “Arduino Yún”

/Users/danielecaso/Documents/Arduino/libraries/MicroMaestroHandle/MicroMaestroHandle.cpp: In constructor ‘MicroMaestroHandle::MicroMaestroHandle(int, int, int, int, int, int, int)’:
/Users/danielecaso/Documents/Arduino/libraries/MicroMaestroHandle/MicroMaestroHandle.cpp:12: error: no matching function for call to ‘SoftwareSerial::SoftwareSerial()’
/Applications/Arduino.app/Contents/Resources/Java/libraries/SoftwareSerial/arch/avr/SoftwareSerial_Class.h:83: note: candidates are: SoftwareSerial::SoftwareSerial(uint8_t, uint8_t, bool)
/Applications/Arduino.app/Contents/Resources/Java/libraries/SoftwareSerial/arch/avr/SoftwareSerial_Class.h:48: note: SoftwareSerial::SoftwareSerial(const SoftwareSerial&)

This report would have more information with
“Show verbose output during compilation”
enabled in File > Preferences.

Il problema è che lui non accetta la dichiarazione di una variabile di tipo SoftwareSerial:

SoftwareSerial MaestroSerial;

Come è possibile risolvere questo problema?

Hai provato a fare l'include della SoftwareSerial anche nel .ino dove poi includi la tua libreria ? :wink:

Guglielmo

Devi obbligatoriamente passare 2 byte, che indicano i pin RX e TX usati per la software serial:

SoftwareSerial MaestroSerial(pin_RX, pin_TX;

leo72:
Devi obbligatoriamente passare 2 byte, che indicano i pin RX e TX usati per la software serial:

Giustissimo Leo ... in effetti non avevo guardato la sintassi con cui l'aveva richiamata ... :~

Il mio suggerimento deriva invece da un problema che ho riscontrato in passato ...
... se fai una TUA lib, che a sua volta include un'altra lib, ho notato che l'IDE si incasina nelle compilazioni se la lib che includi/usi nella TUA lib (... quindi no nel .ino) comunque non viene inclusa anche nel .ino (... nel quale, ripeto, non c'è un riferimento diretto ad essa).

Hai riscontrato anche tu la cosa ? Deriva da come l'IDE gestisce le varie cose e cerca di "semplificare" la vita ?

Guglielmo

Credo di sì.
E poi c'è un altro problema, con le ultime versioni dell'IDE 1.5 è cambiato anche il modo in cui si fanno le librerie:

Sonique dovrebbe leggersi questa pagina.

Ciao ragazzi,

allora provo a rispondere:

@Guglielmlo

Nel .ino ho inserito la libreria SoftwareSerial.

@Leo72

Quello che tu dici avviene nel file .cpp nel costruttore della classe, e precisamente dove istanzio la variabile MaestroSerial = SoftwareSerial(_servoControllerRxPin, _servoControllerTxPin);

Io credo che lui non permetta di istanziare una variabile con riferimento null, ossia nel .h quando scrivo SoftwareSerial MaestroSerial;

SoftwareSerial non è una variabile ma è il nome della classe perciò puoi solo istanziarne una copia. Per istanziarla, devi passargli quei 2 parametri, perché così vuole il prototipo del costruttore della classe:

SoftwareSerial(uint8_t receivePin, uint8_t transmitPin, bool inverse_logic = false);

(estratto da SoftwareSerial.h - il terzo parametro è opzionale, come vedi se non lo specifichi tu, viene impostato di default a false).

Per inciso ...
... c'ho perso tanto di quel tempo ad evitare errori nell'inclusione della SoftwareSerial in un altra mia libreria che alla fine ... ho usato la "via sporca" ... tutto il codice nel .h (e solo quello, senza .c o .cpp) e mi sono levato dalle scatole un mucchio di problemi :grin: :grin: :grin:

Dove mi serve (nei .ino) includo prima la SoftareSerial (che come dicevo, anche se non direttamente richiamata, comunque occorre includere) e poi il mio .h e ... va che una bellezza :wink:

Guglielmo

Grazie ad entrambi,

Leo sono d'accordo con te che SoftwareSerial è il nome di una classe, per cui, volendo esser precisi, io sto definendo oggetto di quella classe. Solo che nel .h non la istanzio, diciamo con un new.

Ora, ho visto anche il codice della SoftwareSerial.h e SoftwareSerial.cpp e ho visto che l'unico costruttore disponibile è di tipo SoftwareSerial(_rx, _tx);

Ma il problema non è questo.

Quella che di seguito ti incollo, per me è una operazione lecita:

SoftwareSerial maestro;
maestro = SoftwareSerial(_rx, _tx);

Ma se provi a fare una cosa del genere nel .ino ti da comunque errore.
Magari sto sbagliando qualcosa, in quanto non programmando più in C/C++ qualcosa mi sfugge.

Non sono neanch'io un super-programmatore in C++ per cui potrei anche dirti cose sbagliate, ma quel modo di istanziare una classe non mi pare corretto :sweat_smile:

quel modo di istanziare una classe non mi pare corretto

Sai, mi sembra strana questa cosa.

Ad esempio, in Java io posso fare tranquillamente la seguente cosa:

MyClass myClassIstance;
            myClassIstance = new MyClass(); //Invocazione del costruttore di default

oppure

MyClass myClassIstance;
            myClassIstance = new MyClass(int param1, int param2); //Invocazione del costruttore

in quanto la differenza col fare direttamente

MyClass myClassIstance = new MyClass(); //Invocazione del costruttore di default

è praticamente nulla!

Ecco perchè credo che il problema risiede in altro punto.

L'ultima spiaggia è quella proposta da Guglielmo, però vorrei provare prima un altro po' soluzioni più "pulite!

Sì ma se il costruttore chiede 2 parametri, quelli glieli devi dare. Però non insisto perché io sono nato prima delle classi per cui.... :stuck_out_tongue_closed_eyes:

Premesso che io sono ANSI C e che di C++ so poco o nulla ...
... sicuro che comunque non devi istanziarla con :

MaestroSerial = new SoftwareSerial(_servoControllerRxPin, _servoControllerTxPin);

Boiata pazzesca ??? :grin: :grin: :grin: Probabile eh ...

Guglielmo

Infatti,
non posso istanziare in quella maniera.

leo72, vedi il mio file .cpp, c'è proprio quello che dici tu:

MaestroSerial = SoftwareSerial(_servoControllerRxPin, _servoControllerTxPin);

Tra l'altro presente proprio nel costruttore della mia classe MicroMaestroHandle

Nel costruttore della tua classe devi mettere MaestroSerial=new SoftwareSerial(ecc. perchè a tutti gli effetti hai un puntatore. La cosa che dici tu la puoi fare facendo:
MaestroSerial=SoftwareSerial(parametri)
new ti serve quando vuoi allocare oggetti dinamicamente mentre il secondo metodo non te li mette nello heap.

Ciao,

nel costruttore della mia classe (file .cpp) ho fatto la modifica che mi hai detto

MicroMaestroHandle::MicroMaestroHandle(int baudrate, int servoControllerResetPin, int servoControllerRxPin, int servoControllerTxPin, int minServoMillis, int maxServoMillis, int numServo){

	_baudrate = baudrate;
	_servoControllerResetPin = servoControllerResetPin;
	_servoControllerRxPin = servoControllerRxPin;
	_servoControllerTxPin = servoControllerTxPin;
	_minServoMillis = minServoMillis;
	_maxServoMillis = maxServoMillis;
	_numServo = numServo;
	MaestroSerial = new SoftwareSerial(_servoControllerRxPin, _servoControllerTxPin);

	
	}

Ma ricevo il seguente errore:

Arduino: 1.5.4 (Mac OS X), Board: “Arduino Yún”

/Users/danielecaso/Documents/Arduino/libraries/MicroMaestroHandle/MicroMaestroHandle.cpp: In constructor ‘MicroMaestroHandle::MicroMaestroHandle(int, int, int, int, int, int, int)’:
/Users/danielecaso/Documents/Arduino/libraries/MicroMaestroHandle/MicroMaestroHandle.cpp:12: error: no matching function for call to ‘SoftwareSerial::SoftwareSerial()’
/Applications/Arduino.app/Contents/Resources/Java/libraries/SoftwareSerial/arch/avr/SoftwareSerial_Class.h:83: note: candidates are: SoftwareSerial::SoftwareSerial(uint8_t, uint8_t, bool)
/Applications/Arduino.app/Contents/Resources/Java/libraries/SoftwareSerial/arch/avr/SoftwareSerial_Class.h:48: note: SoftwareSerial::SoftwareSerial(const SoftwareSerial&)
/Users/danielecaso/Documents/Arduino/libraries/MicroMaestroHandle/MicroMaestroHandle.cpp:21: error: no match for ‘operator=’ in ‘((MicroMaestroHandle*)this)->MicroMaestroHandle::MaestroSerial = (((SoftwareSerial*)operator new(28u)), (->SoftwareSerial::SoftwareSerial(((uint8_t)((MicroMaestroHandle*)this)->MicroMaestroHandle::_servoControllerRxPin), ((uint8_t)((MicroMaestroHandle*)this)->MicroMaestroHandle::_servoControllerTxPin), false), ))’
/Applications/Arduino.app/Contents/Resources/Java/libraries/SoftwareSerial/arch/avr/SoftwareSerial_Class.h:48: note: candidates are: SoftwareSerial& SoftwareSerial::operator=(const SoftwareSerial&)

This report would have more information with
“Show verbose output during compilation”
enabled in File > Preferences.

leo72:
Devi obbligatoriamente passare 2 byte, che indicano i pin RX e TX usati per la software serial:

Hai provato a passargli dei byte come suggerito da leo?

In che senso, passargli due byte?

Vuoi dichiarare _servoControllerRxPin e _servoControllerTxPin come byte ?