|
|
View previous topic :: View next topic |
Author |
Message |
Ali_P
Joined: 18 Oct 2011 Posts: 7 Location: Pakistan
|
PIC to PIC communication (wireless) |
Posted: Tue Oct 18, 2011 7:44 am |
|
|
Hi everyone I'm making a project which involves two PICs (16F876A) to communicate using RS232 interface(half duplex). The Tx is attached with a remote controller (AN0,AN1,AN2) 3 channels of ADC with the PIC and sending a string of char (long int values) to the xbee and then on the Rx i have to drive 3 servos. I can transmit and receive the int values in the Rx using sisr, but processing them to drive the servos is problematic.
Although i have processed one channel (AN0) using atol() function, but if another channel is used then things go wrong. Help needed !
Code: |
//=============TX CODE===============
#include <16F876A.h>
#device adc=10
#include <stdio.h>
#include <STDLIB.H>
#include <string.h>
#fuses HS,NOWDT,PROTECT,PUT
#use delay(clock=20000000)
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7,ERRORS)
// TX CODE INVOLVING 3 VARIABLE ROLL,PITCH,YAW
void main(void)
{
unsigned long value1,sum1,value2,sum2,value3,sum3,ex=233;
unsigned long roll[10],pitch[10],yaw[10]; //average reading of 10 values from remote (analogue)
int out1,out2,out3;
char string [11];
char string2 [5];
SETUP_ADC_PORTS(ALL_ANALOG);
setup_adc( ADC_CLOCK_INTERNAL );
while(TRUE)
{
for (out1=0;out1<10;out1++) //pitch
{
set_adc_channel( 0 );
delay_us (100);
value1 = Read_ADC();
pitch[out1] = value1;
}
for (out1=0;out1<10;out1++)
sum1 += pitch[out1];
sum1 = sum1/10;
for (out2=0;out2<10;out2++) //roll
{
set_adc_channel( 1 );
delay_us (100);
value2 = Read_ADC();
roll[out2] = value2;
}
for (out2=0;out2<10;out2++)
sum2 += roll[out2];
sum2 = sum2/10;
for (out3=0;out3<10;out3++) //yaw
{
set_adc_channel( 2 );
delay_us (100);
value3 = Read_ADC();
yaw[out3] = value3;
}
for (out3=0;out3<10;out3++)
sum3 += yaw[out3];
sum3 = sum3/10;
sprintf(string,"*%lu",sum1); //converting long int value to string (pitch and roll)
sprintf(string2," #%lu",sum2); //* identifier for pitch # identifier for roll
strcat(string,string2); //using two values for testing only; combining two
//string to form single string to be transmitted
printf(string); //transmitting string (combined)
sum1 = 0; //clearing values
sum2 = 0;
sum3 = 0;
delay_ms(50);
}
}
//======================RX CODE================
#include <16F876A.h>
#device adc=10
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#fuses HS,NOWDT,NOPROTECT,NOLVP
#use delay(clock=20000000)
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7,ERRORS) // Stream for remote
#include <input.c>
#define LEFT_SERVO_PIN PIN_B4
#define RIGHT_SERVO_PIN PIN_B5
//sisr
//problem in converting data to long int values (although pitch is converted using atol())
// RX CODE TO READ AND REACT THE SERVOS, although im receiving data
//but i cannot initialize timer1 intrpt in the servos.c utility also and
#include <servos.c> // utility to drive 2 servos (not working with the rx code)
#define BUFFER_SIZE 10
BYTE buffer[BUFFER_SIZE];
BYTE next_in = 0;
BYTE next_out = 0;
init_servos();
#int_rda
void serial_isr() { //interupt service routine, serial
int t,v,x;
char pitch[5];
char roll[5] ;
unsigned long p_c=0, r_l=0;
buffer[next_in]=getc();
t=next_in;
if (buffer[0] == '*'); //string indentifier for pitch
{
for (x=0;x<3;x++)
pitch[0+x] = buffer[1+x];
}
if (buffer[4] == '#') //string identifier for roll
{
for(v=0;v<3;v++)
roll[0+v] = buffer[4+v]; //end of data
}
//converting data to int16
p_c = atol (pitch);
r_l = atol (roll);
printf ( "\r %lu ", p_c);
printf ( " %lu ", r_l);
p_c = 0; // clearing data
r_l = 0;
next_in=(next_in+1) % BUFFER_SIZE;
if(next_in==next_out)
next_in=t;// Buffer full !!
}
#define bkbhit (next_in!=next_out)
BYTE bgetc() {
BYTE c;
while(!bkbhit) ;
c=buffer[next_out];
next_out=(next_out+1) % BUFFER_SIZE;
return(c);
}
void main() {
enable_interrupts(int_rda);
#if defined(__PCD__)
enable_interrupts(intr_global);
#else
enable_interrupts(global);
#endif
printf("\r\n\Running...\r\n");
do {
delay_ms(50);
while(bkbhit)
putc( bgetc() );
} while (TRUE);
}
|
The problem is also for the driving of servos. Can anyone please suggest a code for Rx receiving with servo drive?
Thank you very much. _________________ Ali |
|
|
Gabriel
Joined: 03 Aug 2009 Posts: 1067 Location: Panama
|
|
Posted: Tue Oct 18, 2011 8:27 am |
|
|
I think you are trying to do too many things a the same time...
Start small.
First, read one ADC channel, and controll a Servo with that data, on the SAME PIC.
Second, read one ADC channel, and send the data to another PIC through WIRED serial, and control the servo using the data on the second pic.
Third, same as above but replace wired serial with Wireless module.
Once you got that working... you can expand to more servos.
The 16f876a has 2 PWM channels... you are trying to control 3 servos... thus you need a Software PWM routine for the third servo, or all three.
Your PWM needs to be set to the right FREQUENCY... which may vary among servo manufacturers slighly... if memory is right its about 1ms pulse max rotation to one side, and 2ms pulse max rotation to the other side... with a center position of 1.5ms ... and refresh rate should be every 20ms.... (old/non-digital futaba at least... correct me if im wrong).
Your adc channel reading should control the DUTY CYCLE only.
You might need to scale the value before feeding it to the duty cycle control function.
Start small. Test code blocks rather a whole program.
PIC#1: read adc values, and print to serial.
PIC#2: read serial buffer, adjust pwm duty cycles.
From your variable names... i see you might be trying to build you own RC plane remote...Cool.
I am more of a Oldschool U/C plane guy.
I don't think you need to average that many readings ... if any at all actually... as you are constanly moving your fingers thus changing the ADC values... (if you are making a remote control for a plane).
Also... if you are going to average values... take 10 readings, eliminate the highest and lowest, and then do a bitshift x8.... its faster check out the filter threads here. _________________ CCS PCM 5.078 & CCS PCH 5.093 |
|
|
Gabriel
Joined: 03 Aug 2009 Posts: 1067 Location: Panama
|
|
Posted: Tue Oct 18, 2011 8:39 am |
|
|
Furthermore:
Code: | sprintf(string,"*%lu",sum1); //converting long int value to string (pitch and roll)
sprintf(string2," #%lu",sum2); //* identifier for pitch # identifier for roll
strcat(string,string2); //using two values for testing only; combining two
//string to form single string to be transmitted
printf(string); //transmitting string (combined) |
Why are you doing this?... just send the 3 ADC bytes in a row, as hex values...
no need to combine them into anything....
You need to have a circular buffer that holds 4 characters... (Start identifier,roll, pitch, yaw).
Your receiver checks this buffer constantly... if the buffer contains all 4 bytes in the right order, save them in their appropiate duty cycle variables, and clear the buffer.... repeat.
Your Serial ISR is HUGE.... it should only save data on a buffer... and process everthing on the main function.
IRS=Get in, service, Get out - QUICKLY. _________________ CCS PCM 5.078 & CCS PCH 5.093 |
|
|
asmboy
Joined: 20 Nov 2007 Posts: 2128 Location: albany ny
|
|
Posted: Tue Oct 18, 2011 5:45 pm |
|
|
Post servos.c
Otherwise I have to take your word for there being no
unintended function interdependence. |
|
|
Ali_P
Joined: 18 Oct 2011 Posts: 7 Location: Pakistan
|
|
Posted: Tue Oct 18, 2011 9:49 pm |
|
|
Thank you Gabriel for your reply yes you guessed it right, I'm a R/C plane guy
Well the problem was that I was previously sending int16 values directly, using printf function,
Code: |
printf ("*%lu,%lu,%lu",pitch,roll.yaw);
|
I was able to receive all three values but was not able to process/apply mathematical operations because it was just mere characters and atol() function was not working. But then I tried sprintf function which changes the int format to a string of char to be sent from Tx, that worked and I was able to process data from the buffer[], atol () was working then, the problem came when the 2nd variable arrived.
Do I have to change the #rs232 to give hex directly? I'll try that.
I did first in the main(), but I don't know it was not working somehow?
I'm new to ccs c, could you suggest me a code for driving servos using software pwm and receiving data ? That will be helpful really.
Yes you are right but the servos data: high time: 1-2ms freq:50/60Hz/20ms Pulse
I have yet another variable "throttle" I'm just avoiding it for a time being, first let the 3 variable run
I know my isr is huge but don't have any choice then. _________________ Ali |
|
|
Gabriel
Joined: 03 Aug 2009 Posts: 1067 Location: Panama
|
|
Posted: Wed Oct 19, 2011 7:56 am |
|
|
PSEUDO Code.....
Code: | Void Main()
{
Set_ADC_Channel(0); //set ADC Channel
Delay_US(20); //small delay for sample capacitor to charge
Elevator=Read_ADC(); //read and store value
Set_ADC_Channel(1);
Delay_US(20);
Alerons=Read_ADC();
Set_ADC_Channel(2);
Delay_US(20);
Rudder=Read_ADC();
Printf("*"); // start character (ascii)
Printf(Elevator); // straight hex...
Printf(Alerons);
Printf(Rudder);
} |
... if you print your values to terminal, if your analog readings are:
elevator=0x31
Aleron=0x32
rudder=0x33
you will see "*123" thats because your raw hex values are the same as the ascii values for 1,2&3....hyperterminal wont know the diference...
us SIOW.... it shows you both hex value and ascii....
the same applys for other values.... i think this is why you thought you needed to convert your values to somthing else and used Sprint
you dont need much more than that on your Transmitter...
asuming you are using 8bit ADC, with a variable resistor on each Analog input...
check out the Printf details... you can print all 4 characters in a single line... i just used 4 separate lines to be clearer.
on you receiver end... things are a bit different...
you need to scale the received values for elevator, alerons, and rudder properly....
your servos should be centered when your values for Elevator, aleron and rudder are 0x7F (Decimal 127)
read up on Circular buffers.... (hint: this should be the only thing in your ISR)
G. _________________ CCS PCM 5.078 & CCS PCH 5.093 |
|
|
Gabriel
Joined: 03 Aug 2009 Posts: 1067 Location: Panama
|
|
Posted: Wed Oct 19, 2011 8:01 am |
|
|
one last thing...
I believe you can update servos faster than 20ms. They just use more current because they are constantly updating their position.
You could set up a square wave with a period of 3ms.
50% duty cycle will be 1.5ms which would be Center position. _________________ CCS PCM 5.078 & CCS PCH 5.093 |
|
|
Ali_P
Joined: 18 Oct 2011 Posts: 7 Location: Pakistan
|
|
Posted: Thu Oct 20, 2011 1:26 am |
|
|
Thank you Gabriel for your reply. Actually my problem is mostly solved You are right about sending hex values, and HT was not able to distinguish b/w the raw hex and char values (1,2,3) I sent. I have almost done my both rx and tx coding, the rx problem is mostly solved. Actually I got help in it by a sample program which ran 6 servo from the usart slave. I'm using 10 bit ADC, hmm will definitely try updating servos faster than 20ms period, but I guess this will cause jitter among the servos ?
The other thing was, as the HW PWM of pic minimum freq is 244hz it cannot be used as R/C servo use, limited for motor control use (I don't know if anyone has added a frequency divider at the HW PWM for 50Hz servo control? That would be worth a try for me). Now I am relying on software pwm and timer0 interrupt, things in the simulation seems working, though I have already sent and received data using Xbees wireless mod earlier. I have scaled 10 bit ADC to have 50 values (servo positions: 1023/50=20), that will give me a center position of 25 (1.5ms)(0-----25-----50). This scaling should also work well for throttle position (the fourth channel). I'll be uploading my Tx/Rx code shortly. There was a problem with controlling more than 2 servos, but I'll try to fix it.
Thanks alot. _________________ Ali |
|
|
Gabriel
Joined: 03 Aug 2009 Posts: 1067 Location: Panama
|
|
Posted: Thu Oct 20, 2011 10:00 am |
|
|
I just saw the servo code posted on the library. I immediately thought of your problem.
Actually you don't need to do anything now.
Just copy that program in your RX... add a RF receiver, and make your TX send the appropriate strings... you have a six channel remote!
Ailerons, elevator, rudder, throttle, flaps and gears!
Updating servos faster will cause jitter unless the position pulse is exactly the same and the internal position trimpot reads exactly the same.... which will never happen IMO... which means Jitter.
But you do gain Torque when the servo is updating its position the little motor inside is on.. applying force on the control surfaces its attached.
If you update every 20ms as required you have ~18ms of the motor being off... thus no force being applied to the control surfaces its attached to.
Digital servos use this to their advantage.
Seems you have all you need. _________________ CCS PCM 5.078 & CCS PCH 5.093 |
|
|
olivier
Joined: 08 Apr 2010 Posts: 11
|
this is very excellent info exchange |
Posted: Wed Oct 26, 2011 6:34 pm |
|
|
Gabriel and Ali,
thank you very much for posting info. I am in the process of doing something similar to your and I don't know where to start. I bought an small RC plan other day and want to modify it but still thinking of what to do. You both give me courage to start.
thanks. Hope that I get somewhere in near future |
|
|
Ali_P
Joined: 18 Oct 2011 Posts: 7 Location: Pakistan
|
|
Posted: Tue Nov 01, 2011 8:24 am |
|
|
Olivier, good luck for your project. I'll be posting my tx/rx code shortly as
soon as I get time, it may help you and others as well, and let us be informed too.
Regards. _________________ Ali |
|
|
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|