├── pepper-gamepad-root ├── settings.gradle ├── gradle │ └── wrapper │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties ├── sample-app │ ├── src │ │ └── main │ │ │ ├── assets │ │ │ └── robot │ │ │ │ └── robotsdk.xml │ │ │ ├── res │ │ │ ├── drawable │ │ │ │ ├── error.png │ │ │ │ ├── background.gif │ │ │ │ └── ic_launcher_background.xml │ │ │ ├── drawable-fr-rFR │ │ │ │ ├── error.png │ │ │ │ └── background.gif │ │ │ ├── mipmap-hdpi │ │ │ │ ├── ic_launcher.png │ │ │ │ └── ic_launcher_round.png │ │ │ ├── mipmap-mdpi │ │ │ │ ├── ic_launcher.png │ │ │ │ └── ic_launcher_round.png │ │ │ ├── mipmap-xhdpi │ │ │ │ ├── ic_launcher.png │ │ │ │ └── ic_launcher_round.png │ │ │ ├── mipmap-xxhdpi │ │ │ │ ├── ic_launcher.png │ │ │ │ └── ic_launcher_round.png │ │ │ ├── mipmap-xxxhdpi │ │ │ │ ├── ic_launcher.png │ │ │ │ └── ic_launcher_round.png │ │ │ ├── values │ │ │ │ ├── colors.xml │ │ │ │ ├── styles.xml │ │ │ │ └── strings.xml │ │ │ ├── mipmap-anydpi-v26 │ │ │ │ ├── ic_launcher.xml │ │ │ │ └── ic_launcher_round.xml │ │ │ ├── values-fr │ │ │ │ └── strings.xml │ │ │ ├── layout │ │ │ │ └── activity_main.xml │ │ │ └── drawable-v24 │ │ │ │ └── ic_launcher_foreground.xml │ │ │ ├── AndroidManifest.xml │ │ │ └── java │ │ │ └── com │ │ │ └── softbankrobotics │ │ │ └── peppergamepadsample │ │ │ └── MainActivity.kt │ ├── libs │ │ └── remotecontrollibrary-0.0.3.aar │ ├── proguard-rules.pro │ └── build.gradle ├── pepper-gamepad │ ├── src │ │ └── main │ │ │ ├── assets │ │ │ └── robot │ │ │ │ └── robotsdk.xml │ │ │ ├── AndroidManifest.xml │ │ │ └── java │ │ │ └── com │ │ │ └── softbankrobotics │ │ │ └── peppergamepad │ │ │ └── RemoteRobotController.kt │ ├── compiled │ │ └── pepper-gamepad-1.0.0.aar │ ├── proguard-rules.pro │ └── build.gradle ├── build.gradle ├── gradle.properties ├── gradlew.bat └── gradlew ├── AUTHORS.md ├── .gitignore ├── COPYING.md └── README.md /pepper-gamepad-root/settings.gradle: -------------------------------------------------------------------------------- 1 | include ':pepper-gamepad', ':sample-app' 2 | -------------------------------------------------------------------------------- /pepper-gamepad-root/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/softbankrobotics-labs/pepper-gamepad/HEAD/pepper-gamepad-root/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /pepper-gamepad-root/sample-app/src/main/assets/robot/robotsdk.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /pepper-gamepad-root/pepper-gamepad/src/main/assets/robot/robotsdk.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /pepper-gamepad-root/sample-app/src/main/res/drawable/error.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/softbankrobotics-labs/pepper-gamepad/HEAD/pepper-gamepad-root/sample-app/src/main/res/drawable/error.png -------------------------------------------------------------------------------- /pepper-gamepad-root/pepper-gamepad/compiled/pepper-gamepad-1.0.0.aar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/softbankrobotics-labs/pepper-gamepad/HEAD/pepper-gamepad-root/pepper-gamepad/compiled/pepper-gamepad-1.0.0.aar -------------------------------------------------------------------------------- /pepper-gamepad-root/sample-app/libs/remotecontrollibrary-0.0.3.aar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/softbankrobotics-labs/pepper-gamepad/HEAD/pepper-gamepad-root/sample-app/libs/remotecontrollibrary-0.0.3.aar -------------------------------------------------------------------------------- /pepper-gamepad-root/sample-app/src/main/res/drawable/background.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/softbankrobotics-labs/pepper-gamepad/HEAD/pepper-gamepad-root/sample-app/src/main/res/drawable/background.gif -------------------------------------------------------------------------------- /pepper-gamepad-root/sample-app/src/main/res/drawable-fr-rFR/error.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/softbankrobotics-labs/pepper-gamepad/HEAD/pepper-gamepad-root/sample-app/src/main/res/drawable-fr-rFR/error.png -------------------------------------------------------------------------------- /pepper-gamepad-root/sample-app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/softbankrobotics-labs/pepper-gamepad/HEAD/pepper-gamepad-root/sample-app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /pepper-gamepad-root/sample-app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/softbankrobotics-labs/pepper-gamepad/HEAD/pepper-gamepad-root/sample-app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /pepper-gamepad-root/sample-app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/softbankrobotics-labs/pepper-gamepad/HEAD/pepper-gamepad-root/sample-app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /pepper-gamepad-root/sample-app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/softbankrobotics-labs/pepper-gamepad/HEAD/pepper-gamepad-root/sample-app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /pepper-gamepad-root/sample-app/src/main/res/drawable-fr-rFR/background.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/softbankrobotics-labs/pepper-gamepad/HEAD/pepper-gamepad-root/sample-app/src/main/res/drawable-fr-rFR/background.gif -------------------------------------------------------------------------------- /pepper-gamepad-root/sample-app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/softbankrobotics-labs/pepper-gamepad/HEAD/pepper-gamepad-root/sample-app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /pepper-gamepad-root/sample-app/src/main/res/mipmap-hdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/softbankrobotics-labs/pepper-gamepad/HEAD/pepper-gamepad-root/sample-app/src/main/res/mipmap-hdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /pepper-gamepad-root/sample-app/src/main/res/mipmap-mdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/softbankrobotics-labs/pepper-gamepad/HEAD/pepper-gamepad-root/sample-app/src/main/res/mipmap-mdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /pepper-gamepad-root/sample-app/src/main/res/mipmap-xhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/softbankrobotics-labs/pepper-gamepad/HEAD/pepper-gamepad-root/sample-app/src/main/res/mipmap-xhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /pepper-gamepad-root/sample-app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/softbankrobotics-labs/pepper-gamepad/HEAD/pepper-gamepad-root/sample-app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /pepper-gamepad-root/sample-app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/softbankrobotics-labs/pepper-gamepad/HEAD/pepper-gamepad-root/sample-app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /pepper-gamepad-root/sample-app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #008577 4 | #00574B 5 | #D81B60 6 | 7 | -------------------------------------------------------------------------------- /pepper-gamepad-root/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Wed Jul 31 11:48:58 CEST 2019 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.4-all.zip 7 | -------------------------------------------------------------------------------- /AUTHORS.md: -------------------------------------------------------------------------------- 1 | ## Pepper Gamepad Authors 2 | 3 | The Pepper Gamepad library was written by the Developer Experience team at Softbank Robotics, Paris, July 2019. 4 | 5 | * **Alexandre Roux** (aroux@softbankrobotics.com ) 6 | * **Joss Stuart** (joss.stuart@softbankrobotics.com) 7 | * **Émile Kroeger** (ekroeger@softbankrobotics.com) 8 | -------------------------------------------------------------------------------- /pepper-gamepad-root/sample-app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /pepper-gamepad-root/pepper-gamepad/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /pepper-gamepad-root/sample-app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /pepper-gamepad-root/sample-app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Built application files 2 | *.apk 3 | *.ap_ 4 | 5 | # Files for the dex VM 6 | *.dex 7 | 8 | # Java class files 9 | *.class 10 | 11 | # Generated files 12 | bin/ 13 | gen/ 14 | 15 | # Local configuration file (sdk path, etc) 16 | local.properties 17 | 18 | # Windows thumbnail db 19 | Thumbs.db 20 | 21 | # OSX files 22 | .DS_Store 23 | 24 | # Android Studio 25 | *.iml 26 | .idea 27 | .gradle 28 | build/ 29 | .navigation 30 | captures/ 31 | output.json 32 | 33 | # NDK 34 | obj/ 35 | .externalNativeBuild 36 | 37 | -------------------------------------------------------------------------------- /pepper-gamepad-root/sample-app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile 22 | -------------------------------------------------------------------------------- /pepper-gamepad-root/pepper-gamepad/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile 22 | -------------------------------------------------------------------------------- /pepper-gamepad-root/build.gradle: -------------------------------------------------------------------------------- 1 | // Top-level build file where you can add configuration options common to all sub-projects/modules. 2 | 3 | buildscript { 4 | ext.kotlin_version = '1.3.61' 5 | repositories { 6 | google() 7 | jcenter() 8 | } 9 | dependencies { 10 | classpath 'com.android.tools.build:gradle:3.6.1' 11 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" 12 | 13 | // NOTE: Do not place your application dependencies here; they belong 14 | // in the individual module build.gradle files 15 | } 16 | } 17 | 18 | allprojects { 19 | repositories { 20 | google() 21 | jcenter() 22 | maven { url 'https://qisdk.softbankrobotics.com/sdk/maven' } 23 | maven { url 'https://jitpack.io' } 24 | } 25 | } 26 | 27 | task clean(type: Delete) { 28 | delete rootProject.buildDir 29 | } 30 | -------------------------------------------------------------------------------- /pepper-gamepad-root/gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | # IDE (e.g. Android Studio) users: 3 | # Gradle settings configured through the IDE *will override* 4 | # any settings specified in this file. 5 | # For more details on how to configure your build environment visit 6 | # http://www.gradle.org/docs/current/userguide/build_environment.html 7 | # Specifies the JVM arguments used for the daemon process. 8 | # The setting is particularly useful for tweaking memory settings. 9 | org.gradle.jvmargs=-Xmx1536m 10 | # When configured, Gradle will run in incubating parallel mode. 11 | # This option should only be used with decoupled projects. More details, visit 12 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 13 | # org.gradle.parallel=true 14 | # Kotlin code style for this project: "official" or "obsolete": 15 | kotlin.code.style=official 16 | android.useAndroidX=true 17 | android.enableJetifier=true 18 | -------------------------------------------------------------------------------- /pepper-gamepad-root/sample-app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /pepper-gamepad-root/sample-app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | Pepper Gamepad Sample 3 | 4 | Great, let\'s have fun together! Take the game pad, look at the controls and we\'re good to go! 5 | Time to put these wheels to good use! I hope you have a game pad ready, take a look at the controls and let\'s go! 6 | Can\'t wait to see where you\'ll take me! Here\'s how to use your game pad, take a look and let\'s go for a ride! 7 | 8 | 9 | Oopsie, the gamepad is not connected. Please look at my tablet to see how to do it! 10 | Looks like no gamepad is connected, take a look at my tablet to see how to remedy this! 11 | I can\'t detect the gamepad, please look at my tablet to see how to connect it! 12 | 13 | 14 | -------------------------------------------------------------------------------- /pepper-gamepad-root/sample-app/src/main/res/values-fr/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | Pepper Gamepad Sample 4 | 5 | Génial, on part en balade! Prends ta manette, jette un oeil aux contrôles et on y va! 6 | Super, j\'avais hâte de me dégourdir les roues! J\'espère que tu as ta manette, je t\'affiche un petit rappel des contrôles avant d\'y aller. 7 | J\'ai hâte de voir où tu vas m\'en mné! Prépare ta manette, jette un oeil aux contrôles et c\'est parti! 8 | 9 | 10 | Oupsse, la manette n\'est pas connectée. Regarde sur ma tablette pour voir comment faire! 11 | Ah mince, je ne détecte pas la manette. Regarde sur ma tablette pour voir comment la connecter! 12 | Ah, on dirait que la manette n\'est pas connectée, j\'affiche les instructions pour le faire sur ma tablette! 13 | 14 | -------------------------------------------------------------------------------- /pepper-gamepad-root/pepper-gamepad/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.library' 2 | 3 | apply plugin: 'kotlin-android' 4 | 5 | android { 6 | archivesBaseName = "pepper-gamepad" 7 | version = "1.0.3" 8 | compileSdkVersion 29 9 | defaultConfig { 10 | minSdkVersion 23 11 | targetSdkVersion 29 12 | versionCode 4 13 | versionName "1.0.3" 14 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" 15 | } 16 | buildTypes { 17 | release { 18 | minifyEnabled false 19 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 20 | } 21 | } 22 | compileOptions { 23 | sourceCompatibility = 1.8 24 | targetCompatibility = 1.8 25 | } 26 | libraryVariants.all { variant -> 27 | variant.outputs.all { output -> 28 | outputFileName = "${archivesBaseName}-${version}.aar" 29 | } 30 | } 31 | } 32 | 33 | dependencies { 34 | implementation fileTree(dir: 'libs', include: ['*.jar']) 35 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" 36 | 37 | implementation 'com.aldebaran:qisdk:1.6.7' 38 | implementation 'com.aldebaran:qisdk-design:1.6.7' 39 | } 40 | -------------------------------------------------------------------------------- /pepper-gamepad-root/sample-app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | apply plugin: 'kotlin-android' 4 | 5 | apply plugin: 'kotlin-android-extensions' 6 | 7 | android { 8 | compileSdkVersion 29 9 | defaultConfig { 10 | applicationId "com.softbankrobotics.peppergamepadsample" 11 | minSdkVersion 23 12 | targetSdkVersion 29 13 | versionCode 2 14 | versionName "1.1.0" 15 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" 16 | } 17 | buildTypes { 18 | release { 19 | minifyEnabled false 20 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' 21 | } 22 | } 23 | compileOptions { 24 | sourceCompatibility = 1.8 25 | targetCompatibility = 1.8 26 | } 27 | } 28 | 29 | dependencies { 30 | implementation fileTree(dir: 'libs', include: ['*.jar']) 31 | 32 | implementation"org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" 33 | implementation 'androidx.constraintlayout:constraintlayout:1.1.3' 34 | 35 | implementation 'com.aldebaran:qisdk:1.6.7' 36 | implementation 'com.aldebaran:qisdk-design:1.6.7' 37 | 38 | implementation project(":pepper-gamepad") 39 | 40 | implementation 'pl.droidsonroids.gif:android-gif-drawable:1.2.3' 41 | } 42 | -------------------------------------------------------------------------------- /pepper-gamepad-root/sample-app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 19 | 20 | 30 | 31 | -------------------------------------------------------------------------------- /COPYING.md: -------------------------------------------------------------------------------- 1 | Copyright (c) 2011-2019, SoftBank Robotics 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | * Redistributions of source code must retain the above copyright 7 | notice, this list of conditions and the following disclaimer. 8 | * Redistributions in binary form must reproduce the above copyright 9 | notice, this list of conditions and the following disclaimer in the 10 | documentation and/or other materials provided with the distribution. 11 | * Neither the name of the SoftBank Robotics nor the 12 | names of its contributors may be used to endorse or promote products 13 | derived from this software without specific prior written permission. 14 | 15 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 16 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 17 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 | DISCLAIMED. IN NO EVENT SHALL SoftBank Robotics BE LIABLE FOR ANY 19 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 20 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 21 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 22 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 24 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------------------- /pepper-gamepad-root/sample-app/src/main/res/drawable-v24/ic_launcher_foreground.xml: -------------------------------------------------------------------------------- 1 | 7 | 12 | 13 | 19 | 22 | 25 | 26 | 27 | 28 | 34 | 35 | -------------------------------------------------------------------------------- /pepper-gamepad-root/gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | set DIRNAME=%~dp0 12 | if "%DIRNAME%" == "" set DIRNAME=. 13 | set APP_BASE_NAME=%~n0 14 | set APP_HOME=%DIRNAME% 15 | 16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 17 | set DEFAULT_JVM_OPTS= 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windows variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | 53 | :win9xME_args 54 | @rem Slurp the command line arguments. 55 | set CMD_LINE_ARGS= 56 | set _SKIP=2 57 | 58 | :win9xME_args_slurp 59 | if "x%~1" == "x" goto execute 60 | 61 | set CMD_LINE_ARGS=%* 62 | 63 | :execute 64 | @rem Setup the command line 65 | 66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 67 | 68 | @rem Execute Gradle 69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 70 | 71 | :end 72 | @rem End local scope for the variables with windows NT shell 73 | if "%ERRORLEVEL%"=="0" goto mainEnd 74 | 75 | :fail 76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 77 | rem the _cmd.exe /c_ return code! 78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 79 | exit /b 1 80 | 81 | :mainEnd 82 | if "%OS%"=="Windows_NT" endlocal 83 | 84 | :omega 85 | -------------------------------------------------------------------------------- /pepper-gamepad-root/sample-app/src/main/res/drawable/ic_launcher_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 10 | 12 | 14 | 16 | 18 | 20 | 22 | 24 | 26 | 28 | 30 | 32 | 34 | 36 | 38 | 40 | 42 | 44 | 46 | 48 | 50 | 52 | 54 | 56 | 58 | 60 | 62 | 64 | 66 | 68 | 70 | 72 | 74 | 75 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Pepper Gamepad Remote Control Library 2 | 3 | This Android Library will help you to connect an external controller and map buttons in order to make a Pepper move, using the QiSDK. 4 | 5 | This library was tested with a Xbox One Controller, but can be used with any Bluetooth input device. 6 | 7 | ### Video Demonstration 8 | 9 | This video was filmed at SoftBank Robotics Europe, and shows the basic control scheme while navigating around the SBRE Showroom. 10 | 11 | [Watch video on YouTube](https://youtu.be/ECXIhBUcHZ8) 12 | 13 | ## Getting Started 14 | 15 | ### Prerequisites 16 | 17 | A robotified project for Pepper with QiSDK. Read the [documentation](https://developer.softbankrobotics.com/pepper-qisdk) if needed 18 | 19 | A connection to an external controller. 20 | 21 | ### Connecting a Controller 22 | 23 | 1. Turn on the Bluetooth for the Android Tablet on Pepper. 24 | 2. Set you controller to pairing mode. This will differ between devices, please check the instructions for your specific device if unsure. 25 | 3. In the Tablet settings, navigate to Bluetooth Settings, find the device and pair it. 26 | 27 | ### Running the Sample Application 28 | 29 | The project comes complete with a sample project. You can clone the repository, open it in Android Studio, and run this directly onto a Robot. 30 | 31 | The sample application will handle the case where the controller is not connected, you can use a similar function in your own application. 32 | 33 | Because any number of external controllers can be used, and the mapping needed may be different, it is necessary to override `onGenericMotionEvent` and pass the values to the `RemoteRobotController` in the **pepper-gamepad** library. 34 | 35 | Full implementation details are available to see in the sample project. 36 | 37 | ### Installing 38 | 39 | [**Follow these instructions**](https://jitpack.io/#softbankrobotics-labs/pepper-gamepad) 40 | 41 | Make sure to replace 'Tag' by the number of the version of the library you want to use. 42 | 43 | ## Usage 44 | 45 | *This README assumes some standard setup can be done by the user, such as initialising variables or implementing code in the correct functions. Refer to the Sample Project for full usage code.* 46 | 47 | Initialise the QISDK in the onCreate. If you are unsure how to do this, refer to the [QISDK tutorials](https://developer.softbankrobotics.com/pepper-qisdk/getting-started/creating-robot-application) 48 | 49 | QiSDK.register(this, this) 50 | 51 | In the `onRobotFocusGained`, disable BasicAwareness, and instantiate a `RemoteRobotController` object by passing it the QiContext. Then start it. 52 | 53 | ``` 54 | override fun onRobotFocusGained(qiContext: QiContext) { 55 | val basicAwarenessHolder = HolderBuilder.with(qiContext) 56 | .withAutonomousAbilities(AutonomousAbilitiesType.BASIC_AWARENESS) 57 | .build() 58 | 59 | basicAwarenessHolder.async().hold().thenConsume { 60 | when { 61 | it.isSuccess -> Log.i(TAG, "BasicAwareness held with success") 62 | it.hasError() -> Log.e(TAG, "holdBasicAwareness error: " + it.errorMessage) 63 | it.isCancelled -> Log.e(TAG, "holdBasicAwareness cancelled") 64 | } 65 | } 66 | 67 | remoteRobotController = RemoteRobotController(qiContext) 68 | remoteRobotController.start() 69 | } 70 | ``` 71 | Get the position of the controller and call updateTarget method. It is important to call this function in a thread, as it is using references to the QISDK. 72 | ``` 73 | remoteRobotController.updateTarget(leftJoystickX, leftJoystickY, rightJoystickX, rightJoystickY) 74 | ``` 75 | - Left joystick makes Pepper translate 76 | - Right joystick makes Pepper rotate 77 | 78 | Example : 79 | 80 | ``` 81 | override fun onGenericMotionEvent(event: MotionEvent): Boolean { 82 | 83 | // Add null protection for when the controller disconnects 84 | val inputDevice = event.device ?: return super.onGenericMotionEvent(event) 85 | 86 | // Get left joystick coordinates 87 | val leftJoystickX = getCenteredAxis(event, inputDevice, MotionEvent.AXIS_X) 88 | val leftJoystickY = getCenteredAxis(event, inputDevice, MotionEvent.AXIS_Y) 89 | 90 | // Get right joystick coordinates 91 | val rightJoystickX = getCenteredAxis(event, inputDevice, MotionEvent.AXIS_Z) 92 | val rightJoystickY = getCenteredAxis(event, inputDevice, MotionEvent.AXIS_RZ) 93 | 94 | if (::remoteRobotController.isInitialized) { 95 | thread { 96 | remoteRobotController.updateTarget(leftJoystickX, leftJoystickY, rightJoystickX, rightJoystickY) 97 | } 98 | } 99 | 100 | return true 101 | } 102 | 103 | private fun getCenteredAxis(event: MotionEvent, device: InputDevice, axis: Int): Float { 104 | val range: InputDevice.MotionRange? = device.getMotionRange(axis, event.source) 105 | 106 | // A joystick at rest does not always report an absolute position of 107 | // (0,0). Use the getFlat() method to determine the range of values bounding the joystick axis center. 108 | 109 | range?.apply { 110 | val value = event.getAxisValue(axis) 111 | 112 | // Ignore axis values that are within the 'flat' region of the joystick axis center. 113 | if (Math.abs(value) > flat) { 114 | return value 115 | } 116 | } 117 | 118 | return 0f 119 | } 120 | ``` 121 | 122 | You can stop `RemoteRobotController` object whenever you want by calling the `stop()` method. This can be helpfull if you want to run animations for instance: 123 | 124 | ``` 125 | remoteRobotController.stop() 126 | myCustomAnimation.run() 127 | remoteRobotController.start() 128 | ``` 129 | 130 | ## License 131 | 132 | This project is licensed under the BSD 3-Clause "New" or "Revised" License- see the [COPYING](COPYING.md) file for details 133 | 134 | 135 | -------------------------------------------------------------------------------- /pepper-gamepad-root/gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Attempt to set APP_HOME 10 | # Resolve links: $0 may be a link 11 | PRG="$0" 12 | # Need this for relative symlinks. 13 | while [ -h "$PRG" ] ; do 14 | ls=`ls -ld "$PRG"` 15 | link=`expr "$ls" : '.*-> \(.*\)$'` 16 | if expr "$link" : '/.*' > /dev/null; then 17 | PRG="$link" 18 | else 19 | PRG=`dirname "$PRG"`"/$link" 20 | fi 21 | done 22 | SAVED="`pwd`" 23 | cd "`dirname \"$PRG\"`/" >/dev/null 24 | APP_HOME="`pwd -P`" 25 | cd "$SAVED" >/dev/null 26 | 27 | APP_NAME="Gradle" 28 | APP_BASE_NAME=`basename "$0"` 29 | 30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 31 | DEFAULT_JVM_OPTS="" 32 | 33 | # Use the maximum available, or set MAX_FD != -1 to use that value. 34 | MAX_FD="maximum" 35 | 36 | warn () { 37 | echo "$*" 38 | } 39 | 40 | die () { 41 | echo 42 | echo "$*" 43 | echo 44 | exit 1 45 | } 46 | 47 | # OS specific support (must be 'true' or 'false'). 48 | cygwin=false 49 | msys=false 50 | darwin=false 51 | nonstop=false 52 | case "`uname`" in 53 | CYGWIN* ) 54 | cygwin=true 55 | ;; 56 | Darwin* ) 57 | darwin=true 58 | ;; 59 | MINGW* ) 60 | msys=true 61 | ;; 62 | NONSTOP* ) 63 | nonstop=true 64 | ;; 65 | esac 66 | 67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 68 | 69 | # Determine the Java command to use to start the JVM. 70 | if [ -n "$JAVA_HOME" ] ; then 71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 72 | # IBM's JDK on AIX uses strange locations for the executables 73 | JAVACMD="$JAVA_HOME/jre/sh/java" 74 | else 75 | JAVACMD="$JAVA_HOME/bin/java" 76 | fi 77 | if [ ! -x "$JAVACMD" ] ; then 78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 79 | 80 | Please set the JAVA_HOME variable in your environment to match the 81 | location of your Java installation." 82 | fi 83 | else 84 | JAVACMD="java" 85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 86 | 87 | Please set the JAVA_HOME variable in your environment to match the 88 | location of your Java installation." 89 | fi 90 | 91 | # Increase the maximum file descriptors if we can. 92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then 93 | MAX_FD_LIMIT=`ulimit -H -n` 94 | if [ $? -eq 0 ] ; then 95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 96 | MAX_FD="$MAX_FD_LIMIT" 97 | fi 98 | ulimit -n $MAX_FD 99 | if [ $? -ne 0 ] ; then 100 | warn "Could not set maximum file descriptor limit: $MAX_FD" 101 | fi 102 | else 103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 104 | fi 105 | fi 106 | 107 | # For Darwin, add options to specify how the application appears in the dock 108 | if $darwin; then 109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 110 | fi 111 | 112 | # For Cygwin, switch paths to Windows format before running java 113 | if $cygwin ; then 114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 116 | JAVACMD=`cygpath --unix "$JAVACMD"` 117 | 118 | # We build the pattern for arguments to be converted via cygpath 119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 120 | SEP="" 121 | for dir in $ROOTDIRSRAW ; do 122 | ROOTDIRS="$ROOTDIRS$SEP$dir" 123 | SEP="|" 124 | done 125 | OURCYGPATTERN="(^($ROOTDIRS))" 126 | # Add a user-defined pattern to the cygpath arguments 127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 129 | fi 130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 131 | i=0 132 | for arg in "$@" ; do 133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 135 | 136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 138 | else 139 | eval `echo args$i`="\"$arg\"" 140 | fi 141 | i=$((i+1)) 142 | done 143 | case $i in 144 | (0) set -- ;; 145 | (1) set -- "$args0" ;; 146 | (2) set -- "$args0" "$args1" ;; 147 | (3) set -- "$args0" "$args1" "$args2" ;; 148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 154 | esac 155 | fi 156 | 157 | # Escape application args 158 | save () { 159 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done 160 | echo " " 161 | } 162 | APP_ARGS=$(save "$@") 163 | 164 | # Collect all arguments for the java command, following the shell quoting and substitution rules 165 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" 166 | 167 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong 168 | if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then 169 | cd "$(dirname "$0")" 170 | fi 171 | 172 | exec "$JAVACMD" "$@" 173 | -------------------------------------------------------------------------------- /pepper-gamepad-root/pepper-gamepad/src/main/java/com/softbankrobotics/peppergamepad/RemoteRobotController.kt: -------------------------------------------------------------------------------- 1 | package com.softbankrobotics.peppergamepad 2 | 3 | import android.util.Log 4 | import com.aldebaran.qi.Future 5 | import com.aldebaran.qi.sdk.QiContext 6 | import com.aldebaran.qi.sdk.`object`.actuation.AttachedFrame 7 | import com.aldebaran.qi.sdk.`object`.actuation.LookAt 8 | import com.aldebaran.qi.sdk.`object`.actuation.LookAtMovementPolicy 9 | import com.aldebaran.qi.sdk.`object`.geometry.Transform 10 | import com.aldebaran.qi.sdk.builder.AnimateBuilder 11 | import com.aldebaran.qi.sdk.builder.AnimationBuilder 12 | import com.aldebaran.qi.sdk.builder.LookAtBuilder 13 | import com.aldebaran.qi.sdk.builder.TransformBuilder 14 | import kotlin.math.atan2 15 | import kotlin.math.cos 16 | import kotlin.math.roundToInt 17 | import kotlin.math.sin 18 | 19 | class RemoteRobotController(private val qiContext: QiContext) { 20 | 21 | private val TAG = "RemoteRobotController" 22 | 23 | var isRunning = false 24 | private set 25 | private var startAfterInitialization = false 26 | private var isMoving = false 27 | 28 | private var currentLeftJoystickX = 0 29 | private var currentLeftJoystickY = 0 30 | private var currentRightJoystickX = 0 31 | private var currentRightJoystickY = 0 32 | 33 | private lateinit var lookAtFuture: Future 34 | private lateinit var animateFuture: Future 35 | 36 | private lateinit var defaultPosition: Transform 37 | private lateinit var targetFrame: AttachedFrame 38 | private lateinit var lookAt: LookAt 39 | 40 | init { 41 | qiContext.actuation.async().gazeFrame().andThenConsume { robotFrame -> 42 | defaultPosition = TransformBuilder.create().fromXTranslation(100.0) 43 | targetFrame = robotFrame.makeAttachedFrame(defaultPosition) 44 | lookAt = LookAtBuilder.with(qiContext).withFrame(targetFrame.frame()).build() 45 | lookAt.addOnStartedListener { 46 | Log.i(TAG, "LookAt started") 47 | } 48 | if (startAfterInitialization) start() 49 | } 50 | } 51 | 52 | fun start() { 53 | Log.d(TAG, "start") 54 | 55 | if (!::lookAt.isInitialized) { 56 | startAfterInitialization = true 57 | return 58 | } 59 | 60 | if (isRunning) return 61 | 62 | lookAtFuture = lookAt.async().run() 63 | lookAtFuture.thenConsume { 64 | when { 65 | lookAtFuture.isDone -> Log.i(TAG, "LookAt done") 66 | lookAtFuture.hasError() -> Log.e(TAG, "LookAt error: ${lookAtFuture.errorMessage}") 67 | lookAtFuture.isCancelled -> Log.e(TAG, "LookAt cancelled") 68 | } 69 | } 70 | 71 | isRunning = true 72 | } 73 | 74 | fun stop() { 75 | Log.d(TAG, "stop") 76 | 77 | if (!isRunning) return 78 | 79 | lookAtFuture.requestCancellation() 80 | animateFuture.requestCancellation() 81 | 82 | isRunning = false 83 | } 84 | 85 | fun updateTarget( 86 | newLeftJoystickX: Float, 87 | newLeftJoystickY: Float, 88 | newRightJoystickX: Float, 89 | newRightJoystickY: Float 90 | ) { 91 | Log.d( 92 | TAG, "updateTarget newLeftJoystickX=$newLeftJoystickX " + 93 | "newLeftJoystickY=$newLeftJoystickY " + 94 | "newRightJoystickX=$newRightJoystickX " + 95 | "newRightJoystickY=$newRightJoystickY" 96 | ) 97 | 98 | // Round values 99 | var roundedNewLeftJoystickX = 0 100 | var roundedNewLeftJoystickY = 0 101 | if (!(newLeftJoystickX == 0f && newLeftJoystickY == 0f)) { 102 | val leftJoystickTheta = atan2(newLeftJoystickY, newLeftJoystickX) 103 | roundedNewLeftJoystickX = (cos(leftJoystickTheta) * 2).roundToInt() * 5 104 | roundedNewLeftJoystickY = (sin(leftJoystickTheta) * 2).roundToInt() * 5 105 | } 106 | var roundedNewRightJoystickX = 0 107 | var roundedNewRightJoystickY = 0 108 | if (!(newRightJoystickX == 0f && newRightJoystickY == 0f)) { 109 | val rightJoystickTheta = atan2(newRightJoystickY, newRightJoystickX) 110 | roundedNewRightJoystickX = (cos(rightJoystickTheta) * 10).roundToInt() 111 | roundedNewRightJoystickY = (sin(rightJoystickTheta) * 10).roundToInt() 112 | } 113 | 114 | // Avoid repeating commands 115 | if (!(roundedNewLeftJoystickX == currentLeftJoystickX && roundedNewLeftJoystickY == currentLeftJoystickY)) { 116 | currentLeftJoystickX = roundedNewLeftJoystickX 117 | currentLeftJoystickY = roundedNewLeftJoystickY 118 | 119 | makeTranslation() 120 | } 121 | if (!(roundedNewRightJoystickX == currentRightJoystickX && roundedNewRightJoystickY == currentRightJoystickY)) { 122 | currentRightJoystickX = roundedNewRightJoystickX 123 | currentRightJoystickY = roundedNewRightJoystickY 124 | 125 | makeRotation() 126 | } 127 | } 128 | 129 | private fun makeTranslation() { 130 | Log.d( 131 | TAG, 132 | "makeTranslation currentLeftJoystickX=$currentLeftJoystickX currentLeftJoystickY=$currentLeftJoystickY" 133 | ) 134 | 135 | if (!isRunning) return 136 | 137 | if (::animateFuture.isInitialized && !animateFuture.isDone) { 138 | animateFuture.requestCancellation() 139 | } else if (!(currentLeftJoystickX == 0 && currentLeftJoystickY == 0) && !isMoving) { 140 | isMoving = true 141 | lookAt.async().setPolicy(LookAtMovementPolicy.HEAD_ONLY).andThenConsume { 142 | val targetX = -currentLeftJoystickY.toDouble() 143 | val targetY = -currentLeftJoystickX.toDouble() 144 | 145 | val animationString = "[\"Holonomic\", [\"Line\", [$targetX, $targetY]], 0.0, 40.0]" 146 | val animation = AnimationBuilder.with(qiContext).withTexts(animationString).build() 147 | val animate = AnimateBuilder.with(qiContext).withAnimation(animation).build() 148 | animate.addOnStartedListener { 149 | Log.i(TAG, "Animate started") 150 | 151 | if (!(targetX == -currentLeftJoystickY.toDouble() && targetY == -currentLeftJoystickX.toDouble())) { 152 | animateFuture.requestCancellation() 153 | } 154 | } 155 | 156 | animateFuture = animate.async().run() 157 | animateFuture.thenConsume { 158 | when { 159 | animateFuture.isSuccess -> Log.i(TAG, "Animate finished with success") 160 | animateFuture.hasError() -> Log.e( 161 | TAG, 162 | "Animate error: ${animateFuture.errorMessage}" 163 | ) 164 | animateFuture.isCancelled -> Log.i(TAG, "Animate cancelled") 165 | } 166 | 167 | lookAt.policy = LookAtMovementPolicy.HEAD_AND_BASE 168 | isMoving = false 169 | 170 | makeTranslation() 171 | } 172 | } 173 | } 174 | } 175 | 176 | private fun makeRotation() { 177 | Log.d( 178 | TAG, 179 | "makeRotation currentRightJoystickX=$currentRightJoystickX currentRightJoystickY=$currentRightJoystickY" 180 | ) 181 | 182 | if (!isRunning) return 183 | 184 | if (currentRightJoystickX == 0 && currentRightJoystickY == 0) { 185 | targetFrame.update(defaultPosition) 186 | } else { 187 | val targetX = -currentRightJoystickY.toDouble() 188 | val targetY = -currentRightJoystickX.toDouble() 189 | 190 | val transform = TransformBuilder.create().from2DTranslation(targetX, targetY) 191 | targetFrame.update(transform) 192 | } 193 | } 194 | } 195 | -------------------------------------------------------------------------------- /pepper-gamepad-root/sample-app/src/main/java/com/softbankrobotics/peppergamepadsample/MainActivity.kt: -------------------------------------------------------------------------------- 1 | package com.softbankrobotics.peppergamepadsample 2 | 3 | import android.app.Activity 4 | import android.content.Context 5 | import android.hardware.input.InputManager 6 | import android.hardware.input.InputManager.InputDeviceListener 7 | import android.os.Bundle 8 | import android.util.Log 9 | import android.view.InputDevice 10 | import android.view.MotionEvent 11 | import android.view.View 12 | import com.aldebaran.qi.sdk.QiContext 13 | import com.aldebaran.qi.sdk.QiSDK 14 | import com.aldebaran.qi.sdk.RobotLifecycleCallbacks 15 | import com.aldebaran.qi.sdk.`object`.holder.AutonomousAbilitiesType 16 | import com.aldebaran.qi.sdk.`object`.holder.Holder 17 | import com.aldebaran.qi.sdk.builder.HolderBuilder 18 | import com.aldebaran.qi.sdk.builder.SayBuilder 19 | import com.softbankrobotics.peppergamepad.RemoteRobotController 20 | import kotlinx.android.synthetic.main.activity_main.* 21 | import kotlin.concurrent.thread 22 | import kotlin.math.abs 23 | import kotlin.random.Random 24 | 25 | class MainActivity : Activity(), RobotLifecycleCallbacks, InputDeviceListener { 26 | 27 | companion object { 28 | private const val TAG = "RemoteControlSample" 29 | } 30 | 31 | private lateinit var inputManager: InputManager 32 | 33 | private var qiContext: QiContext? = null 34 | private lateinit var basicAwarenessHolder: Holder 35 | 36 | private lateinit var remoteRobotController: RemoteRobotController 37 | 38 | override fun onCreate(savedInstanceState: Bundle?) { 39 | super.onCreate(savedInstanceState) 40 | 41 | setContentView(R.layout.activity_main) 42 | 43 | QiSDK.register(this, this) 44 | 45 | inputManager = getSystemService(Context.INPUT_SERVICE) as InputManager 46 | } 47 | 48 | override fun onResume() { 49 | super.onResume() 50 | inputManager.registerInputDeviceListener(this, null) 51 | checkControllerConnection() 52 | 53 | // Enables sticky immersive mode. 54 | window.decorView.systemUiVisibility = (View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY 55 | // Set the content to appear under the system bars so that the 56 | // content doesn't resize when the system bars hide and show. 57 | or View.SYSTEM_UI_FLAG_LAYOUT_STABLE 58 | or View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION 59 | or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN 60 | // Hide the nav bar and status bar 61 | or View.SYSTEM_UI_FLAG_HIDE_NAVIGATION 62 | or View.SYSTEM_UI_FLAG_FULLSCREEN) 63 | } 64 | 65 | override fun onInputDeviceRemoved(deviceId: Int) { 66 | Log.d(TAG, "onInputDeviceRemoved") 67 | checkControllerConnection() 68 | } 69 | 70 | override fun onInputDeviceAdded(deviceId: Int) { 71 | Log.d(TAG, "onInputDeviceAdded") 72 | checkControllerConnection() 73 | } 74 | 75 | override fun onInputDeviceChanged(deviceId: Int) { 76 | Log.d(TAG, "onInputDeviceChanged") 77 | checkControllerConnection() 78 | } 79 | 80 | private fun checkControllerConnection() { 81 | val connectedControllers = getGameControllerIds() 82 | if (connectedControllers.isEmpty()) { 83 | runOnUiThread { 84 | backgroundGifImageView.visibility = View.INVISIBLE 85 | errorImageView.visibility = View.VISIBLE 86 | } 87 | 88 | val errorSentences = resources.getStringArray(R.array.error) 89 | sayRandomSentence(errorSentences) 90 | } else { 91 | runOnUiThread { 92 | backgroundGifImageView.visibility = View.VISIBLE 93 | errorImageView.visibility = View.INVISIBLE 94 | } 95 | 96 | val welcomeSentences = resources.getStringArray(R.array.welcome) 97 | sayRandomSentence(welcomeSentences) 98 | } 99 | } 100 | 101 | private fun sayRandomSentence(sentencesArray: Array) { 102 | if (qiContext == null) { 103 | return 104 | } 105 | 106 | val i = Random.nextInt(0, sentencesArray.size - 1) 107 | SayBuilder.with(qiContext) 108 | .withText(sentencesArray[i]) 109 | .buildAsync().andThenConsume { 110 | it.async().run() 111 | } 112 | } 113 | 114 | private fun getGameControllerIds(): List { 115 | val gameControllerDeviceIds = mutableListOf() 116 | val deviceIds = inputManager.inputDeviceIds 117 | deviceIds.forEach { deviceId -> 118 | InputDevice.getDevice(deviceId).apply { 119 | 120 | // Verify that the device has gamepad buttons, control sticks, or both. 121 | if (sources and InputDevice.SOURCE_GAMEPAD == InputDevice.SOURCE_GAMEPAD 122 | || sources and InputDevice.SOURCE_JOYSTICK == InputDevice.SOURCE_JOYSTICK 123 | ) { 124 | // This device is a game controller. Store its device ID. 125 | gameControllerDeviceIds 126 | .takeIf { !it.contains(deviceId) } 127 | ?.add(deviceId) 128 | } 129 | } 130 | } 131 | return gameControllerDeviceIds 132 | } 133 | 134 | override fun onRobotFocusGained(qiContext: QiContext) { 135 | Log.i(TAG, "onRobotFocusGained") 136 | this.qiContext = qiContext 137 | 138 | checkControllerConnection() 139 | 140 | // Hold Basic Awareness to avoid robot getting distracted 141 | basicAwarenessHolder = HolderBuilder.with(qiContext) 142 | .withAutonomousAbilities(AutonomousAbilitiesType.BASIC_AWARENESS) 143 | .build() 144 | basicAwarenessHolder.async().hold().thenConsume { 145 | when { 146 | it.isSuccess -> Log.i(TAG, "BasicAwareness held with success") 147 | it.hasError() -> Log.e(TAG, "holdBasicAwareness error: " + it.errorMessage) 148 | it.isCancelled -> Log.e(TAG, "holdBasicAwareness cancelled") 149 | } 150 | } 151 | remoteRobotController = RemoteRobotController(qiContext) 152 | remoteRobotController.start() 153 | } 154 | 155 | override fun onGenericMotionEvent(event: MotionEvent): Boolean { 156 | Log.d(TAG, "onGenericMotionEvent $event") 157 | 158 | // Add null protection for when the controller disconnects 159 | val inputDevice = event.device ?: return super.onGenericMotionEvent(event) 160 | 161 | // Get left joystick coordinates 162 | val leftJoystickX = getCenteredAxis(event, inputDevice, MotionEvent.AXIS_X) 163 | val leftJoystickY = getCenteredAxis(event, inputDevice, MotionEvent.AXIS_Y) 164 | 165 | // Get right joystick coordinates 166 | val rightJoystickX = getCenteredAxis(event, inputDevice, MotionEvent.AXIS_Z) 167 | val rightJoystickY = getCenteredAxis(event, inputDevice, MotionEvent.AXIS_RZ) 168 | 169 | if (::remoteRobotController.isInitialized) { 170 | thread { 171 | remoteRobotController.updateTarget( 172 | leftJoystickX, 173 | leftJoystickY, 174 | rightJoystickX, 175 | rightJoystickY 176 | ) 177 | } 178 | } else { 179 | Log.d(TAG, "@@@@@@@@@ not initialized") 180 | } 181 | 182 | return true 183 | } 184 | 185 | private fun getCenteredAxis( 186 | event: MotionEvent, 187 | device: InputDevice, 188 | axis: Int 189 | ): Float { 190 | val range: InputDevice.MotionRange? = device.getMotionRange(axis, event.source) 191 | 192 | // A joystick at rest does not always report an absolute position of 193 | // (0,0). Use the getFlat() method to determine the range of values 194 | // bounding the joystick axis center. 195 | range?.apply { 196 | val value = event.getAxisValue(axis) 197 | 198 | // Ignore axis values that are within the 'flat' region of the 199 | // joystick axis center. 200 | if (abs(value) > flat) { 201 | return value 202 | } 203 | } 204 | return 0f 205 | } 206 | 207 | override fun onRobotFocusLost() { 208 | Log.i(TAG, "onRobotFocusLost") 209 | qiContext = null 210 | remoteRobotController.stop() 211 | } 212 | 213 | override fun onRobotFocusRefused(reason: String?) { 214 | Log.e(TAG, "onRobotFocusRefused: $reason") 215 | } 216 | 217 | override fun onPause() { 218 | super.onPause() 219 | inputManager.unregisterInputDeviceListener(this) 220 | } 221 | 222 | override fun onDestroy() { 223 | super.onDestroy() 224 | QiSDK.unregister(this, this) 225 | } 226 | } 227 | --------------------------------------------------------------------------------