Pages: [1] 2   Go Down
Author Topic: Timing Problem with Lanc & pulsein  (Read 1333 times)
0 Members and 1 Guest are viewing this topic.
Offline Offline
Newbie
*
Karma: 0
Posts: 9
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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:
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:


#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
}




« Last Edit: January 25, 2013, 07:54:45 am by makru83 » Logged

UK
Offline Offline
Shannon Member
****
Karma: 223
Posts: 12630
-
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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.
Logged

I only provide help via the forum - please do not contact me for private consultancy.

Offline Offline
Newbie
*
Karma: 0
Posts: 9
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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.
Logged

Global Moderator
Offline Offline
Brattain Member
*****
Karma: 498
Posts: 19065
Lua rocks!
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Code:
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
Logged


Temple, Texas
Offline Offline
Sr. Member
****
Karma: 14
Posts: 361
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Code:
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
Logged

Global Moderator
Offline Offline
Brattain Member
*****
Karma: 498
Posts: 19065
Lua rocks!
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

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).
Logged


Temple, Texas
Offline Offline
Sr. Member
****
Karma: 14
Posts: 361
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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 smiley

Cheers,
John
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 9
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 9
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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
Logged

Dubai, UAE
Offline Offline
Edison Member
*
Karma: 22
Posts: 1675
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

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:
   if(bUpdateFlags & THROTTLE_FLAG)
    {
      unThrottleIn = unThrottleInShared;
      // Serial.println(unThrottleIn);
    }
 
    if(bUpdateFlags & STEERING_FLAG)
    {
      unSteeringIn = unSteeringInShared;
    }
 
    if(bUpdateFlags & AUX_FLAG)
    {
      unAuxIn = unAuxInShared;
    }

Duane B
Logged


Offline Offline
Newbie
*
Karma: 0
Posts: 9
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 9
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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
Logged

Dubai, UAE
Offline Offline
Edison Member
*
Karma: 22
Posts: 1675
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

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
Logged


Offline Offline
Newbie
*
Karma: 0
Posts: 9
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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:
// 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
Logged

Dubai, UAE
Offline Offline
Edison Member
*
Karma: 22
Posts: 1675
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

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:
#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:
#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
Logged


Pages: [1] 2   Go Up
Jump to: