0
Offline
Newbie
Karma: 0
Posts: 26
Arduino rocks
|
 |
« Reply #120 on: June 04, 2008, 12:58:17 pm » |
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
Faraday Member
Karma: 6
Posts: 6226
Have fun!
|
 |
« Reply #121 on: June 04, 2008, 01:00:00 pm » |
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
Newbie
Karma: 0
Posts: 26
Arduino rocks
|
 |
« Reply #122 on: June 04, 2008, 03:23:29 pm » |
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
Newbie
Karma: 0
Posts: 26
Arduino rocks
|
 |
« Reply #123 on: June 04, 2008, 09:01:31 pm » |
Mem, I found the signal I want on the Receiver. The code compiles with one exception: This sketch line: 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: 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: 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
Faraday Member
Karma: 6
Posts: 6226
Have fun!
|
 |
« Reply #124 on: June 05, 2008, 01:43:40 am » |
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 #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
Newbie
Karma: 0
Posts: 26
Arduino rocks
|
 |
« Reply #125 on: June 05, 2008, 08:48:11 am » |
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 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
Faraday Member
Karma: 6
Posts: 6226
Have fun!
|
 |
« Reply #126 on: June 05, 2008, 09:23:34 am » |
Good to hear your making progress, looking forward to seeing more  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) 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
Newbie
Karma: 0
Posts: 26
Arduino rocks
|
 |
« Reply #127 on: June 05, 2008, 11:06:14 pm » |
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
Newbie
Karma: 0
Posts: 26
Arduino rocks
|
 |
« Reply #128 on: June 06, 2008, 08:38:49 pm » |
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
Faraday Member
Karma: 6
Posts: 6226
Have fun!
|
 |
« Reply #129 on: June 06, 2008, 10:49:57 pm » |
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
Newbie
Karma: 0
Posts: 23
Arduino rocks
|
 |
« Reply #130 on: June 08, 2008, 09:36:42 am » |
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
Faraday Member
Karma: 6
Posts: 6226
Have fun!
|
 |
« Reply #131 on: June 08, 2008, 10:35:06 am » |
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 //*****************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 //******** 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
Newbie
Karma: 0
Posts: 23
Arduino rocks
|
 |
« Reply #132 on: June 09, 2008, 06:54:17 am » |
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
Faraday Member
Karma: 6
Posts: 6226
Have fun!
|
 |
« Reply #133 on: June 09, 2008, 07:01:25 am » |
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
Newbie
Karma: 0
Posts: 23
Arduino rocks
|
 |
« Reply #134 on: June 09, 2008, 07:54:22 am » |
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
|
|
|
|
|
|