Go Down

Topic: Timing Problem with Lanc & pulsein (Read 1 time) previous topic - next topic

makru83

Jan 25, 2013, 10:56 am Last Edit: Jan 25, 2013, 01:54 pm by makru83 Reason: 1
I am trying to control a Sony VideoCamera through an RC Transmitter.
The Lanc Code I am using is from Michael Koch,
http://controlyourcamera.blogspot.co.at/2011/02/arduino-powered-lanc-remote.html

The Code works great, but if I add my pulsein Code for reading PPM/PWM Signal from the Reciever,
Code: [Select]
button = pulseIn(ppmSwitch, HIGH, 20000);
 poti = pulseIn(ppmPoti, HIGH, 20000);

the Zoom & Focus Control is choppy, because of the 20000ms Timing needed for reading the Pwm Signals.

How could I overcome the Problem?

Code: [Select]



#define cmdPin 7
#define lancPin 11
#define ppmPoti 13
#define ppmSwitch 4
int cmdRepeatCount;
int bitDuration = 104; //Duration of one LANC bit in microseconds.
int button;
int poti;
int recordstate = 0;

//Start-stop video recording
boolean REC[] = {LOW,LOW,LOW,HIGH,HIGH,LOW,LOW,LOW,   LOW,LOW,HIGH,HIGH,LOW,LOW,HIGH,HIGH}; //18 33

//Zoom in from slowest to fastest speed
boolean ZOOM_IN_0[] = {LOW,LOW,HIGH,LOW,HIGH,LOW,LOW,LOW,   LOW,LOW,LOW,LOW,LOW,LOW,LOW,LOW}; //28 00
boolean ZOOM_IN_1[] = {LOW,LOW,HIGH,LOW,HIGH,LOW,LOW,LOW,   LOW,LOW,LOW,LOW,LOW,LOW,HIGH,LOW}; //28 02
boolean ZOOM_IN_2[] = {LOW,LOW,HIGH,LOW,HIGH,LOW,LOW,LOW,   LOW,LOW,LOW,LOW,LOW,HIGH,LOW,LOW}; //28 04
boolean ZOOM_IN_3[] = {LOW,LOW,HIGH,LOW,HIGH,LOW,LOW,LOW,   LOW,LOW,LOW,LOW,LOW,HIGH,HIGH,LOW}; //28 06
boolean ZOOM_IN_4[] = {LOW,LOW,HIGH,LOW,HIGH,LOW,LOW,LOW,   LOW,LOW,LOW,LOW,HIGH,LOW,LOW,LOW}; //28 08
boolean ZOOM_IN_5[] = {LOW,LOW,HIGH,LOW,HIGH,LOW,LOW,LOW,   LOW,LOW,LOW,LOW,HIGH,LOW,HIGH,LOW}; //28 0A
boolean ZOOM_IN_6[] = {LOW,LOW,HIGH,LOW,HIGH,LOW,LOW,LOW,   LOW,LOW,LOW,LOW,HIGH,HIGH,LOW,LOW}; //28 0C
boolean ZOOM_IN_7[] = {LOW,LOW,HIGH,LOW,HIGH,LOW,LOW,LOW,   LOW,LOW,LOW,LOW,HIGH,HIGH,HIGH,LOW}; //28 0E

//Zoom out from slowest to fastest speed
boolean ZOOM_OUT_0[] = {LOW,LOW,HIGH,LOW,HIGH,LOW,LOW,LOW,   LOW,LOW,LOW,HIGH,LOW,LOW,LOW,LOW}; //28 10
boolean ZOOM_OUT_1[] = {LOW,LOW,HIGH,LOW,HIGH,LOW,LOW,LOW,   LOW,LOW,LOW,HIGH,LOW,LOW,HIGH,LOW}; //28 12
boolean ZOOM_OUT_2[] = {LOW,LOW,HIGH,LOW,HIGH,LOW,LOW,LOW,   LOW,LOW,LOW,HIGH,LOW,HIGH,LOW,LOW}; //28 14
boolean ZOOM_OUT_3[] = {LOW,LOW,HIGH,LOW,HIGH,LOW,LOW,LOW,   LOW,LOW,LOW,HIGH,LOW,HIGH,HIGH,LOW}; //28 16
boolean ZOOM_OUT_4[] = {LOW,LOW,HIGH,LOW,HIGH,LOW,LOW,LOW,   LOW,LOW,LOW,HIGH,HIGH,LOW,LOW,LOW}; //28 18
boolean ZOOM_OUT_5[] = {LOW,LOW,HIGH,LOW,HIGH,LOW,LOW,LOW,   LOW,LOW,LOW,HIGH,HIGH,LOW,HIGH,LOW}; //28 1A
boolean ZOOM_OUT_6[] = {LOW,LOW,HIGH,LOW,HIGH,LOW,LOW,LOW,   LOW,LOW,LOW,HIGH,HIGH,HIGH,LOW,LOW}; //28 1C
boolean ZOOM_OUT_7[] = {LOW,LOW,HIGH,LOW,HIGH,LOW,LOW,LOW,   LOW,LOW,LOW,HIGH,HIGH,HIGH,HIGH,LOW}; //28 1E

/*  
Focus Control - not in Use

//Focus control. Camera must be switched to manual focus
boolean FOCUS_NEAR[] = {LOW,LOW,HIGH,LOW,HIGH,LOW,LOW,LOW,   LOW,HIGH,LOW,LOW,LOW,HIGH,HIGH,HIGH}; //28 47
boolean FOCUS_FAR[] = {LOW,LOW,HIGH,LOW,HIGH,LOW,LOW,LOW,   LOW,HIGH,LOW,LOW,LOW,HIGH,LOW,HIGH}; //28 45

boolean FOCUS_AUTO[] = {LOW,LOW,HIGH,LOW,HIGH,LOW,LOW,LOW,   LOW,HIGH,LOW,LOW,LOW,LOW,LOW,HIGH}; //28 41

*/

void setup() {

 pinMode(lancPin, INPUT); //listens to the LANC line
 pinMode(cmdPin, OUTPUT); //writes to the LANC line
 pinMode(ppmSwitch, INPUT); //PPM RX Switch Input
 pinMode(ppmPoti, INPUT); //PPM RX Poti Input

 digitalWrite(cmdPin, LOW); //set LANC line to +5V
 delay(5000); //Wait for camera to power up completly
 bitDuration = bitDuration - 8; //Writing to the digital port takes about 8 microseconds so only 96 microseconds are left for each bit
}


void loop() {
   
 
 button = pulseIn(ppmSwitch, HIGH, 20000);
 poti = pulseIn(ppmPoti, HIGH, 20000);
 
 if(button>1500 && recordstate==0)
 {
   recordstate = 1;
   lancCommand(REC);
 }
 
 if(button<1400 && recordstate==1)
 {
   recordstate = 0;
   lancCommand(REC);
 }
 
   
 if (poti>1580 && poti<1630){lancCommand(ZOOM_IN_0);}
 if (poti>1630 && poti<1680){lancCommand(ZOOM_IN_1);}
 if (poti>1680 && poti<1730){lancCommand(ZOOM_IN_2);}
 if (poti>1730 && poti<1780){lancCommand(ZOOM_IN_3);}
 if (poti>1780 && poti<1830){lancCommand(ZOOM_IN_4);}
 if (poti>1830 && poti<1880){lancCommand(ZOOM_IN_5);}
 if (poti>1880 && poti<1930){lancCommand(ZOOM_IN_6);}
 if (poti>1930){lancCommand(ZOOM_IN_7);}
 
 
 if (poti<1420 && poti>1370){lancCommand(ZOOM_OUT_0);}
 if (poti<1370 && poti>1320){lancCommand(ZOOM_OUT_1);}
 if (poti<1320 && poti>1270){lancCommand(ZOOM_OUT_2);}
 if (poti<1270 && poti>1220){lancCommand(ZOOM_OUT_3);}
 if (poti<1220 && poti>1170){lancCommand(ZOOM_OUT_4);}
 if (poti<1170 && poti>1120){lancCommand(ZOOM_OUT_5);}
 if (poti<1120 && poti>1070){lancCommand(ZOOM_OUT_6);}
 if (poti<1070){lancCommand(ZOOM_OUT_7);}
 
 
}


void lancCommand(boolean lancBit[]) {
     
       cmdRepeatCount = 0;
 
  while (cmdRepeatCount < 5) {  //repeat 5 times to make sure the camera accepts the command

               while (pulseIn(lancPin, HIGH) < 5000) {  
                 //"pulseIn, HIGH" catches any 0V TO +5V TRANSITION and waits until the LANC line goes back to 0V
                 //"pulseIn" also returns the pulse duration so we can check if the previous +5V duration was long enough (>5ms) to be the pause before a new 8 byte data packet
                 //Loop till pulse duration is >5ms
               }

  //LOW after long pause means the START bit of Byte 0 is here
  delayMicroseconds(bitDuration);  //wait START bit duration

  //Write the 8 bits of byte 0
                       //Note that the command bits have to be put out in reverse order with the least significant, right-most bit (bit 0) first
                       for (int i=7; i>-1; i--) {
    digitalWrite(cmdPin, lancBit[i]);  //Write bits.
    delayMicroseconds(bitDuration);
                       }
 
                       //Byte 0 is written now put LANC line back to +5V
                       digitalWrite(cmdPin, LOW);
                       delayMicroseconds(10); //make sure to be in the stop bit before byte 1
                       
                       while (digitalRead(lancPin)) {
                         //Loop as long as the LANC line is +5V during the stop bit
                       }

                       //0V after the previous stop bit means the START bit of Byte 1 is here
        delayMicroseconds(bitDuration);  //wait START bit duration
     
        //Write the 8 bits of Byte 1
                       //Note that the command bits have to be put out in reverse order with the least significant, right-most bit (bit 0) first
                       for (int i=15; i>7; i--) {
             digitalWrite(cmdPin,lancBit[i]);  //Write bits
            delayMicroseconds(bitDuration);
                       }

                       //Byte 1 is written now put LANC line back to +5V
                       digitalWrite(cmdPin, LOW);

  cmdRepeatCount++;  //increase repeat count by 1
 
  /*Control bytes 0 and 1 are written, now don't care what happens in Bytes 2 to 7
  and just wait for the next start bit after a long pause to send the first two command bytes again.*/
 

}//While cmdRepeatCount < 5
}





PeterH

You could use interrupts to detect the start and end of each pulse (and use micros() to determine the interval between the start/end) rather than using a blocking call to pulseIn(). If your interrupt handler stored the calculated pulse length in a volatile byte variable then your main code reading it in loop() could refer to the variable whenever it wanted to, the method of keeping the variable up to date would be transparent to it.
I only provide help via the forum - please do not contact me for private consultancy.

makru83

As a complete Noob, I couldn't figure out how I have to work with Interrupts to detect start and end of the pwm/ppm pulse.

Does someone maybe have a sample Code, to read the PWM Signal from one Pin through Interrupts?
I looked at some Examples, but they are to complex for me, to figure this part out.

Nick Gammon

Code: [Select]

boolean ZOOM_IN_0[] = {LOW,LOW,HIGH,LOW,HIGH,LOW,LOW,LOW,   LOW,LOW,LOW,LOW,LOW,LOW,LOW,LOW}; //28 00
...


booleans are true or false. Try making them "byte" type.

Stuff about interrupts: http://www.gammon.com.au/interrupts
Please post technical questions on the forum, not by personal message. Thanks!

More info:
http://www.gammon.com.au/electronics

johncc


Code: [Select]

boolean ZOOM_IN_0[] = {LOW,LOW,HIGH,LOW,HIGH,LOW,LOW,LOW,   LOW,LOW,LOW,LOW,LOW,LOW,LOW,LOW}; //28 00
...


booleans are true or false. Try making them "byte" type.



?

It seems to me the coder (not the OP I don't think) just  chose to deal with an array of 8 "bits" here  as  "bool bits[]={0,0,1,0, 1,0,0,0};" rather than a more conventional "u_int8 bits=0x28;"  (Ok, maybe he "wasted" 7 bytes of memory-- but then so does your recommendation byte bits[]={0,0,1,0, 1,0,0,0};).

I'm not trying to confront, just trying to identify if I'm missing something...

Thanks,
John

Nick Gammon

It will probably use the same amount of memory, I'm just saying it is the "wrong" datatype. I didn't recommend 0/1 BTW, the values LOW/HIGH are intended to go into the byte type, not the boolean type.

Let's hypothetically say that one day HIGH is defined as 0xFF, and that the boolean type can only hold one bit. Then you can't put HIGH into a boolean. (Today you probably can).
Please post technical questions on the forum, not by personal message. Thanks!

More info:
http://www.gammon.com.au/electronics

johncc

Ok, I see where you're coming from, thanks.  I agree this will make his declaration more consistent/correct.

I doubt it will have an effect on his problem though :)

Cheers,
John

makru83

I changed the boolean to byte, and yes it works just like before :-)

About the Interrupts, I found a page providing a good sample Code,
but I still don't get it to work to read the pwm Signal through Interrupts.

http://rcarduino.blogspot.co.at/2012/11/how-to-read-rc-channels-rcarduinofastlib.html

makru83

Hi John,

as soon as I change the Value below 15000 the PPM Signals recieved are not correct anymore, 2 of 3 Results will have 0 instead of the PPM Value.
Anyway, I just found a simpler Code which works with External Interrupts. Therefore I can only use 2 Pins, but for me this is just as much as I need.

Here is the Example:
http://rcarduino.blogspot.co.uk/2012/01/how-to-read-rc-receiver-with.html

DuaneB

Hi,
   I wrote both of the links you have posted.

   I suspect that you were reading 0's with the first sketch because of the location of your serial print statement. Would you mind trying the sketch again with the serial print in this location, if you use it in any other location without testing if(bUpdateFlags & THROTTLE_FLAG) you cannot assume that it will have a valid value.

Code: [Select]

   if(bUpdateFlags & THROTTLE_FLAG)
    {
      unThrottleIn = unThrottleInShared;
      // Serial.println(unThrottleIn);
    }
 
    if(bUpdateFlags & STEERING_FLAG)
    {
      unSteeringIn = unSteeringInShared;
    }
 
    if(bUpdateFlags & AUX_FLAG)
    {
      unAuxIn = unAuxInShared;
    }


Duane B
Read this
http://rcarduino.blogspot.com/2012/04/servo-problems-with-arduino-part-1.html
then watch this
http://rcarduino.blogspot.com/2012/04/servo-problems-part-2-demonstration.html

Rcarduino.blogspot.com

makru83

Hi Duane,

right, all I got were 0's :-)
I will try your Code as soon as I am back home and post back afterwards.

Mario

makru83

Hi Duane,

sorry, but I am still not able to get it to work yet.
If I grab any of your Examples:
http://rcarduino.blogspot.co.at/2012/04/how-to-read-multiple-rc-channels-draft.html  or
http://rcarduino.blogspot.co.at/2012/11/how-to-read-rc-channels-rcarduinofastlib.html

and load them unmodified onto my Arduino Mega, I am not able to do any Serial.print, nor will the Example work with an attached Servo.
Looking over the Code, it looks that your sample should be working without Changes on the predefined Pins, therefore I connected the RX "Channel 1" to Pin 5 and the Servo to Pin 8.
The Servo actually turns into neutral Position "1500" but stays there. As said, I am also not able to do any Serial.prints



But as said, I can probably work with your Example of the External Interrupts.

thanks,
Mario

DuaneB

Hi,
   I didn't see that you were using a Mega.

   From this link

http://arduino.cc/en/Hacking/PinMapping2560

it appears that int0 is digital pin 21 on the mega, try this as the PPM pin - not sure where you got pin 5 from ?

Duane B

rcarduino.blogspot.com
Read this
http://rcarduino.blogspot.com/2012/04/servo-problems-with-arduino-part-1.html
then watch this
http://rcarduino.blogspot.com/2012/04/servo-problems-part-2-demonstration.html

Rcarduino.blogspot.com

makru83

Hi,

sorry but I just dived into the arduino platform 2 Days ago, so I might have made some big mistakes,
but I guessed from your Code

Code: [Select]

// Assign your channel in pins
#define THROTTLE_IN_PIN 5
#define STEERING_IN_PIN 6
#define AUX_IN_PIN 7

// Assign your channel out pins
#define THROTTLE_OUT_PIN 8
#define STEERING_OUT_PIN 9
#define AUX_OUT_PIN 10


that Pin 5 would be the ppm signal in & Pin 8 would be ppm out to the Servo / Esc.
Looking at your Video, you used the same Pin's too - 5 & 8. Arduino Uno has it's int1 on Pin2.
Sample Code from: http://rcarduino.blogspot.co.at/2012/04/how-to-read-multiple-rc-channels-draft.html
Just to clarify, I am not using a PPM-Sum Signal, it's a single Channel PPM/PWM Signal. (Don't actually know if it is pwm or ppm now, as some say it's ppm)

Mario

DuaneB

Keeping it simple, the starting point should be this sketch, its the most basic and the starting point for all of the others -

http://rcarduino.blogspot.com/2012/01/how-to-read-rc-receiver-with.html

The sketch assumes you are using an UNO, to change it for a mega, change the following code

Code: [Select]

#define THROTTLE_SIGNAL_IN 0 // INTERRUPT 0 = DIGITAL PIN 2 - use the interrupt number in attachInterrupt
#define THROTTLE_SIGNAL_IN_PIN 2 // INTERRUPT 0 = DIGITAL PIN 2 - use the PIN number in digitalRead


To

Code: [Select]

#define THROTTLE_SIGNAL_IN 0 // INTERRUPT 0 = DIGITAL PIN 21 - use the interrupt number in attachInterrupt
#define THROTTLE_SIGNAL_IN_PIN 21 // INTERRUPT 0 = DIGITAL PIN 21 - use the PIN number in digitalRead


Try this with the signal wire from the RC Receiver connected to pin 21 of the mega.

Duane B
Read this
http://rcarduino.blogspot.com/2012/04/servo-problems-with-arduino-part-1.html
then watch this
http://rcarduino.blogspot.com/2012/04/servo-problems-part-2-demonstration.html

Rcarduino.blogspot.com

Go Up