├── 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 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/android/.idea/inspectionProfiles/Project_Default.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
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 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
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 |
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 | 
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 |
26 |
--------------------------------------------------------------------------------
/android/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 | Android
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
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 |
725 |
--------------------------------------------------------------------------------