Skip to content
Snippets Groups Projects
manual_assist_main.c 11 KiB
Newer Older
dmlarson's avatar
dmlarson committed
//system include
#include <stdlib.h>
#include <stdio.h>
#include <signal.h>

//user includes
#include "joystick.h"
#include "frontend_common.h"
#include "frontend_tracker.h"
#include "frontend_param.h"

//Path to the joystick device
#define JOYSTICK_PATH "/dev/input/js0"

//Variables used to calculate the allowed setpoint change per iteration of the main loop
#define WAIT_TIME_USEC 5000
#define METER_P_SEC 0.66f
#define SETPOINT_THRESHOLD (((float) WAIT_TIME_USEC) / 1000000) * METER_P_SEC

//Variables used to update setpoints through the frontend
#define QUAD_X 9
#define QUAD_Y 10
#define QUAD_Alt 11
#define QUAD_Yaw 12
#define PARAM 0

//Variables that define the bounds that the user can fly between
#define MAX_Y 1.2f
#define MIN_Y -1.2f
#define MAX_X 1.5f
#define MIN_X -1.5f
#define MAX_Alt -0.7f
#define MIN_Alt -1.5f
#define MAX_Yaw 160f
#define MIN_Yaw -160f


#define DELTA 0.05f
#define MIDPOINT 0.5f

//Checks whether a value from the joystick is recognized as a midpoint and hence the quad will not move
#define isMidPoint(value) (value < (MIDPOINT + DELTA) && value > (MIDPOINT - DELTA)) ? 1 : 0

int exit_flag = 0;

//Connection to backend
struct backend_conn *conn = NULL;
/**
 * Handler function for exit signals. This allows the backend to properly close.
 */
static void sig_exit_handler(int s) {
    printf("Exiting with condition %d\n\r", s);
    exit_flag = 1;
}

//Adjusts the setpoints so that there is not a jump once the value is not recognized
float adjustJoystickValue(float value) {
    if (value > 0.5f) {
        return value - DELTA;
    }
    return value + DELTA;
}

int main(int argc, char *argv[]) {
    //Pointer to joystick object
    struct joystick *js;

    //Struct containing VRPN information
    struct frontend_tracker_data td;
    
    //Struct containing setpoint update information for frontend
    struct frontend_param_data pd;

    //Whether or not the quad has taken off
    int takeoff = 0;

    //Temporary status variable used to hold return values
    int status = 0;

    //Whether or not we have gotten the current position of the quad upon start of user control
    int initialize_setpoint = 0;

    //Joystick channel values
    float js_throttle, js_yaw, js_pitch, js_roll, js_left_switch, js_right_switch;
    
    //Quad setpoint related variables (Note - quad_Alt is Z)
    float quad_X, quad_Y, quad_Alt, quad_yaw;

    float temp_setpoint = 0;
    //Quad setpoint changed variables
    int quad_X_modified, quad_Y_modified, quad_Alt_modified, quad_yaw_modified;
    quad_X_modified = quad_Y_modified = quad_Alt_modified = quad_yaw_modified = 0;

    //Setup exit signals
    signal(SIGINT, sig_exit_handler);
    signal(SIGABRT, sig_exit_handler);
    signal(SIGQUIT, sig_exit_handler);
    signal(SIGTERM, sig_exit_handler);

    //Initialize joystick
    js = joystick_init(JOYSTICK_PATH, JS_NONBLOCKING);
    if (!js) {
        printf("Aborting because joystick did not initialize correctly...\n");
        return 1;
    }

    //Prints out info about the device connected
    joystick_info(js);

    //Create a connection to the backend
    conn = ucart_backendConnect();
    if (conn == NULL) {
        printf("Failed to connect to backend, exitting...\r\n");
        joystick_destroy(js);
        return 1;
    }
    printf("Manual Assist Mode Starting...\r\n");

    printf("Setpoint Threshold = %f\r\n", SETPOINT_THRESHOLD);
    
    while (!exit_flag) {
        //Read to update values
        if (joystick_read(js) == 1) {
            //Get values from joystick
            js_throttle = joystick_get_throttle(js);
            //NOTE - yaw control is not yet supported
            js_yaw = joystick_get_yaw(js);
            js_pitch = joystick_get_pitch(js);
            js_roll = joystick_get_roll(js);
            js_left_switch = joystick_get_left_switch(js);
            js_right_switch = joystick_get_right_switch(js);

            //Print debug info using the left switch on the controller
            if (js_left_switch > 0.5f) {
                printf("Throttle: %f\r\n", js_throttle);
                printf("Yaw: %f\r\n", js_yaw);
                printf("Pitch: %f\r\n", js_pitch);
                printf("Roll: %f\r\n", js_roll);
                printf("Left Switch: %f\r\n", js_left_switch);
                printf("Right Switch: %f\r\n", js_right_switch);
            }

            //Right switch controls takeoff and touch down
            if (!takeoff && js_right_switch > .5) {
                //TODO - may not want to use system calls...
                //call takeoff script
                printf("TAKING OFF...\r\n");
                status = system("./scripts/take_off.sh");
                if (status == -1) {
                    printf("System call failed...\r\n");
                    exit_flag = 1;
                }
                takeoff = 1;
                usleep(5000000);
                printf("You now have control...\r\n");
            } else if (takeoff && js_right_switch < .5) {
                //TODO - may not want to use system calls...
                //call touchdown script
                printf("LANDING QUAD...\r\n");
                status = system("./scripts/touch_down.sh");
                if (status == -1) {
                    printf("System call failed...\r\n");
                    exit_flag = 1;
                }
                takeoff = 0;
                usleep(5000000);
                initialize_setpoint = 0;
                quad_X_modified = quad_Y_modified = quad_Alt_modified = quad_yaw_modified = 0;
                printf("You have control, but you must takeoff first...\r\n");
            }

            if (takeoff) {
                if (!initialize_setpoint) {
                    //grab setpoint
                    initialize_setpoint = 1;
                    status = frontend_track(conn, &td);
                    if (status) {
                        exit_flag = 1;
                    } else {
                        quad_X = td.longitudinal;
                        quad_Y = td.lateral;
                        quad_Alt = td.height;
                        quad_yaw = td.yaw;
                    }
                } else {
                    //check all joystick values to make sure that they are not in the middle
                    if (!isMidPoint(js_throttle)) {
                        js_throttle = adjustJoystickValue(js_throttle);
                        quad_Alt_modified = 1;
                        temp_setpoint = -(js_throttle - 0.5f);
                        quad_Alt += temp_setpoint * SETPOINT_THRESHOLD;
                        if (quad_Alt < MIN_Alt) {
                            quad_Alt = MIN_Alt;
                        } else if (quad_Alt > MAX_Alt) {
                            quad_Alt = MAX_Alt;
                        }
                    }
                    if (!isMidPoint(js_pitch)) {
                        js_pitch = adjustJoystickValue(js_pitch);
                        quad_X_modified = 1;
                        temp_setpoint = (js_pitch - 0.5f);
                        quad_X += temp_setpoint * SETPOINT_THRESHOLD;
                        if (quad_X < MIN_X) {
                            quad_X = MIN_X;
                        } else if (quad_X > MAX_X) {
                            quad_X = MAX_X;
                        }
                    }
                    if (!isMidPoint(js_roll)) {
                        js_roll = adjustJoystickValue(js_roll);
                        quad_Y_modified = 1;
                        temp_setpoint = (js_roll - 0.5f);
                        quad_Y += temp_setpoint * SETPOINT_THRESHOLD;
                        if (quad_Y < MIN_Y) {
                            quad_Y = MIN_Y;
                        } else if (quad_Y > MAX_Y) {
                            quad_Y = MAX_Y;
                        }
                    }
                    //if (!isMidPoint(js_yaw)) {
                        //TODO - not yet supported
                        //js_yaw = adjustJoystickValue(js_yaw);
                        //quad_yaw_modified = 1;
                        //temp_setpoint = (js_yaw - 0.5f);
                        //quad_yaw += temp_setpoint * SETPOINT_THRESHOLD;
                        //if (quad_yaw < MIN_Yaw) {
                        //    quad_yaw = MIN_Yaw;
                        //} else if (quad_yaw > MAX_Yaw) {
                        //    quad_yaw = MAX_Yaw;
                        //}
                    //}

                    //check if any of the setpoints have been changed,
                    //if so send a message to backend
                    if (quad_Alt_modified) {
                        pd.block = QUAD_Alt;
                        pd.param = PARAM;
                        pd.value = quad_Alt;
                        status = frontend_setparam(conn, &pd);
                        if (status) {
                            printf("frontend_setparam failed...\r\n");
                            exit_flag = 1;
                        }
                    }
                    if (quad_X_modified) {
                        pd.block = QUAD_X;
                        pd.param = PARAM;
                        pd.value = quad_X;
                        status = frontend_setparam(conn, &pd);
                        if (status) {
                            printf("frontend_setparam failed...\r\n");
                            exit_flag = 1;
                        }

                    }
                    if (quad_Y_modified) {
                        pd.block = QUAD_Y;
                        pd.param = PARAM;
                        pd.value = quad_Y;
                        status = frontend_setparam(conn, &pd);
                        if (status) {
                            printf("frontend_setparam failed...\r\n");
                            exit_flag = 1;
                        }

                    }
                    //if (quad_yaw_modified) {
                        //TODO - not yet supported
                        //pd.block = QUAD_Yaw;
                        //pd.param = PARAM;
                        //pd.value = quad_yaw;
                        //status = frontend_setparam(conn, &pd);
                        //if (status) {
                        //    printf("frontend_setparam failed...\r\n");
                        //    exit_flag = 1;
                        //}
                    //}
                    quad_X_modified = quad_Y_modified = quad_Alt_modified = quad_yaw_modified = 0;
                }
            }
        } else {
            printf("Aborting because joystick could not be read...\r\n");
            exit_flag = 1;
        } 
        usleep(5000);
    }

    printf("Manual Assist Mode Exiting...\r\n");

    //If quad is still in the air when exitting, make sure to land it
    if (takeoff) {
        printf("LANDING QUAD...\r\n");
        status = system("./scripts/touch_down.sh");
        if (status == -1) {
            printf("System call failed...\r\n");
            exit_flag = 1;
        }
        takeoff = 0;
        usleep(5000000);
    }

    //Cleanup joystick
    joystick_destroy(js);

    //Cleanup backend connection
    if (conn) {
        ucart_backendDisconnect(conn);
        conn = NULL;
    }

    return 0;
}