Pages: 1 ... 7 8 [9] 10 11 ... 15   Go Down
Author Topic: 3 axis auto stabilized platform  (Read 29182 times)
0 Members and 1 Guest are viewing this topic.
0
Offline Offline
Newbie
*
Karma: 0
Posts: 26
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

New Problem - but a logical one:


I think there's a bit of a problem accessing the Pulses array from the ISR, the Lib, and the sketch - is there a scope modifier I need?
Ben

The Error Says:
o: In function `incPulse':
multiple definition of `Pulses'hardware\libraries\ServoInput2\ServoInput2.o:D:\arduino-0011/hardware\libraries\ServoInput2\ServoInput2.cpp:11: first defined here


o: In function `incPulse':
o: In function `incPulse':
Logged

London
Offline Offline
Tesla Member
***
Karma: 10
Posts: 6255
Have fun!
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Here are some other things to look at:

in the cpp file, after #include "ServoInput2.h" add:
 #include <wiring.h>
 #include <avr/interrupt.h>

move the declarations of the following into the cpp file and make them static as follows
static volatile unsigned int Pulses[ MAX_CHANNELS + 1]; // array holding channel pulses width value in microseconds
static volatile uint8_t  Channel;      // number of channels detected so far in the frame (first channel is 1)
static volatile uint8_t State;         // this will be one of the following states:

remove the semicolon from the end of
  uint8_t ServoInput2::getState()

at the bottom of the file, make an instance of the library for the user. There can only be one instance (there is support for only a single input capture in the arduino chip) so lets make it a little easer for the user
ServoInput2 ServoInput = ServoInput2() ;

in the header file add
  #include <inttypes.h>
to the top of the header file

and add
  extern ServoInput2 ServoInput;  // make an instance for the user
to the bottom , just before the endif.
you will need to remove the following from the sketch
  ServoInput2 servoInput(); // remove this because its declared in the source file.

I think you will need to fix some inconsistent capitalization between the sketch and the source files but these changes should get you close.
« Last Edit: June 04, 2008, 01:01:46 pm by mem » Logged

0
Offline Offline
Newbie
*
Karma: 0
Posts: 26
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Mem,
Great
That compiles. appears to run - I'll need to connect it to a receiver next.
(the creation of a user instance didn't work - but I remmed, and everything else appears ok.)
Logged

0
Offline Offline
Newbie
*
Karma: 0
Posts: 26
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Mem,
I found the signal I want on the Receiver.

The code compiles with one exception:

This sketch line:

Code:
 uint8_t chan = 1;
        servoRoll.writeChan(chan,pulsewidth);


Yields this error:

o: In function `loop':
undefined reference to `ServoTimer2::writeChan(unsigned char, int)'

Which is quite surprising - where does "char" come from?

Here's the h:

Code:
class ServoTimer2
{
  public:
      // constructor:
      ServoTimer2();

      uint8_t attach(int);     // attach the given pin to the next free channel, sets pinMode, returns channel number or 0 if failure
                               // the attached servo is pulsed with the current pulse width value, (see the write method)
        void detach();
        void write(int);         // store the pulse width in microseconds (between MIN_PULSE_WIDTH and MAX_PULSE_WIDTH)for this channel
        void writeChan(uint8_t,int);     // (Channel,Pulsewidth) store the pulse width in microseconds (between MIN_PULSE_WIDTH and MAX_PULSE_WIDTH)for the

given                                     //channel
        int read();                    // returns current pulse width in microseconds for this servo
      boolean attached();      // return true if this servo is attached
 private:
       uint8_t chanIndex;      // index into the channel data for this servo

};

And the method code:
Code:
static void writeChan(uint8_t chan, int pulsewidth);


static void ServoTimer2::writeChan(uint8_t chan, int pulsewidth)
{
   // calculate and store the values for the given channel
... etc

So far you've lived up to your tagline...
Any ideas here?
Ben
Logged

London
Offline Offline
Tesla Member
***
Karma: 10
Posts: 6255
Have fun!
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

The compiler is complaining because
  static void writeChan(uint8_t chan, int pulsewidth)
is a static function, only accessible to code in the servoTimer2.cpp source file and not a member of the servoTimer2 class.

Making it a member method would be odd because it would allow any instance to change any other instances data. I suggest you create an array of servo instances and use that to access the data like this example sketch

Code:
#include <ServoTimer2.h>

#define NBR_SERVOS 8   // this must be between 1 and NBR_CHANNELS as defined in ServoTimer2.H
byte servoPins[NBR_SERVOS] = {2,3,4,5,6,7,8,9};  // pins our servos are attached to
ServoTimer2 Servos[NBR_SERVOS]  ;

int direction[NBR_SERVOS];   // 1 is forward, -1 is reverse

void setup() {
  for( int i =0; i < NBR_SERVOS; i++){
       direction[i] = 1;  //  forward
       Servos[i].attach(servoPins[i]);
       Servos[i].write( 800 + (i * 200));  // write some test data       
    }    
}
  
void loop() {
  int pulseWidth;
 
    //sweep all the servos back and forth
    for( int i=0; i <  NBR_SERVOS; i++){
        pulseWidth = Servos[i].read();        
        if(pulseWidth >= MAX_PULSE_WIDTH){
            direction[i] = -1;
        }
        if (pulseWidth <= MIN_PULSE_WIDTH) {
             direction[i] = 1;    
        }
       Servos[i].write(pulseWidth + direction[i]);      
    }
    delay(10);
}
uint8_t is another name for an unsigned char, it's short for u(unsigned)int(integer)8(eight bits)_t(it's a type). I tend to use byte instead of uint8_t these days but either more clearly express their purpose than 'a character without a sign'. All three forms are the same to the compiler
« Last Edit: June 05, 2008, 01:50:48 am by mem » Logged

0
Offline Offline
Newbie
*
Karma: 0
Posts: 26
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Great!
It compiles. I'll hook it up next and test some servos.
I changed uint8_t to byte universally.

one nice feature is that it supports 4 kinds of servo channels:

1. receiver-based servos
2. virtual servos (channels that get used to switch on the UAV code - or adjust software gyro gain for example) and
3. pin-tied servos - in excess of the number of channels supported by the receiver
4. non-servo peripherals - for example an ir transmitter that drives a camera based on a virtual servo.

simply assign servos to the feedback pin here (2), to nothing (0) or to some real pin

Code:
byte servoPins[NBR_SERVOS] = {2,2,2,2,0,0,8,9};  // pins our servos are attached to

More when its attached...
Logged

London
Offline Offline
Tesla Member
***
Karma: 10
Posts: 6255
Have fun!
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Good to hear your making progress, looking forward to seeing more  smiley

0 is a real Arduino pin so if you attach a servo assigned to pin 0 it will write to that pin. Pin 0 is usually used  by the serial port on the Arduino so don't actually attach an instance using pin 0 if your board has a serial interface/USB.

Your sketch could check and not call the attach method if the pin is 0 (or 1)
Code:
void setup() {
  for( int i =0; i < NBR_SERVOS; i++){
      if(servoPins[i] >1)
          Servos[i].attach(servoPins[i]); // this will start pulsing the pin!
      Servos[i].write( 800 + (i * 200));  // writing to an unattched pin is ok
    }    
}
« Last Edit: June 05, 2008, 09:27:49 am by mem » Logged

0
Offline Offline
Newbie
*
Karma: 0
Posts: 26
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Foiled for tonight.
I have a Hitec NFS-04MG 4 channel receiver; the output stage is a 4015 shift register. The composite signal appears on one topside trace, but it appears not to be separable. (It's not a straight shot into the shift - since the reset RC timer is all tangled up in the composite line.

I think i shouldn't waste more time on this receiver - it's old school - I'd like to "crack" a receiver which is more widely available. I've got a nice GWS nano 6 chan I think I'll break open next.
In order to use this model - it might work to add a reset line on a separate pin, but that misses the point...

Ben
Logged

0
Offline Offline
Newbie
*
Karma: 0
Posts: 26
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Mem,
I think you mentioned having a Hitec Micro O5S
 - do you think it possible to cut the composite trace and get a small wire on both the PIC input pin, and the radio signal out?
I have some other receivers - but I don't have a clearly disambiguated composite trace isolated.
that receiver is $23 at Tower hobby and quite small. It would be an excellent candidate generally...

Ben
Logged

London
Offline Offline
Tesla Member
***
Karma: 10
Posts: 6255
Have fun!
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

The 05S should be suitable, you can find info on the composite signal locations in a post early in this thread. I tested the input capture code using the composit signal output from this receiver. I didn't try to inject a signal but I think you may be able to lift the pins of the SMT PIC chip if you have a small enough soldering iron. The traces are tiny so it will need a steady hand and good eyesight.
Logged

0
Offline Offline
Newbie
*
Karma: 0
Posts: 23
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hi to all!! Im new arduino fun, its one month i try to understand PPM/PWN and R/C transmission. I read MEM & Axeil post to know more about it, also i found an oscilloscope to investigate on my R/C Hitec Focus 4.
My idea is to create a UAV (QuadCopter) like other project on Internet ;-) but im not a good elettronic/programmer... so i follow the new post from Bgalliand as i can understand hw wants make the same goal of me.
At the moment my progress are:
1) Found the pin on receiver (Hitec Focus4) where arrived the PPM signal (4 Channel)
2) i used the old code from MEM/Axeil to read PPM without multiplex only attached to pin 8, but i can read all 4 CH without dirty and wrong order capture.

My idea is to use 4 Brushless motor to power the QuadCopter and an Accelorometer to correct the fly, perhaps the future is to have much more but at the moment is enough.
I ask for an help from where i need to move now, I can read the PPM and pulse the Brushless (with ESC controller) without other component? is need a multiplexer to have a good PPM signal?
Many thanks for your great post!!!
Logged

London
Offline Offline
Tesla Member
***
Karma: 10
Posts: 6255
Have fun!
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

hi DiMiz, axileon needed the multiplexer because he wanted to use a receiver that did not output the channels in sequence. If your hitec 4 channel receiver works like my hitec 5 channel one then you can skip the multiplexer and use the recent decoder code, I think this is the latest:

 ServoInput.h
Code:
//*****************ServoInput2.h*************************************
#ifndef ServoInput2_H
#define ServoInput2_H

#include <inttypes.h>

#define icpPin            8   // this interrupt handler must use pin 8
#define TICKS_PER_uS      2   // number of timer ticks per microsecond
#define MAX_CHANNELS    8   // maximum number of channels we can store  
#define SYNC_GAP_LEN      (3000 * TICKS_PER_uS) // we assume a space at least 3000us is sync (note clock counts in 0.5 us ticks)
#define NOT_SYNCHED_state  0    // the system is not synched so the data is random
#define ACQUIRING_state  1      // one sync pulse detected but not all channels have been received
#define READY_state     2       // synched and all channel data is valid

class ServoInput2
{
  public:
      ServoInput2(); //Constructor
      int GetChannelPulseWidth(uint8_t);  // this is the access function for channel data
      uint8_t getState(); //State Function

 private:
};

#endif

servoInput.cpp
Code:
//******** servoInput.cpp *********

#include "ServoInput2.h"
#include <wiring.h>
#include <avr/interrupt.h>


static volatile unsigned int Pulses[ MAX_CHANNELS + 1]; // array holding channel pulses width value in microseconds
static volatile uint8_t  Channel;      // number of channels detected so far in the frame (first channel is 1)
static volatile uint8_t State;         // this will be one of the following states:



ISR(TIMER1_CAPT_vect)
{
   if(! bit_is_set(TCCR1B ,ICES1)){       // was falling edge detected ?  
       TCNT1 = 0;               // reset the counter      
       if(Channel <= MAX_CHANNELS) {
           Pulses[Channel++] = ICR1 / TICKS_PER_uS;  // store pulse length as microsoeconds
        }      
   }
   else {                          // rising  edge was detected  
        TCNT1 = 0;               // reset the counter      
        if(ICR1 >= SYNC_GAP_LEN){   // is the space between pulses big enough to be the SYNC
            Channel = 1;       // if so, reset the channel counter to 1      
              if(State == NOT_SYNCHED_state)
                  State = ACQUIRING_state;        // this is the first sync pulse, we need one more to fill the channel data array
              else if( State == ACQUIRING_state)      
                   State = READY_state;           // this is the second sync so flag that channel data is valid
        }    
   }      
   TCCR1B ^= _BV(ICES1);                 // toggle bit value to trigger on the other edge
}


ServoInput2::ServoInput2()
{
  pinMode(icpPin,INPUT);
  Channel = 1;            
  State = NOT_SYNCHED_state;
  TCCR1A = 0x00;         // COM1A1=0, COM1A0=0 => Disconnect Pin OC1 from Timer/Counter 1 -- PWM11=0,PWM10=0 => PWM Operation disabled
  TCCR1B = 0x02;         // 16MHz clock with prescaler means TCNT1 increments every .5 uS (cs11 bit set
  TIMSK1 = _BV(ICIE1);   // enable input capture interrupt for timer 1
}


uint8_t ServoInput2::getState()  
{
  return State;
}


int ServoInput2::GetChannelPulseWidth( uint8_t channel)
{
  // this is the access function for channel data
  int result;  
  if( (State == READY_state)  && (channel > 0) && (channel <=  MAX_CHANNELS)  ) {
    cli();             //disable interrupts
    result =  Pulses[channel] ;
    sei();             // enable interrupts
  }
  else
    result = 0;        // return 0 if no valid pulse is available  

  return result;
}
« Last Edit: June 08, 2008, 10:36:27 am by mem » Logged

0
Offline Offline
Newbie
*
Karma: 0
Posts: 23
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hi MEM!! Many thanks for your fast reply to my help, I try this code this evening. As i can see this is function and simple Arduino skecth, how can i use it? Also i can debug with Serial output the PulseWidth?
Many thanks i will report my test.
Sincerelly
Logged

London
Offline Offline
Tesla Member
***
Karma: 10
Posts: 6255
Have fun!
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Reply #116 has a sketch that sends the pulse width to the serial port. If you can try to post an outline of the functionality you want for your sketch,  I or others here can help you more with the code.
Logged

0
Offline Offline
Newbie
*
Karma: 0
Posts: 23
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Thanks Mem i will try the sketch from post 116, i think is what i need now to test R/C transmission and PPM conversion.
My generic outline for what i want is:
1- Grab R/C command from transmitter
2- Receive PPM signal decode it and match Accelorometer XYZ variation to stabilized the QuadCopter
3- Pulse 4 Brushless motor using the ESC circuit (The ESc is already done :-))

At the moment if can decode without problem the PPM signal i think is great step :-)
Many thanks this evening i will report my improvements, also you never made a Helicopter like my project?
Logged

Pages: 1 ... 7 8 [9] 10 11 ... 15   Go Up
Jump to: