├── android ├── app │ ├── .gitignore │ ├── src │ │ └── main │ │ │ ├── res │ │ │ ├── mipmap-hdpi │ │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-mdpi │ │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-xhdpi │ │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-xxhdpi │ │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-xxxhdpi │ │ │ │ └── ic_launcher.png │ │ │ ├── values │ │ │ │ ├── dimens.xml │ │ │ │ ├── colors.xml │ │ │ │ ├── styles.xml │ │ │ │ └── strings.xml │ │ │ ├── drawable │ │ │ │ └── ic_settings_bluetooth_black_24dp.xml │ │ │ ├── menu │ │ │ │ └── menu_main.xml │ │ │ └── layout │ │ │ │ └── activity_main.xml │ │ │ ├── java │ │ │ └── me │ │ │ │ └── eigenein │ │ │ │ └── arduinocar │ │ │ │ ├── ViewExtensions.kt │ │ │ │ ├── DialogExtensions.kt │ │ │ │ ├── Application.kt │ │ │ │ ├── InputMessage.kt │ │ │ │ ├── OutputMessage.kt │ │ │ │ ├── BluetoothExtensions.kt │ │ │ │ └── MainActivity.kt │ │ │ └── AndroidManifest.xml │ ├── proguard-rules.pro │ └── build.gradle ├── settings.gradle ├── web_hi_res_512.png ├── .idea │ ├── copyright │ │ └── profiles_settings.xml │ ├── vcs.xml │ ├── inspectionProfiles │ │ ├── profiles_settings.xml │ │ └── Project_Default.xml │ ├── modules.xml │ ├── runConfigurations.xml │ ├── gradle.xml │ ├── compiler.xml │ └── misc.xml ├── gradle │ └── wrapper │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties ├── .gitignore ├── build.gradle ├── gradle.properties ├── gradlew.bat └── gradlew ├── arduino ├── .gitignore ├── platformio.ini ├── lib │ └── readme.txt ├── .travis.yml └── src │ └── main.cpp ├── images ├── schematic.png └── Screenshot_20171105-182204_framed.png ├── README.md └── schematic ├── svg.pcb.L9110 H-bridge_9eed947992b17e43635203677d03ae4a_2_pcb.svg ├── part.L9110 H-bridge_02eed2341d1f9ec262679b574ab39474_11.fzp └── svg.schematic.L9110 H-bridge_9eed947992b17e43635203677d03ae4a_2_schematic.svg /android/app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /android/settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app' 2 | -------------------------------------------------------------------------------- /arduino/.gitignore: -------------------------------------------------------------------------------- 1 | .pioenvs 2 | .piolibdeps 3 | .clang_complete 4 | .gcc-flags.json 5 | -------------------------------------------------------------------------------- /images/schematic.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eigenein/rc-car/HEAD/images/schematic.png -------------------------------------------------------------------------------- /android/web_hi_res_512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eigenein/rc-car/HEAD/android/web_hi_res_512.png -------------------------------------------------------------------------------- /android/.idea/copyright/profiles_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /android/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eigenein/rc-car/HEAD/android/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /images/Screenshot_20171105-182204_framed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eigenein/rc-car/HEAD/images/Screenshot_20171105-182204_framed.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eigenein/rc-car/HEAD/android/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eigenein/rc-car/HEAD/android/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eigenein/rc-car/HEAD/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eigenein/rc-car/HEAD/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eigenein/rc-car/HEAD/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/workspace.xml 5 | /.idea/libraries 6 | .DS_Store 7 | /build 8 | /captures 9 | .externalNativeBuild 10 | -------------------------------------------------------------------------------- /android/.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /android/app/src/main/java/me/eigenein/arduinocar/ViewExtensions.kt: -------------------------------------------------------------------------------- 1 | package me.eigenein.arduinocar 2 | 3 | import android.view.View 4 | 5 | fun View.show() { 6 | visibility = View.VISIBLE 7 | } 8 | 9 | fun View.gone() { 10 | visibility = View.GONE 11 | } 12 | -------------------------------------------------------------------------------- /android/app/src/main/res/values/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 16dp 4 | 4dp 5 | 16dp 6 | 7 | -------------------------------------------------------------------------------- /android/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Sat Nov 04 19:27:55 CET 2017 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-4.1-all.zip 7 | -------------------------------------------------------------------------------- /android/.idea/inspectionProfiles/profiles_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | -------------------------------------------------------------------------------- /android/.idea/inspectionProfiles/Project_Default.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | -------------------------------------------------------------------------------- /android/app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #3f51b5 4 | #002984 5 | #757de8 6 | #ff4081 7 | #ffffffff 8 | 9 | -------------------------------------------------------------------------------- /android/app/src/main/java/me/eigenein/arduinocar/DialogExtensions.kt: -------------------------------------------------------------------------------- 1 | package me.eigenein.arduinocar 2 | 3 | import android.app.AlertDialog 4 | import android.content.Context 5 | 6 | fun showAlertDialog(context: Context, init: AlertDialog.Builder.() -> Unit) { 7 | val builder = AlertDialog.Builder(context) 8 | builder.init() 9 | builder.show() 10 | } 11 | -------------------------------------------------------------------------------- /android/app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /android/.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /arduino/platformio.ini: -------------------------------------------------------------------------------- 1 | ; PlatformIO Project Configuration File 2 | ; 3 | ; Build options: build flags, source filter 4 | ; Upload options: custom upload port, speed and extra flags 5 | ; Library options: dependencies, extra library storages 6 | ; Advanced options: extra scripting 7 | ; 8 | ; Please visit documentation for the other options and examples 9 | ; http://docs.platformio.org/page/projectconf.html 10 | 11 | [env:nanoatmega328] 12 | platform = atmelavr 13 | board = nanoatmega328 14 | framework = arduino 15 | -------------------------------------------------------------------------------- /android/app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | Arduino Car 3 | No paired devices found 4 | Connect 5 | Choose vehicle device 6 | Successfully connected to %1$s 7 | Connecting to %1$s 8 | Connection to %1$s failed 9 | 10 | -------------------------------------------------------------------------------- /android/app/src/main/res/drawable/ic_settings_bluetooth_black_24dp.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /android/.idea/runConfigurations.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | -------------------------------------------------------------------------------- /android/app/src/main/java/me/eigenein/arduinocar/Application.kt: -------------------------------------------------------------------------------- 1 | package me.eigenein.arduinocar 2 | 3 | import android.util.Log 4 | import io.reactivex.plugins.RxJavaPlugins 5 | import java.io.IOException 6 | 7 | class Application : android.app.Application() { 8 | private val logTag = Application::class.java.simpleName 9 | 10 | override fun onCreate() { 11 | super.onCreate() 12 | 13 | RxJavaPlugins.setErrorHandler { 14 | if (it is IOException) { 15 | Log.w(logTag, "Unhandled Rx I/O error: " + it.message) 16 | } else { 17 | throw it 18 | } 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /android/.idea/gradle.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 17 | 18 | -------------------------------------------------------------------------------- /android/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.1.51' 5 | repositories { 6 | jcenter() 7 | } 8 | dependencies { 9 | classpath 'com.android.tools.build:gradle:3.0.0' 10 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" 11 | 12 | // NOTE: Do not place your application dependencies here; they belong 13 | // in the individual module build.gradle files 14 | } 15 | } 16 | 17 | allprojects { 18 | repositories { 19 | jcenter() 20 | } 21 | } 22 | 23 | task clean(type: Delete) { 24 | delete rootProject.buildDir 25 | } 26 | -------------------------------------------------------------------------------- /android/app/src/main/res/menu/menu_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 13 | 19 | 20 | -------------------------------------------------------------------------------- /android/.idea/compiler.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /android/gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | 3 | # IDE (e.g. Android Studio) users: 4 | # Gradle settings configured through the IDE *will override* 5 | # any settings specified in this file. 6 | 7 | # For more details on how to configure your build environment visit 8 | # http://www.gradle.org/docs/current/userguide/build_environment.html 9 | 10 | # Specifies the JVM arguments used for the daemon process. 11 | # The setting is particularly useful for tweaking memory settings. 12 | org.gradle.jvmargs=-Xmx1536m 13 | 14 | # When configured, Gradle will run in incubating parallel mode. 15 | # This option should only be used with decoupled projects. More details, visit 16 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 17 | # org.gradle.parallel=true 18 | -------------------------------------------------------------------------------- /android/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /android/app/src/main/java/me/eigenein/arduinocar/InputMessage.kt: -------------------------------------------------------------------------------- 1 | package me.eigenein.arduinocar 2 | 3 | import java.io.InputStream 4 | import java.nio.ByteBuffer 5 | import java.nio.ByteOrder 6 | 7 | interface InputMessage 8 | 9 | data class ConnectedMessage(val device_name: String) : InputMessage 10 | data class DeprecatedTelemetryMessage(val vcc: Float) : InputMessage 11 | 12 | fun InputStream.readValue(size: Int): ByteArray = (1..size).map { read().toByte() }.toByteArray() 13 | 14 | fun InputStream.messageIterable() = object : Iterable { 15 | override fun iterator(): Iterator = object : Iterator { 16 | override fun hasNext(): Boolean = true 17 | 18 | override fun next(): InputMessage = DeprecatedTelemetryMessage( 19 | ByteBuffer.wrap(readValue(6), 2, 4).order(ByteOrder.LITTLE_ENDIAN).int / 1000f 20 | ) 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | DIY RC car controlled by Android app via Bluetooth. 2 | 3 | ## App screenshot 4 | 5 | 6 | 7 | ## Parts 8 | 9 | * [Arduino Nano V3.0 compatible board](https://www.aliexpress.com/item/Nano-CH340-ATmega328P-MicroUSB-Pins-soldered-Compatible-for-Arduino-Nano-V3-0/32572612009.html) 10 | * HC-06 Bluetooth module 11 | * [L9110S H-bridge module](https://www.aliexpress.com/item/MCIGICM-Free-Shipping-5pcs-New-N-L9110S-module-Dual-DC-motor-Driver-Controller-Board-H-bridge/32379934884.html) 12 | * Chassis kit [like this one](https://www.aliexpress.com/item/new-4wd-smart-robot-car-chassis-kits-1-48-double-Board-strong-Smart-car-chassis-for/32604275012.html) 13 | * [4x AA chargable batteries](http://www.ikea.com/nl/nl/catalog/products/70303876/) 14 | * 4x AA battery holder 15 | * 220µF capacitor (for smoothing of pulsations) 16 | 17 | ## Schematic 18 | 19 | ![](images/schematic.png) 20 | -------------------------------------------------------------------------------- /arduino/lib/readme.txt: -------------------------------------------------------------------------------- 1 | 2 | This directory is intended for the project specific (private) libraries. 3 | PlatformIO will compile them to static libraries and link to executable file. 4 | 5 | The source code of each library should be placed in separate directory, like 6 | "lib/private_lib/[here are source files]". 7 | 8 | For example, see how can be organized `Foo` and `Bar` libraries: 9 | 10 | |--lib 11 | | |--Bar 12 | | | |--docs 13 | | | |--examples 14 | | | |--src 15 | | | |- Bar.c 16 | | | |- Bar.h 17 | | |--Foo 18 | | | |- Foo.c 19 | | | |- Foo.h 20 | | |- readme.txt --> THIS FILE 21 | |- platformio.ini 22 | |--src 23 | |- main.c 24 | 25 | Then in `src/main.c` you should use: 26 | 27 | #include 28 | #include 29 | 30 | // rest H/C/CPP code 31 | 32 | PlatformIO will find your libraries automatically, configure preprocessor's 33 | include paths and build them. 34 | 35 | More information about PlatformIO Library Dependency Finder 36 | - http://docs.platformio.org/page/librarymanager/ldf.html 37 | -------------------------------------------------------------------------------- /android/app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in /Users/eigenein/Library/Android/sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class device_name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | 19 | # Uncomment this to preserve the line number information for 20 | # debugging stack traces. 21 | #-keepattributes SourceFile,LineNumberTable 22 | 23 | # If you keep the line number information, uncomment this to 24 | # hide the original source file device_name. 25 | #-renamesourcefileattribute SourceFile 26 | -------------------------------------------------------------------------------- /android/app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | apply plugin: 'kotlin-android' 3 | 4 | android { 5 | compileSdkVersion 26 6 | buildToolsVersion "26.0.2" 7 | defaultConfig { 8 | applicationId "me.eigenein.arduinocar" 9 | minSdkVersion 26 10 | targetSdkVersion 26 11 | versionCode 1 12 | versionName "1.0" 13 | } 14 | buildTypes { 15 | release { 16 | minifyEnabled false 17 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 18 | } 19 | } 20 | } 21 | 22 | dependencies { 23 | compile fileTree(dir: 'libs', include: ['*.jar']) 24 | compile "org.jetbrains.kotlin:kotlin-stdlib-jre7:$kotlin_version" 25 | compile 'com.android.support.constraint:constraint-layout:1.0.2' 26 | compile 'com.github.eigenein:joypad-android:5' 27 | compile 'com.android.support:cardview-v7:26.1.0' 28 | compile 'io.reactivex.rxjava2:rxandroid:2.0.1' 29 | compile 'io.reactivex.rxjava2:rxjava:2.1.6' 30 | } 31 | repositories { 32 | mavenCentral() 33 | maven { url "https://jitpack.io" } 34 | maven { url "https://maven.google.com" } 35 | } 36 | -------------------------------------------------------------------------------- /android/app/src/main/java/me/eigenein/arduinocar/OutputMessage.kt: -------------------------------------------------------------------------------- 1 | package me.eigenein.arduinocar 2 | 3 | import java.io.OutputStream 4 | 5 | interface OutputMessage 6 | 7 | data class DeprecatedNoOperationOutputMessage(val unit: Unit) : OutputMessage 8 | data class DeprecatedBrakeOutputMessage(val unit: Unit) : OutputMessage 9 | data class DeprecatedMoveOutputMessage(val left: Float, val right: Float) : OutputMessage 10 | 11 | val deprecatedNoOperationOutputMessage = DeprecatedNoOperationOutputMessage(Unit) 12 | val deprecatedBrakeOutputMessage = DeprecatedBrakeOutputMessage(Unit) 13 | 14 | fun OutputStream.writeMessage(message: OutputMessage) = write( 15 | when (message) { 16 | is DeprecatedNoOperationOutputMessage -> byteArrayOf(0x01) 17 | is DeprecatedBrakeOutputMessage -> byteArrayOf(0x02) 18 | is DeprecatedMoveOutputMessage -> byteArrayOf( 19 | 0x03, 20 | speedToByte(message.left), 21 | if (message.left < 0f) 1 else 0, 22 | speedToByte(message.right), 23 | if (message.right < 0f) 1 else 0 24 | ) 25 | else -> byteArrayOf() 26 | } 27 | ) 28 | 29 | private fun speedToByte(speed: Float) = (Math.abs(speed) * 255f).toByte() 30 | -------------------------------------------------------------------------------- /android/app/src/main/java/me/eigenein/arduinocar/BluetoothExtensions.kt: -------------------------------------------------------------------------------- 1 | package me.eigenein.arduinocar 2 | 3 | import android.bluetooth.BluetoothDevice 4 | import android.util.Log 5 | import io.reactivex.Observable 6 | import io.reactivex.schedulers.Schedulers 7 | import io.reactivex.subjects.Subject 8 | import java.util.* 9 | 10 | private val logTag = "BluetoothExtensions" 11 | private val serialUUID = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB") 12 | 13 | fun BluetoothDevice.messages(subject: Subject): Observable = Observable.using({ 14 | Log.i(logTag, "Connecting to %s".format(name)) 15 | val socket = this.createRfcommSocketToServiceRecord(serialUUID) 16 | socket.connect() 17 | Log.i(logTag, "Connected to %s".format(name)) 18 | 19 | val outputSubscription = subject 20 | .subscribeOn(Schedulers.newThread()) 21 | .subscribe { 22 | Log.d(logTag, "Output message: %s".format(it)) 23 | socket.outputStream.writeMessage(it) 24 | } 25 | 26 | Pair(socket, outputSubscription) 27 | }, { 28 | val (socket, _) = it 29 | 30 | Observable.concat( 31 | Observable.just(ConnectedMessage(name)), 32 | Observable.fromIterable(socket.inputStream.messageIterable()) 33 | ) 34 | }, { 35 | val (socket, outputSubscription) = it 36 | Log.i(logTag, "Closing connection to %s".format(name)) 37 | outputSubscription.dispose() 38 | socket.close() 39 | }) 40 | -------------------------------------------------------------------------------- /arduino/.travis.yml: -------------------------------------------------------------------------------- 1 | # Continuous Integration (CI) is the practice, in software 2 | # engineering, of merging all developer working copies with a shared mainline 3 | # several times a day < http://docs.platformio.org/page/ci/index.html > 4 | # 5 | # Documentation: 6 | # 7 | # * Travis CI Embedded Builds with PlatformIO 8 | # < https://docs.travis-ci.com/user/integration/platformio/ > 9 | # 10 | # * PlatformIO integration with Travis CI 11 | # < http://docs.platformio.org/page/ci/travis.html > 12 | # 13 | # * User Guide for `platformio ci` command 14 | # < http://docs.platformio.org/page/userguide/cmd_ci.html > 15 | # 16 | # 17 | # Please choice one of the following templates (proposed below) and uncomment 18 | # it (remove "# " before each line) or use own configuration according to the 19 | # Travis CI documentation (see above). 20 | # 21 | 22 | 23 | # 24 | # Template #1: General project. Test it using existing `platformio.ini`. 25 | # 26 | 27 | # language: python 28 | # python: 29 | # - "2.7" 30 | # 31 | # sudo: false 32 | # cache: 33 | # directories: 34 | # - "~/.platformio" 35 | # 36 | # install: 37 | # - pip install -U platformio 38 | # 39 | # script: 40 | # - platformio run 41 | 42 | 43 | # 44 | # Template #2: The project is intended to by used as a library with examples 45 | # 46 | 47 | # language: python 48 | # python: 49 | # - "2.7" 50 | # 51 | # sudo: false 52 | # cache: 53 | # directories: 54 | # - "~/.platformio" 55 | # 56 | # env: 57 | # - PLATFORMIO_CI_SRC=path/to/test/file.c 58 | # - PLATFORMIO_CI_SRC=examples/file.ino 59 | # - PLATFORMIO_CI_SRC=path/to/test/directory 60 | # 61 | # install: 62 | # - pip install -U platformio 63 | # 64 | # script: 65 | # - platformio ci --lib="." --board=ID_1 --board=ID_2 --board=ID_N 66 | -------------------------------------------------------------------------------- /schematic/svg.pcb.L9110 H-bridge_9eed947992b17e43635203677d03ae4a_2_pcb.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | generic_male_pin_header_6_100mil_hs_0.7mm_0.508mm.svg 5 | 6 | Fritzing footprint SVG 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /android/.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 16 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | Android 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 49 | -------------------------------------------------------------------------------- /android/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 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 12 | set DEFAULT_JVM_OPTS= 13 | 14 | set DIRNAME=%~dp0 15 | if "%DIRNAME%" == "" set DIRNAME=. 16 | set APP_BASE_NAME=%~n0 17 | set APP_HOME=%DIRNAME% 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 Windowz variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | if "%@eval[2+2]" == "4" goto 4NT_args 53 | 54 | :win9xME_args 55 | @rem Slurp the command line arguments. 56 | set CMD_LINE_ARGS= 57 | set _SKIP=2 58 | 59 | :win9xME_args_slurp 60 | if "x%~1" == "x" goto execute 61 | 62 | set CMD_LINE_ARGS=%* 63 | goto execute 64 | 65 | :4NT_args 66 | @rem Get arguments from the 4NT Shell from JP Software 67 | set CMD_LINE_ARGS=%$ 68 | 69 | :execute 70 | @rem Setup the command line 71 | 72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if "%ERRORLEVEL%"=="0" goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 85 | exit /b 1 86 | 87 | :mainEnd 88 | if "%OS%"=="Windows_NT" endlocal 89 | 90 | :omega 91 | -------------------------------------------------------------------------------- /android/app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 10 | 11 | 21 | 22 | 33 | 34 | 35 | 46 | 47 | 57 | 58 | 59 | 60 | -------------------------------------------------------------------------------- /arduino/src/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | // Define supported processors. 4 | // ------------------------------------------------------------------------------------------------- 5 | 6 | #if !defined(__AVR_ATmega328P__) 7 | #error "ATmega328 only is supported at the moment." 8 | #endif 9 | 10 | // Command definitions. 11 | // ------------------------------------------------------------------------------------------------- 12 | 13 | const unsigned int BYTE_ORDER_MARK = 0xFEFF; 14 | 15 | const int MESSAGE_NOOP = 0x01; 16 | const int MESSAGE_BRAKE = 0x02; 17 | const int MESSAGE_MOVE = 0x03; 18 | 19 | const int SPEED_FULL = 255; 20 | const int FLAG_INVERSE = 1; 21 | 22 | // Pins. 23 | // ------------------------------------------------------------------------------------------------- 24 | 25 | const int PIN_LEFT_OUTPUT = 2; 26 | const int PIN_LEFT_PWM = 3; // FIXME: change to 6 (because 3 and 5 are on different timers). 27 | const int PIN_RIGHT_OUTPUT = 4; 28 | const int PIN_RIGHT_PWM = 5; 29 | const int PIN_INDICATOR = 13; 30 | 31 | // Main loop. 32 | // ------------------------------------------------------------------------------------------------- 33 | 34 | int blockingRead() { 35 | while (!Serial.available()); 36 | return Serial.read(); 37 | } 38 | 39 | void brake() { 40 | digitalWrite(PIN_LEFT_OUTPUT, HIGH); 41 | digitalWrite(PIN_LEFT_PWM, HIGH); 42 | 43 | digitalWrite(PIN_RIGHT_OUTPUT, HIGH); 44 | digitalWrite(PIN_RIGHT_PWM, HIGH); 45 | } 46 | 47 | bool receiveCommand() { 48 | switch (blockingRead()) { 49 | 50 | case MESSAGE_NOOP: 51 | break; 52 | 53 | case MESSAGE_MOVE: 54 | { 55 | int leftSpeed = blockingRead(); 56 | int leftInverse = blockingRead(); 57 | int rightSpeed = blockingRead(); 58 | int rightInverse = blockingRead(); 59 | // Left wheel. 60 | digitalWrite(PIN_LEFT_OUTPUT, leftInverse != FLAG_INVERSE ? LOW : HIGH); 61 | analogWrite(PIN_LEFT_PWM, leftInverse != FLAG_INVERSE ? leftSpeed : 255 - leftSpeed); 62 | // Right wheel. 63 | digitalWrite(PIN_RIGHT_OUTPUT, rightInverse != FLAG_INVERSE ? LOW : HIGH); 64 | analogWrite(PIN_RIGHT_PWM, rightInverse != FLAG_INVERSE ? rightSpeed : 255 - rightSpeed); 65 | } 66 | break; 67 | 68 | case MESSAGE_BRAKE: 69 | brake(); 70 | break; 71 | 72 | default: 73 | return false; 74 | } 75 | return true; 76 | } 77 | 78 | long readVcc() { 79 | long vcc; 80 | 81 | ADMUX = _BV(REFS0) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1); 82 | delay(1); 83 | ADCSRA |= _BV(ADSC); 84 | while (bit_is_set(ADCSRA, ADSC)); 85 | vcc = ADCL; 86 | vcc |= ADCH << 8; 87 | vcc = 1126400L / vcc; 88 | 89 | return vcc; 90 | } 91 | 92 | void sendTelemetry() { 93 | digitalWrite(PIN_INDICATOR, HIGH); 94 | Serial.write((char*)&BYTE_ORDER_MARK, sizeof(BYTE_ORDER_MARK)); 95 | long vcc = readVcc(); 96 | Serial.write((char*)&vcc, sizeof(vcc)); 97 | digitalWrite(PIN_INDICATOR, LOW); 98 | } 99 | 100 | // Entry point. 101 | // ------------------------------------------------------------------------------------------------- 102 | 103 | void setup() { 104 | // Set the maximum possible PWM frequency for the motors. 105 | // http://forum.arduino.cc/index.php?topic=16612.msg121031#msg121031 106 | TCCR0B = (TCCR0B & 0b11111000) | 0x01; 107 | TCCR2B = (TCCR2B & 0b11111000) | 0x01; // FIXME: remove after changing PIN_LEFT_PWM. 108 | 109 | pinMode(PIN_LEFT_OUTPUT, OUTPUT); 110 | pinMode(PIN_LEFT_PWM, OUTPUT); 111 | 112 | pinMode(PIN_RIGHT_OUTPUT, OUTPUT); 113 | pinMode(PIN_RIGHT_PWM, OUTPUT); 114 | 115 | pinMode(PIN_INDICATOR, OUTPUT); 116 | 117 | brake(); 118 | Serial.begin(9600); 119 | } 120 | 121 | void loop() { 122 | if (receiveCommand()) { 123 | sendTelemetry(); 124 | } 125 | } 126 | -------------------------------------------------------------------------------- /android/gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 10 | DEFAULT_JVM_OPTS="" 11 | 12 | APP_NAME="Gradle" 13 | APP_BASE_NAME=`basename "$0"` 14 | 15 | # Use the maximum available, or set MAX_FD != -1 to use that value. 16 | MAX_FD="maximum" 17 | 18 | warn ( ) { 19 | echo "$*" 20 | } 21 | 22 | die ( ) { 23 | echo 24 | echo "$*" 25 | echo 26 | exit 1 27 | } 28 | 29 | # OS specific support (must be 'true' or 'false'). 30 | cygwin=false 31 | msys=false 32 | darwin=false 33 | case "`uname`" in 34 | CYGWIN* ) 35 | cygwin=true 36 | ;; 37 | Darwin* ) 38 | darwin=true 39 | ;; 40 | MINGW* ) 41 | msys=true 42 | ;; 43 | esac 44 | 45 | # Attempt to set APP_HOME 46 | # Resolve links: $0 may be a link 47 | PRG="$0" 48 | # Need this for relative symlinks. 49 | while [ -h "$PRG" ] ; do 50 | ls=`ls -ld "$PRG"` 51 | link=`expr "$ls" : '.*-> \(.*\)$'` 52 | if expr "$link" : '/.*' > /dev/null; then 53 | PRG="$link" 54 | else 55 | PRG=`dirname "$PRG"`"/$link" 56 | fi 57 | done 58 | SAVED="`pwd`" 59 | cd "`dirname \"$PRG\"`/" >/dev/null 60 | APP_HOME="`pwd -P`" 61 | cd "$SAVED" >/dev/null 62 | 63 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 64 | 65 | # Determine the Java command to use to start the JVM. 66 | if [ -n "$JAVA_HOME" ] ; then 67 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 68 | # IBM's JDK on AIX uses strange locations for the executables 69 | JAVACMD="$JAVA_HOME/jre/sh/java" 70 | else 71 | JAVACMD="$JAVA_HOME/bin/java" 72 | fi 73 | if [ ! -x "$JAVACMD" ] ; then 74 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 75 | 76 | Please set the JAVA_HOME variable in your environment to match the 77 | location of your Java installation." 78 | fi 79 | else 80 | JAVACMD="java" 81 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 82 | 83 | Please set the JAVA_HOME variable in your environment to match the 84 | location of your Java installation." 85 | fi 86 | 87 | # Increase the maximum file descriptors if we can. 88 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then 89 | MAX_FD_LIMIT=`ulimit -H -n` 90 | if [ $? -eq 0 ] ; then 91 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 92 | MAX_FD="$MAX_FD_LIMIT" 93 | fi 94 | ulimit -n $MAX_FD 95 | if [ $? -ne 0 ] ; then 96 | warn "Could not set maximum file descriptor limit: $MAX_FD" 97 | fi 98 | else 99 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 100 | fi 101 | fi 102 | 103 | # For Darwin, add options to specify how the application appears in the dock 104 | if $darwin; then 105 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 106 | fi 107 | 108 | # For Cygwin, switch paths to Windows format before running java 109 | if $cygwin ; then 110 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 111 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 112 | JAVACMD=`cygpath --unix "$JAVACMD"` 113 | 114 | # We build the pattern for arguments to be converted via cygpath 115 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 116 | SEP="" 117 | for dir in $ROOTDIRSRAW ; do 118 | ROOTDIRS="$ROOTDIRS$SEP$dir" 119 | SEP="|" 120 | done 121 | OURCYGPATTERN="(^($ROOTDIRS))" 122 | # Add a user-defined pattern to the cygpath arguments 123 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 124 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 125 | fi 126 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 127 | i=0 128 | for arg in "$@" ; do 129 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 130 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 131 | 132 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 133 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 134 | else 135 | eval `echo args$i`="\"$arg\"" 136 | fi 137 | i=$((i+1)) 138 | done 139 | case $i in 140 | (0) set -- ;; 141 | (1) set -- "$args0" ;; 142 | (2) set -- "$args0" "$args1" ;; 143 | (3) set -- "$args0" "$args1" "$args2" ;; 144 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 145 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 146 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 147 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 148 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 149 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 150 | esac 151 | fi 152 | 153 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules 154 | function splitJvmOpts() { 155 | JVM_OPTS=("$@") 156 | } 157 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS 158 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" 159 | 160 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" 161 | -------------------------------------------------------------------------------- /android/app/src/main/java/me/eigenein/arduinocar/MainActivity.kt: -------------------------------------------------------------------------------- 1 | package me.eigenein.arduinocar 2 | 3 | import android.app.Activity 4 | import android.bluetooth.BluetoothAdapter 5 | import android.bluetooth.BluetoothDevice 6 | import android.content.Intent 7 | import android.os.Bundle 8 | import android.util.Log 9 | import android.view.Menu 10 | import android.view.MenuItem 11 | import android.view.WindowManager 12 | import android.widget.ProgressBar 13 | import android.widget.Toast 14 | import io.reactivex.android.schedulers.AndroidSchedulers 15 | import io.reactivex.disposables.CompositeDisposable 16 | import io.reactivex.schedulers.Schedulers 17 | import io.reactivex.subjects.PublishSubject 18 | import ninja.eigenein.joypad.JoypadView 19 | import ninja.eigenein.joypad.WheelsPower 20 | import java.io.IOException 21 | 22 | class MainActivity : Activity(), JoypadView.Listener { 23 | 24 | private val logTag = MainActivity::class.java.simpleName 25 | private val connectRetriesCount = 5L 26 | 27 | private val outputMessagesSubject = PublishSubject.create() 28 | private val connectionDisposable = CompositeDisposable() 29 | 30 | private lateinit var joypadView: JoypadView 31 | private lateinit var progressBar: ProgressBar 32 | 33 | private lateinit var deviceNameMenuItem: MenuItem 34 | private lateinit var vccMenuItem: MenuItem 35 | 36 | override fun onCreate(savedInstanceState: Bundle?) { 37 | super.onCreate(savedInstanceState) 38 | window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON) 39 | setContentView(R.layout.activity_main) 40 | 41 | joypadView = findViewById(R.id.joypad_view) 42 | joypadView.setListener(this) 43 | progressBar = findViewById(R.id.progress_bar) 44 | } 45 | 46 | override fun onCreateOptionsMenu(menu: Menu): Boolean { 47 | menuInflater.inflate(R.menu.menu_main, menu) 48 | deviceNameMenuItem = menu.findItem(R.id.menu_main_device_name) 49 | vccMenuItem = menu.findItem(R.id.menu_main_vcc) 50 | return true 51 | } 52 | 53 | override fun onOptionsItemSelected(item: MenuItem): Boolean { 54 | return when (item.itemId) { 55 | R.id.menu_main_connect -> { 56 | connectionDisposable.clear() // close any existing connection beforehand 57 | showDevicesDialog { connectTo(it) } 58 | return true 59 | } 60 | else -> super.onOptionsItemSelected(item) 61 | } 62 | } 63 | 64 | override fun onPause() { 65 | super.onPause() 66 | connectionDisposable.clear() 67 | } 68 | 69 | override fun onUp() { 70 | outputMessagesSubject.onNext(deprecatedBrakeOutputMessage) 71 | } 72 | 73 | override fun onMove(distance: Float, dx: Float, dy: Float) { 74 | val wheelsPower = WheelsPower.wheelsPower(distance, dx, dy) 75 | outputMessagesSubject.onNext(DeprecatedMoveOutputMessage(wheelsPower.left, wheelsPower.right)) 76 | } 77 | 78 | private fun showDevicesDialog(listener: (BluetoothDevice) -> Unit) { 79 | val bluetoothAdapter = BluetoothAdapter.getDefaultAdapter() 80 | if (!bluetoothAdapter.isEnabled) { 81 | startActivityForResult(Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE), 0) 82 | return 83 | } 84 | val devices = bluetoothAdapter.bondedDevices.sortedBy { it.name }.toTypedArray() 85 | if (devices.isEmpty()) { 86 | Toast.makeText(this, R.string.toast_no_paired_devices, Toast.LENGTH_LONG).show() 87 | return 88 | } 89 | showAlertDialog(this) { 90 | setTitle(R.string.dialog_title_choose_vehicle) 91 | setCancelable(true) 92 | setItems(devices.map { it.name }.toTypedArray(), { _, which -> listener(devices[which]) }) 93 | } 94 | } 95 | 96 | private fun connectTo(device: BluetoothDevice) { 97 | connectionDisposable.clear() // close any still existing connection 98 | connectionDisposable.add( 99 | device.messages(outputMessagesSubject) 100 | .subscribeOn(Schedulers.newThread()) 101 | .retry(connectRetriesCount) 102 | .observeOn(AndroidSchedulers.mainThread()) 103 | .subscribe( 104 | { onInputMessage(it) }, 105 | { 106 | if (it !is IOException) { 107 | throw RuntimeException(it) // non-IO errors shouldn't be suppressed 108 | } 109 | Log.e(logTag, "Connection to " + device.name + " failed") 110 | Toast.makeText(this, getString(R.string.toast_connection_failed, device.name), Toast.LENGTH_SHORT).show() 111 | progressBar.gone() 112 | }, 113 | { Log.e(logTag, "Connection stream ended") }, 114 | { 115 | // FIXME: the handler doesn't work on retries. 116 | Toast.makeText(this, getString(R.string.toast_connecting, device.name), Toast.LENGTH_SHORT).show() 117 | progressBar.show() 118 | } 119 | ) 120 | ) 121 | } 122 | 123 | private fun onInputMessage(message: InputMessage) { 124 | Log.d(logTag, "Input message: %s".format(message)) 125 | when (message) { 126 | is ConnectedMessage -> { 127 | deviceNameMenuItem.title = message.device_name 128 | Toast.makeText(this, getString(R.string.toast_connected, message.device_name), Toast.LENGTH_SHORT).show() 129 | progressBar.gone() 130 | outputMessagesSubject.onNext(deprecatedNoOperationOutputMessage) // FIXME 131 | } 132 | is DeprecatedTelemetryMessage -> vccMenuItem.title = "%.2fV".format(message.vcc) 133 | } 134 | } 135 | } 136 | -------------------------------------------------------------------------------- /schematic/part.L9110 H-bridge_02eed2341d1f9ec262679b574ab39474_11.fzp: -------------------------------------------------------------------------------- 1 | 2 | 3 | Igor Fonseca Albuquerque 4 | L9110 H-bridge module 5 | 6 | sex fev 17 2017 7 | 8 | L9110 9 | h-bridge 10 | 11 | 12 | variant 1 13 | L9110 14 | L9110 H-bridge 15 | 16 | 17 | <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> 18 | <html><head><meta name="qrichtext" content="1" /><style type="text/css"> 19 | p, li { white-space: pre-wrap; } 20 | </style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> 21 | <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Ubuntu'; font-size:11pt;">L9110 H-bridge module</span></p></body></html> 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 2.5 to 12V 49 | 50 | 51 |

52 | 53 | 54 |

55 | 56 | 57 |

58 |

59 | 60 | 61 | 62 | 63 | Digital input 64 | 65 | 66 |

67 | 68 | 69 |

70 | 71 | 72 |

73 |

74 | 75 | 76 | 77 | 78 | Digital input 79 | 80 | 81 |

82 | 83 | 84 |

85 | 86 | 87 |

88 |

89 | 90 | 91 | 92 | 93 | Digital input 94 | 95 | 96 |

97 | 98 | 99 |

100 | 101 | 102 |

103 |

104 | 105 | 106 | 107 | 108 | Digital input 109 | 110 | 111 |

112 | 113 | 114 |

115 | 116 | 117 |

118 |

119 | 120 | 121 | 122 | 123 | GND 124 | 125 | 126 |

127 | 128 | 129 |

130 | 131 | 132 |

133 |

134 | 135 | 136 | 137 | 138 | pin 6 139 | 140 | 141 |

142 | 143 | 144 |

145 | 146 | 147 |

148 |

149 | 150 | 151 | 152 | 153 | pin 7 154 | 155 | 156 |

157 | 158 | 159 |

160 | 161 | 162 |

163 |

164 | 165 | 166 | 167 | 168 | pin 8 169 | 170 | 171 |

172 | 173 | 174 |

175 | 176 | 177 |

178 |

179 | 180 | 181 | 182 | 183 | pin 9 184 | 185 | 186 |

187 | 188 | 189 |

190 | 191 | 192 |

193 |

194 | 195 | 196 | 197 | 198 | 199 | 200 | -------------------------------------------------------------------------------- /schematic/svg.schematic.L9110 H-bridge_9eed947992b17e43635203677d03ae4a_2_schematic.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | image/svg+xml 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | generic_ic_dip_8_schem.svg 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | VCC 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | IA-A 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | IA-B 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | IB-A 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 | 270 | 271 | 272 | 273 | 274 | 275 | IB-B 276 | 277 | 278 | 279 | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299 | 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308 | 309 | 310 | 311 | 312 | 313 | 314 | 315 | 316 | 317 | 318 | 319 | 320 | 321 | 322 | 323 | 324 | 325 | 326 | 327 | 328 | 329 | 330 | 331 | 332 | 333 | 334 | 335 | 336 | 337 | 338 | 339 | 340 | 341 | 342 | 343 | 344 | 345 | 346 | 347 | 348 | 349 | 350 | 351 | 352 | 353 | 354 | 355 | 356 | 357 | GND 358 | 359 | 360 | 361 | 362 | 363 | 364 | 365 | 366 | 367 | 368 | 369 | 370 | 371 | 372 | 373 | 374 | 375 | 376 | 377 | 378 | 379 | 380 | 381 | 382 | 383 | 384 | 385 | 386 | 387 | 388 | 389 | 390 | 391 | 392 | 393 | 394 | 395 | 396 | 397 | 398 | 399 | 400 | 401 | 402 | 403 | 404 | 405 | 406 | 407 | 408 | 409 | 410 | 411 | 412 | 413 | 414 | 415 | 416 | 417 | 418 | 419 | 420 | 421 | 422 | 423 | 424 | 425 | 426 | 427 | 428 | 429 | 430 | 431 | 432 | 433 | 434 | 435 | 436 | 437 | 438 | 439 | 440 | 441 | 442 | 443 | 444 | 445 | 446 | 447 | 448 | 449 | 450 | 451 | 452 | 453 | 454 | 455 | 456 | 457 | 458 | 459 | 460 | 461 | 462 | 463 | 464 | 465 | 466 | 467 | 468 | 469 | 470 | 471 | 472 | 473 | 474 | 475 | 476 | 477 | 478 | 479 | 480 | 481 | 482 | 483 | 484 | 485 | 486 | 487 | 488 | 489 | 490 | 491 | 492 | 493 | 494 | 495 | 496 | 497 | 498 | 499 | 500 | 501 | 502 | 503 | 504 | 505 | 506 | 507 | 508 | 509 | 510 | 511 | 512 | 513 | 514 | 515 | 516 | 517 | 518 | 519 | 520 | 521 | 522 | 523 | 524 | 525 | 526 | 527 | 528 | 529 | 530 | 531 | 532 | 533 | 534 | 535 | 536 | 537 | 538 | 539 | 540 | 541 | 542 | 543 | 544 | 545 | 546 | 547 | 548 | 549 | 550 | 551 | 552 | 553 | 554 | 555 | 556 | 557 | 558 | 559 | 560 | 561 | 562 | 563 | 564 | 565 | 566 | 567 | 568 | 569 | 570 | 571 | 572 | 573 | 574 | 575 | 576 | 577 | 578 | 579 | 580 | 581 | 582 | 583 | 584 | 585 | 586 | 587 | 588 | 589 | 590 | 591 | 592 | 593 | 594 | 595 | 596 | 597 | 598 | 599 | 600 | 601 | 602 | 603 | 604 | 605 | 606 | 607 | 608 | 609 | 610 | 611 | 612 | 613 | 614 | 615 | 616 | 617 | 618 | 619 | 620 | 621 | 622 | 623 | 624 | 625 | 626 | 627 | 628 | 629 | 630 | 631 | 632 | 633 | 634 | 635 | 636 | 637 | 638 | 639 | 640 | 641 | 642 | 643 | 644 | 645 | 646 | 647 | 648 | MOTOR A-A 649 | 650 | 651 | 652 | 653 | 654 | 655 | 656 | 657 | 658 | 659 | 660 | 661 | 662 | 663 | 664 | 665 | 666 | 667 | 668 | 669 | MOTOR A-B 670 | 671 | 672 | 673 | 674 | 675 | 676 | 677 | 678 | 679 | 680 | 681 | 682 | 683 | 684 | 685 | 686 | 687 | 688 | 689 | 690 | MOTOR B-A 691 | 692 | 693 | 694 | 695 | 696 | 697 | 698 | 699 | 700 | 701 | 702 | 703 | 704 | 705 | 706 | 707 | 708 | 709 | 710 | 711 | MOTOR B-B 712 | 713 | 714 | 715 | 716 | 717 | 718 | 719 | 720 | 721 | 722 | 723 | 724 | 725 | --------------------------------------------------------------------------------