diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..34cc7a8 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "oscc"] + path = oscc + url = https://github.com/PolySync/oscc.git diff --git a/CMakeLists.txt b/CMakeLists.txt index fec70ec..75e988d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,11 +5,7 @@ project(oscc-joystick-commander) find_package(PkgConfig REQUIRED) pkg_check_modules(SDL2 REQUIRED sdl2) -if(KIA_SOUL) - add_definitions(-DKIA_SOUL) -elseif(KIA_SOUL_EV) - add_definitions(-DKIA_SOUL_EV) -endif() +include(oscc/api/OsccConfig.cmake) add_executable( oscc-joystick-commander @@ -29,4 +25,3 @@ target_link_libraries( oscc-joystick-commander PRIVATE ${SDL2_LIBRARIES}) - diff --git a/Jenkinsfile b/Jenkinsfile new file mode 100644 index 0000000..b162528 --- /dev/null +++ b/Jenkinsfile @@ -0,0 +1,15 @@ +#!groovy +node('xenial') { + try { + stage('Checkout') { + clean_checkout() + } + stage('Build') { + sh 'git clone git@github.com:PolySync/oscc.git --branch master && mkdir build && cd build && cmake .. -DKIA_SOUL=ON && make' + echo 'Build Complete!' + } + } + finally { + deleteDir() + } +} \ No newline at end of file diff --git a/LICENSE.md b/LICENSE.md index b9f7a8d..2fad33b 100644 --- a/LICENSE.md +++ b/LICENSE.md @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2017 PolySync Technologies +Copyright (c) 2019 PolySync Technologies Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/README.md b/README.md index bd658bf..4377f9d 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,9 @@ +# Joystick Commander + +## Overview + Joystick commander is an example application designed to show how the Open Source Car Control API can be used to recieve reports from and send commands to a drive by-wire enabled vehicle. Using an SDL2 supported game controller, inputs are normalized and converted to relative torque, throttle, and brake commands. This application also demonstrates registering callback functions to recieve and parse OSCC reports as well as vehicle state reports from the car's OBD-II CAN network. @@ -7,7 +11,9 @@ Using an SDL2 supported game controller, inputs are normalized and converted to For more information about OSCC, check out our [github](https://github.com/PolySync/oscc). -# Pre-requisites: +## Getting Started + +These instructions have been tested with a new Ubuntu 18.04 installation. - OSCC's API and firmware modules are both required, and the modules must be installed on the vehicle - The socketcan driver for USB and PCIe CAN interfaces is required, and is pre-installed on most Linux systems @@ -20,90 +26,103 @@ This application has been tested with a Logitech F310 gamepad and a wired Xbox 3 [Logitech Gamepad F310](http://a.co/3GoUlkN) -Install the SDL2 library with the command below. -``` -sudo apt install libsdl2-dev +### 1. Install Dependencies + +You will need several packages installed on your machine in order to build the oscc-joystick-commander application. Use the following command to install them using `apt`: + +```sh +sudo apt install git cmake libsdl2-dev ``` +### 2. Set up this repository locally -# Getting OSCC & Joystick Commander +Clone this repository to your machine, if you have not already done so: -If you haven't already, install the OSCC hardware modules onto the target vehicle. +```sh +# clone the repository +$ git clone git@github.com:PolySync/oscc-joystick-commander.git -Once the hardware is installed and the firmware is flashed, clone and enter the joystick commander repo: -``` -git clone git@github.com:PolySync/oscc-joystick-commander.git -cd oscc-joystick-commander +# change the current directory to the repository +$ cd oscc-joystick-commander ``` -From within the joystick commander directory, clone the OSCC repo: +Note: If you do not have a github account you will need to clone the repository using HTTPS. -``` -git clone git@github.com:PolySync/oscc.git --branch master +Then, from within that directory, sync and initialize Git submodules: + +```sh +$ git submodule sync +$ git submodule update --init --recursive ``` -This will clone into a directory called `oscc` where CMake will look for the OSCC API when it builds joystick commander. +## Building Joystick Commander +### 1. CMake Configuration -# Building Joystick Commander +Before you can build the oscc-joystick-commander application, you must use cmake to configure the project. From within the oscc-joystick-commander repository on your machine: -From the joystick commander directory, run the following sequence to build it: +```sh +# create a build directory that will act as our workspace, and cd to it +$ mkdir build/ +$ cd build/ +``` + +From there, you will run `cmake` to build a platform-specific Makefile. `cmake` will require some arguments, including the vehicle that the firmware is being built for. You can get a list of supported vehicles using the following command: +```sh +$ cmake -LA .. 2>/dev/null | grep 'VEHICLE_VALUES' ``` -mkdir build -cd build -cmake .. -DKIA_SOUL=ON -make + +For example, to configure `cmake` to build a platform-specific Makefile for the Kia Niro, you would use the following command (from within the `build/` directory you created): + +```sh +$ cmake -DVEHICLE=kia_niro .. ``` -The KIA_SOUL CMake option enables the API to swap between different vehicle specifications, allowing the firmware and API to remain car agnostic. +Note: You may also choose to add the flag -DDEBUG=ON to enable debug messaging, serial console, etc. This should not be used for production builds. + +### CAN interface After initializing the CAN interface, use the channel number to start joystick commander and begin sending commands to the OSCC modules. For example with a Kvaser Leaf Light attached, using a bitrate of 500000 and a CAN channel of 0: -``` +```sh sudo ip link set can0 type can bitrate 500000 sudo ip link set up can0 ``` You would then run: -``` +```sh ./oscc-joystick-commander 0 ``` For more information on setting up a socketcan interface, check out [this guide](http://elinux.org/Bringing_CAN_interface_up). +# Application Details -# Controlling the Vehicle with the Joystick Gamepad +## Controlling the Vehicle with the Joystick Gamepad -Once the joystick commander is up and running you can use it to send commands to the Arduino modules. +Once the joystick commander is up and running you can use it to send commands to DriveKit. Use the left trigger to brake, the right trigger for throttle, and the left gamepad axis to control steering. The vehicle will only respond to commands if control is enabled with the start button. The back button disables control. - -# Application Details - - ### main -Entry point of joystick commander. Initializes OSCC interface, checks for controller updates in 50 ms intervals, and closes the interface when the program terminates. This contains the applications main loop. - +`main.c` is the entry point of joystick commander. Initializes OSCC interface, checks for controller updates in 5 ms intervals, and closes the interface when the program terminates. This contains the applications main loop. ### joystick `joystick.c` contains the functionality necessary to initialize and interact with the game controller. - ### commander The commander files contain the joystick commander's interactivity with the OSCC API. It demonstrates opening and closing the CAN channel communications with OSCC's control CAN network, sending enable/disable commands to the modules through the API, retrieving OSCC reports through callback functions, and sending commands through the OSCC `publish` functions. - # Using OSCC API To use the OSCC API in your applications, you need to include any relevant header files. @@ -111,7 +130,7 @@ To use the OSCC API in your applications, you need to include any relevant heade * The can message protocols are located in `oscc/api/include/can_protocols/` * These specify the structs we use for steering, throttle, brake, and fault reports * Vehicle specific macros and values are located in `oscc/api/include/vehicles/` - * You only need to include `vehicles.h`, which will include the relevant vehicle-specific header depending on the option provided to CMake (e.g., `-DKIA_SOUL=ON` will include `kia_soul.h`) + * You only need to include `vehicles.h`, which will include the relevant vehicle-specific header depending on the option provided to CMake (e.g., `-DVEHICLE=kia_niro` will include `kia_niro.h`) * `oscc/api/include/oscc.h` includes the functionality to interface with the OSCC API @@ -130,4 +149,4 @@ Please direct questions regarding OSCC and/or licensing to help@polysync.io. *Distributed as-is; no warranty is given.* -Copyright (c) 2017 PolySync Technologies, Inc. All Rights Reserved. +Copyright (c) 2019 PolySync Technologies, Inc. All Rights Reserved. diff --git a/oscc b/oscc new file mode 160000 index 0000000..45ce9fc --- /dev/null +++ b/oscc @@ -0,0 +1 @@ +Subproject commit 45ce9fccda8b75e58612b70bd45d88bc0621126b diff --git a/src/commander.c b/src/commander.c index 15a0ca0..fa3cb2d 100644 --- a/src/commander.c +++ b/src/commander.c @@ -28,6 +28,7 @@ #define JOYSTICK_AXIS_STEER (SDL_CONTROLLER_AXIS_LEFTX) #define JOYSTICK_BUTTON_ENABLE_CONTROLS (SDL_CONTROLLER_BUTTON_START) #define JOYSTICK_BUTTON_DISABLE_CONTROLS (SDL_CONTROLLER_BUTTON_BACK) +#define STEERING_RANGE_PERCENTAGE (0.36) #define BRAKES_ENABLED_MIN (0.05) #define JOYSTICK_DELAY_INTERVAL (50000) #define COMMANDER_ENABLED ( 1 ) @@ -166,8 +167,7 @@ int check_for_controller_update( ) } } - if ( (return_code == OSCC_OK) - && (control_enabled == true) ) + if ( return_code == OSCC_OK ) { return_code = command_brakes( ); @@ -191,21 +191,37 @@ static int get_normalized_position( unsigned long axis_index, double * const nor int axis_position = 0; + static const float deadzone = 0.3; + return_code = joystick_get_axis( axis_index, &axis_position ); if ( return_code == OSCC_OK ) { + // this is between -1.0 and 1.0 + double raw_normalized_position = ((double) axis_position / INT16_MAX); + if ( axis_index == JOYSTICK_AXIS_STEER ) { - ( *normalized_position ) = CONSTRAIN( - ((double) axis_position) / INT16_MAX, - -1.0, - 1.0); + // if axis is in deadzone, do nothing + if ( fabs(raw_normalized_position) < deadzone) + { + ( *normalized_position ) = 0.0; + } + else + { + // normalize over non deadzone range + raw_normalized_position *= (fabs(raw_normalized_position) - deadzone) / (1.0 - deadzone); + + ( *normalized_position ) = CONSTRAIN( + raw_normalized_position, + -1.0, + 1.0); + } } else { ( *normalized_position ) = CONSTRAIN( - ((double) axis_position) / INT16_MAX, + raw_normalized_position, 0.0, 1.0); } @@ -348,6 +364,12 @@ static int command_brakes( ) return_code = oscc_publish_brake_position( average ); } } + else + { + average = 0.0; + + return_code = OSCC_OK; + } return ( return_code ); } @@ -392,6 +414,12 @@ static int command_throttle( ) return_code = oscc_publish_throttle_position( average ); } } + else + { + average = 0.0; + + return_code = OSCC_OK; + } return ( return_code ); } @@ -421,11 +449,17 @@ static int command_steering( ) printf("Steering: %f\n", average); - return_code = oscc_publish_steering_torque( average ); + // use only 20% of allowable range for controllability + return_code = oscc_publish_steering_torque( average * STEERING_RANGE_PERCENTAGE ); } + } + else + { + average = 0.0; - + return_code = OSCC_OK; } + return ( return_code ); } diff --git a/src/joystick.c b/src/joystick.c index 9dc59ed..b786739 100644 --- a/src/joystick.c +++ b/src/joystick.c @@ -62,7 +62,12 @@ typedef struct static joystick_guid_s joystick_guid; -static joystick_device_data_s joystick_data = { NULL, &joystick_guid }; +static joystick_device_data_s joystick_data = { + .controller = NULL, + .haptic = NULL, + .guid = &joystick_guid + }; + static joystick_device_data_s* joystick = NULL; static int joystick_init_subsystem( ) @@ -171,7 +176,7 @@ int joystick_open( unsigned long device_index ) if ( joystick != NULL ) { - joystick->controller = + joystick->controller = (void*) SDL_GameControllerOpen( (int) device_index ); if ( joystick->controller == JOYSTICK_DEVICE_CONTROLLER_INVALID ) @@ -183,7 +188,7 @@ int joystick_open( unsigned long device_index ) ret = OSCC_OK; const SDL_JoystickGUID m_guid = - SDL_JoystickGetGUID( + SDL_JoystickGetGUID( SDL_GameControllerGetJoystick( joystick->controller ) ); memcpy( joystick_guid.data, m_guid.data, sizeof( m_guid.data ) ); @@ -196,10 +201,10 @@ int joystick_open( unsigned long device_index ) joystick_guid.ascii_string, sizeof( joystick_guid.ascii_string ) ); - joystick->haptic = - (void*) SDL_HapticOpenFromJoystick( + joystick->haptic = + (void*) SDL_HapticOpenFromJoystick( SDL_GameControllerGetJoystick( joystick->controller )); - + if ( SDL_HapticRumbleInit( joystick->haptic ) != 0 ) { SDL_HapticClose( joystick->haptic ); @@ -217,7 +222,7 @@ void joystick_close( ) { if ( SDL_GameControllerGetAttached( joystick->controller ) == SDL_TRUE ) { - if ( joystick->haptic ) + if ( joystick->haptic ) { SDL_HapticClose( joystick->haptic ); } @@ -266,7 +271,7 @@ int joystick_get_axis( unsigned long axis_index, int * const position ) const Sint16 pos = SDL_GameControllerGetAxis( joystick->controller, axis_index ); - + ( *position ) = (int) pos; } @@ -288,12 +293,12 @@ int joystick_get_button( unsigned long button_index, if ( m_state == 1 ) { ( *button_state ) = JOYSTICK_BUTTON_STATE_PRESSED; - + if ( joystick->haptic ) { SDL_HapticRumblePlay( joystick->haptic, 1.0f, 100 ); } - + ( void ) usleep( BUTTON_PRESSED_DELAY ); } else diff --git a/src/main.c b/src/main.c index 292de37..9bf057e 100644 --- a/src/main.c +++ b/src/main.c @@ -10,7 +10,7 @@ #include "commander.h" #include "can_protocols/steering_can_protocol.h" -#define COMMANDER_UPDATE_INTERVAL_MICRO (50000) +#define COMMANDER_UPDATE_INTERVAL_MICRO (5000) #define SLEEP_TICK_INTERVAL_MICRO (1000) static int error_thrown = OSCC_OK;