Showing posts with label programming. Show all posts
Showing posts with label programming. Show all posts

Friday, June 14, 2013

32. How to #monitor the #Voltage and #Mode of #UAV Battery

We replaced some variables in ardustation programming in telemtry.c and then monitored it in HappyKill More GCS program in the Serial Data:

// The Ardupilot GroundStation protocol is mostly documented here:
//    http://diydrones.com/profiles/blogs/ardupilot-telemetry-protocol

///////////////////////// battery health testing code
if((udb_analogInputs[0].value<batt_min_value) && (mode ==3))
{
BATT_FLAG =1;
}
//////////////////////////////////////////////////////

if(mode<3)
{
BATT_FLAG =0;
}


if (udb_heartbeat_counter % 40 == 0)  // Every 8 runs (5 heartbeat counts per 8Hz)
{

serial_output("!!!LAT:%li,LON:%li,SPD:%.2f,CRT:%.2f,ALT:%li,ALH:%i,CRS:%.2f,BER:%i,WPN:%i,DS

T:%i,BTV:%.2f***\r\n"
 "+++THH:%i,RLL:%li,PCH:%li,STT:%i,***\r\n",
lat_gps.WW / 10 , long_gps.WW / 10 , (float)(sog_gps.BB / 100.0), 

(float)(climb_gps.BB / 100.0),
(alt_sl_gps.WW - alt_origin.WW) / 100, desiredHeight, 

(float)(cog_gps.BB / 100.0), desired_dir_deg,
waypointIndex, udb_analogInputs[0].value, (float)(voltage_milis.BB / 

100.0), 
(int16_t)((udb_pwOut[THROTTLE_OUTPUT_CHANNEL] - 

udb_pwTrim[THROTTLE_OUTPUT_CHANNEL])/20),
earth_roll, earth_pitch,
(BATT_FLAG+1) // So that flag is not discarded if it is 0
) ;
}
else if (udb_heartbeat_counter % 10 == 0)  // Every 2 runs (5 heartbeat counts per 

8Hz)
{
serial_output("+++THH:%i,RLL:%li,PCH:%li,STT:%i,***\r\n",
(int16_t)((udb_pwOut[THROTTLE_OUTPUT_CHANNEL] - 

udb_pwTrim[THROTTLE_OUTPUT_CHANNEL])/20),
earth_roll, earth_pitch,
mode
) ;
}
return ;
}

These can be viewed in the serial data screen of the Happy Kill More GCS program.

Friday, May 31, 2013

31. Further modifications in #Software for Battery Monitoring

We realized that by merely doing the flag int_flightplan 1 in telemetry.c will not direct our program in Return To Land Mode. We discovered in the programming that RTL mode can only be achieved when two conditions are met:
  1. Program/drone is in Auto-Pilot Mode, for this we need our gps to be locked &
  2. failSafePulses or the pulses coming from the transmitter are 0 i.e. we have lost the radio signal
This can be seen from the following program in states.c file:

/////// Come home state, entered when the radio signal is lost, and gps is locked.
void ent_returnS()
{
flags._.GPS_steering = 1 ;
flags._.pitch_feedback = 1 ;
flags._.altitude_hold_throttle = (ALTITUDEHOLD_WAYPOINT == AH_FULL) ;
flags._.altitude_hold_pitch = (ALTITUDEHOLD_WAYPOINT == AH_FULL || ALTITUDEHOLD_WAYPOINT == AH_PITCH_ONLY) ;
#if ( FAILSAFE_TYPE == FAILSAFE_RTL )
init_flightplan( 1 ) ;
#elif ( FAILSAFE_TYPE == FAILSAFE_MAIN_FLIGHTPLAN )
if ( stateS != &waypointS )
{
init_flightplan( 0 ) ; // Only reset non-rtl waypoints if not already following waypoints
}

The condition to control the failSafePulses is mentioned in the background.c file:


if ( ( failSafePulses == 0 ) || ( noisePulses > MAX_NOISE_RATE ) )
{
if (udb_flags._.radio_on == 1) {
udb_flags._.radio_on = 0 ;
udb_callback_radio_did_turn_off() ;
}
LED_GREEN = LED_OFF ;
noisePulses = 0 ; // reset count of noise pulses
}
else
{
udb_flags._.radio_on = 1 ;
LED_GREEN = LED_ON ;
}
failSafePulses = 0 ;
}

Mode is mentioned in telemetry.c file and can be controlled from the receiver:

void serial_output_8hz( void )
{
uint16_t mode ;
struct relative2D matrix_accum ;
union longbbbb accum ;
int16_t desired_dir_deg ;  // desired_dir converted to a bearing (0-360)
int32_t earth_pitch ; // pitch in binary angles ( 0-255 is 360 degreres)
int32_t earth_roll ; // roll of the plane with respect to earth frame
//int32_t earth_yaw ; // yaw with respect to earth frame
accum.WW  = ( desired_dir * BYTECIR_TO_DEGREE ) + 32768 ;
desired_dir_deg  = accum._.W1 - 90 ; // "Convert UAV DevBoad Earth" to Compass Bearing
if ( desired_dir_deg < 0 ) desired_dir_deg += 360 ; 

if (flags._.GPS_steering == 0 && flags._.pitch_feedback == 0)
mode = 1 ;
else if (flags._.GPS_steering == 0 && flags._.pitch_feedback == 1)
mode = 2 ;
else if (flags._.GPS_steering == 1 && flags._.pitch_feedback == 1 && udb_flags._.radio_on == 1)
mode = 3 ;
else if (flags._.GPS_steering == 1 && flags._.pitch_feedback == 1 && udb_flags._.radio_on == 0)
mode = 0 ;
else
mode = 99 ; // Unknown
Hence to meet the above two conditions we created a flag BATT_FLAG which we defined in telemetry.c and declared as extern in defines.h file. When BATT_FLAG is set to 1 (in telemetry.c file) the int_flightplan  will become 0 (in background.c file) and thus enable out RTL Mode.

In telemetry.c file:

#define batt_min_value 16000
int BATT_FLAG =0;

if((udb_analogInputs[0].value<batt_min_value) && (mode = =3)) // if battery value goes below 16000 and is in Auto-Pilot Mode 
{
BATT_FLAG =1;
}
//////////////////////////////////////////////////////

if(mode<3) // if in Manual or Stabilized Mode then will never make BATT_FLAG 1 and int_flightplan 0
{
BATT_FLAG =0;
}

In background.c file:

// check to see if at least one valid pulse has been received,
// and also that the noise rate has not been exceeded
if(BATT_FLAG = =1)
{
failSafePulses =0;
}
if ( ( failSafePulses = = 0 ) || ( noisePulses > MAX_NOISE_RATE ) )
{
if (udb_flags._.radio_on == 1) {
udb_flags._.radio_on = 0 ;
udb_callback_radio_did_turn_off() ;
}
LED_GREEN = LED_OFF ;
noisePulses = 0 ; // reset count of noise pulses
}
else
{
udb_flags._.radio_on = 1 ;
LED_GREEN = LED_ON ;
}
failSafePulses = 0 ;
}

Here if we change from Auto-Pilot Mode to any other Mode then our BATT_FLAG will become 0 and our failSafePulses will start receiving real time signals from the transmitter on the drone.

How we monitored our changes, I will mention that in my next post.

Thursday, May 30, 2013

29. Battery Monitoring Circuit for #UAV - #Software

Now we are working to create a program where we will guide our aircraft in case of insufficient battery. For this purpose we have added a voltage divider circuit, using 1k (R1) and .33k (R2) ohm resistances, to our existing UDB4 board and made the following changes in the telemetry.c file: 

#define batt_min_value 88

///////////////////////// battery health testing code
if(udb_analogInputs[0].value<batt_min_value)
{
init_flightplan( 1 );
}
//////////////////////////////////////////////////////

Here udb_analogInputs[0].value is real-time or current value that comes on one of our Analog pins of PIC controller (from AN15 to AN 18). If it goes below a certain value (for 3S LIPO battery - below 3.6 Volts each or net 10.8 Volts) then the program will switch to Return to Land (RTL) mode. 

In order to read what exact value that will come at full charge i.e. 12.48 Volts on the Analog Pins we replaced our diff in telemetry.c with udb_analogInputs[0].value so that we may set our batt_min_value:

// The Ardupilot GroundStation protocol is mostly documented here:
//    http://diydrones.com/profiles/blogs/ardupilot-telemetry-protocol
///////////////////////// battery health testing code
if(udb_analogInputs[0].value<batt_min_value)
{
init_flightplan( 1 );
}
//////////////////////////////////////////////////////


if (udb_heartbeat_counter % 40 == 0)  // Every 8 runs (5 heartbeat counts per 8Hz)
{
serial_output("!!!LAT:%li,LON:%li,SPD:%.2f,CRT:%.2f,ALT:%li,ALH:%i,CRS:%.2f,BER:%i,WPN:%i,DST:%i,BTV:%.2f***\r\n"
 "+++THH:%i,RLL:%li,PCH:%li,STT:%i,***\r\n",
lat_gps.WW / 10 , long_gps.WW / 10 , (float)(sog_gps.BB / 100.0), (float)(climb_gps.BB / 100.0),
(alt_sl_gps.WW - alt_origin.WW) / 100, desiredHeight, (float)(cog_gps.BB / 100.0), desired_dir_deg,
waypointIndex, udb_analogInputs[0].value, (float)(voltage_milis.BB / 100.0), 
(int16_t)((udb_pwOut[THROTTLE_OUTPUT_CHANNEL] - udb_pwTrim[THROTTLE_OUTPUT_CHANNEL])/20),
earth_roll, earth_pitch,
mode
) ;
}

We will be able to monitor it on Happy Killmore GCS software as we did our diff variable earlier (Switch-out from Auto-Pilot Mode : Another function for #UAV)

Also, if init_flightplan( 1 ); is set to one as here, then we will be able to switch to RTL mode or else not as we can see in the flightplan-waypoints.c file:

// In the future, we could include more than 2 waypoint sets...
// flightplanNum is 0 for main waypoints, and 1 for RTL waypoints
void init_flightplan ( int16_t flightplanNum )
{
if ( flightplanNum == 1 ) // RTL waypoint set
{
currentWaypointSet = (struct waypointDef*)rtlWaypoints ;
numPointsInCurrentSet = NUMBER_RTL_POINTS ;
}
else if ( flightplanNum == 0 ) // Main waypoint set
{
currentWaypointSet = (struct waypointDef*)waypoints ;
    numPointsInCurrentSet = NUMBER_POINTS ;
    }

Monday, May 20, 2013

24. Update Switch-out from Auto-Pilot Mode

1. In order to receive indication physically on Dev Board that we have switched out from Auto-Pilot Mode  we use the Blue LED (declared in ConfigUDB4.h file) present on it.

So in servoMix.c file we made the following changes:

void startupfuntion(void)
{
if (startflag == 0)
{
startflag =1;
currentvalue = mychannelvalue;
}
}

void checkmode(void)
{
diff = mychannelvalue-currentvalue;
if((diff>100) || (diff<-100))
//if (diff==1)
{
currentvalue = mychannelvalue;
if(LED_BLUE == 0)
LED_BLUE = 1;
else
LED_BLUE = 0;
if (flags._.GPS_steering == 1 && flags._.pitch_feedback == 1 && udb_flags._.radio_on == 1)
            {
 next_waypoint();
              currentvalue = mychannelvalue;
}
}
}

2. Also we declared our int variable - diff in defines.h file so that it may be used for other purposes too, and removed its static declaration:

extern int diff; //extern helps to access a variable/function defined in a single file and makes it available for all the other files in our program

3. In order to check what difference in servoMix.c file (diff) is coming in the - diff = mychannelvalue-currentvalue;, so that we may check whether vale in our condition - if((diff>100) || (diff<-100)) is within range or not. So we opened telemetry.c file and did the following changes:


// Yaw
// Earth Frame of Reference
// Ardustation does not use yaw in degrees
// matrix_accum.x = rmat[4] ;
// matrix_accum.y = rmat[1] ;
// earth_yaw = rect_to_polar(&matrix_accum) ; // binary angle (0 - 256 = 360 degrees)
// earth_yaw = (earth_yaw * BYTECIR_TO_DEGREE) >> 16 ; // switch polarity, convert to -180 - 180 degrees
// The Ardupilot GroundStation protocol is mostly documented here:
//    http://diydrones.com/profiles/blogs/ardupilot-telemetry-protocol
if (udb_heartbeat_counter % 40 == 0)  // Every 8 runs (5 heartbeat counts per 8Hz)
{
serial_output("!!!LAT:%li,LON:%li,SPD:%.2f,CRT:%.2f,ALT:%li,ALH:%i,CRS:%.2f,BER:%i,WPN:%i,DST:%i,BTV:%.2f***\r\n"
 "+++THH:%i,RLL:%li,PCH:%li,STT:%i,***\r\n",
lat_gps.WW / 10 , long_gps.WW / 10 , (float)(sog_gps.BB / 100.0), (float)(climb_gps.BB / 100.0),
(alt_sl_gps.WW - alt_origin.WW) / 100, desiredHeight, (float)(cog_gps.BB / 100.0), desired_dir_deg,
waypointIndex, diff, (float)(voltage_milis.BB / 100.0), 
(int16_t)((udb_pwOut[THROTTLE_OUTPUT_CHANNEL] - udb_pwTrim[THROTTLE_OUTPUT_CHANNEL])/20),
earth_roll, earth_pitch,
mode
) ;
}
else if (udb_heartbeat_counter % 10 == 0)  // Every 2 runs (5 heartbeat counts per 8Hz)
{
serial_output("+++THH:%i,RLL:%li,PCH:%li,STT:%i,***\r\n",
(int16_t)((udb_pwOut[THROTTLE_OUTPUT_CHANNEL] - udb_pwTrim[THROTTLE_OUTPUT_CHANNEL])/20),
earth_roll, earth_pitch,
mode
) ;
}
return ;
}

We changed to diff from tofinish_line so that in Realterm Software we may see the diff value coming and set our condition accordingly.


4. And finally: What is the meaning of diff?

Diff is the decimal difference in milliseconds that comes between the up and down position of the switch we will use, on the transmitter, to switch-out from Auto-Pilot mode.

Saturday, May 18, 2013

23. Switch-out from Auto-Pilot Mode : Another function for #UAV

In our previous programming segment (16. Auto Take-Off and Auto-Landing programming of the #UAV and 6. How are we going to build a more stable Loiter program? - The Idea.) we had made Auto-Pilot program and also an Auto-take off and Auto-landing program for our U.A.V.

Then we thought more. What if due to some reason we want our U.A.V to move out of the Auto-Pilot mode towards the next desired waypoint (like sometimes we may want a quick auto-landing or surveillance of some other area)?. Hence we came up with another addition to the whole program we had made so far.

We decided to use one of the 2 output channels left (rest 5 out total 7 are used for Aileron, Throttle, rudder, Elevator and Mode) of the UDB Devboard to receive a signal from our transmitter so that whenever we change the position of the switch from its initial position (at start-up) i.e. from up to down or down to up, our  DevBoard will switch out of the Auto-Pilot mode.

So in order form a logic, we first tried a simple C program in which if we press any letter different from the one we have put in the memory (through scanf function), then it will display a certain message and if we press the same letter as in the memory then another certain message will appear:


#include <stdio.h>
#include <conio.h>

int main()

{
char in, oc;
in = 'j';
printf("Testing code");
while(1)
{
          printf("input pls");
          oc=getch(); // so that we do not have to press enter every-time we enter something on screen
          //scanf("%c", &oc);
          //printf("yes wrkin");
          if (oc!=in)
             {
                     printf("Matched");
                    if ( (oc == 'j')||(oc == 'h'))
                       {
                                printf("moved to next waypoint");
                                in = oc;
                       }
             }
}
   getch();
   return 0;
}

To implement this idea we went into the servoMix.c file of our program and edited the following:

static int mychannelvalue =0;
static char startflag =0; // will be used to check position of switch at sart-up only once
void startupfuntion(void); //to store the current position of the switch
void checkmode (void); // to check the position of the switch, if changed then switch-out of Auto-Pilot mode
static int currentvalue =0;

// Helicopter airframe
// Mix half of roll_control and half of pitch_control into aileron channels
// Mix full pitch_control into elevator
// Ignore waggle for now
#if ( AIRFRAME_TYPE == AIRFRAME_HELI )
temp = pwManual[AILERON_INPUT_CHANNEL] +
REVERSE_IF_NEEDED(AILERON_CHANNEL_REVERSED, roll_control/2 +

pitch_control/2) ;
udb_pwOut[AILERON_OUTPUT_CHANNEL] = udb_servo_pulsesat( temp ) ;

temp = pwManual[ELEVATOR_INPUT_CHANNEL] +

REVERSE_IF_NEEDED(ELEVATOR_CHANNEL_REVERSED, pitch_control) ;
udb_pwOut[ELEVATOR_OUTPUT_CHANNEL] = udb_servo_pulsesat( temp ) ;

temp = pwManual[AILERON_SECONDARY_OUTPUT_CHANNEL] +
REVERSE_IF_NEEDED(AILERON_SECONDARY_CHANNEL_REVERSED,

-roll_control/2 + pitch_control/2) ;
udb_pwOut[AILERON_SECONDARY_OUTPUT_CHANNEL] = temp ;

temp = pwManual[RUDDER_INPUT_CHANNEL] /*+

REVERSE_IF_NEEDED(RUDDER_CHANNEL_REVERSED, yaw_control)*/ ;
udb_pwOut[RUDDER_OUTPUT_CHANNEL] = udb_servo_pulsesat( temp ) ;

if ( pwManual[THROTTLE_INPUT_CHANNEL] == 0 )
{
udb_pwOut[THROTTLE_OUTPUT_CHANNEL] = 0 ;
}
else
{
temp = pwManual[THROTTLE_INPUT_CHANNEL] +

REVERSE_IF_NEEDED(THROTTLE_CHANNEL_REVERSED, throttle_control) ;
udb_pwOut[THROTTLE_OUTPUT_CHANNEL] = udb_servo_pulsesat( temp ) ;
}
#endif
mychannelvalue = udb_servo_pulsesat( pwManual[PASSTHROUGH_A_INPUT_CHANNEL] )

;

startupfuntion();
checkmode();
// next_waypoint();      

udb_pwOut[PASSTHROUGH_A_OUTPUT_CHANNEL] = udb_servo_pulsesat(

pwManual[PASSTHROUGH_A_INPUT_CHANNEL] ) ;
udb_pwOut[PASSTHROUGH_B_OUTPUT_CHANNEL] = udb_servo_pulsesat(

pwManual[PASSTHROUGH_B_INPUT_CHANNEL] ) ;
udb_pwOut[PASSTHROUGH_C_OUTPUT_CHANNEL] = udb_servo_pulsesat(

pwManual[PASSTHROUGH_C_INPUT_CHANNEL] ) ;
udb_pwOut[PASSTHROUGH_D_OUTPUT_CHANNEL] = udb_servo_pulsesat(

pwManual[PASSTHROUGH_D_INPUT_CHANNEL] ) ;
}

void cameraServoMix( void )
{
int32_t temp ;
int16_t pwManual[NUM_INPUTS+1] ;

// If radio is off, use udb_pwTrim values instead of the udb_pwIn values
for (temp = 0; temp <= NUM_INPUTS; temp++)
if (udb_flags._.radio_on)
pwManual[temp] = udb_pwIn[temp];
else
pwManual[temp] = udb_pwTrim[temp];

temp = ( pwManual[CAMERA_PITCH_INPUT_CHANNEL] - 3000 ) +

REVERSE_IF_NEEDED(CAMERA_PITCH_CHANNEL_REVERSED,
cam_pitch_servo_pwm_delta ) ;
temp = cam_pitchServoLimit(temp) ;
udb_pwOut[CAMERA_PITCH_OUTPUT_CHANNEL] = udb_servo_pulsesat( temp + 3000 ) ;

temp = ( pwManual[CAMERA_YAW_INPUT_CHANNEL] - 3000 ) +

REVERSE_IF_NEEDED(CAMERA_YAW_CHANNEL_REVERSED,
cam_yaw_servo_pwm_delta ) ;
temp = cam_yawServoLimit(temp) ;
udb_pwOut[CAMERA_YAW_OUTPUT_CHANNEL] = udb_servo_pulsesat( temp + 3000 ) ;
}

void startupfuntion(void)
{
if (startflag == 0)
{
startflag =1;
currentvalue = mychannelvalue;
}
}

void checkmode(void)
{
int diff;
diff = mychannelvalue-currentvalue;
 if(diff>100 || diff<-100)
{
             if (flags._.GPS_steering == 1 && flags._.pitch_feedback == 1 && udb_flags._.radio_on == 1) //to check if in Auto-Pilot mode, else will never go for the function, make sure only Auto-Pilot switch-out
            {
 next_waypoint();
                           currentvalue = mychannelvalue;
}
}
}