├── release_files.json ├── eff-uno-racer ├── episode3 │ ├── model.png │ ├── spoolholder.png │ └── episode3.md ├── episode2 │ ├── PiImager.png │ ├── breadboard.jpg │ ├── carpi.py │ ├── carduino.ino │ └── pi-motors.md └── episode1 │ ├── breadboard.jpg │ ├── breadboard2.png │ ├── GrandfathersElectronics.jpg │ └── new-project.md ├── license_policy.yml ├── sonar-project.properties ├── .github └── workflows │ ├── release-zip-file.yml │ ├── sonarcloud.yml │ ├── license_audit.yml │ ├── cla.yml │ ├── repolinter.yml │ └── banned_file_changes_pr.yml ├── .gitignore ├── README.md ├── repolinter.json └── LICENSE /release_files.json: -------------------------------------------------------------------------------- 1 | // see https://github.com/oracle-devrel/action-release-zip-maker for docs 2 | [ 3 | ] 4 | -------------------------------------------------------------------------------- /eff-uno-racer/episode3/model.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ttscoff/chris-blogs/main/eff-uno-racer/episode3/model.png -------------------------------------------------------------------------------- /eff-uno-racer/episode2/PiImager.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ttscoff/chris-blogs/main/eff-uno-racer/episode2/PiImager.png -------------------------------------------------------------------------------- /eff-uno-racer/episode1/breadboard.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ttscoff/chris-blogs/main/eff-uno-racer/episode1/breadboard.jpg -------------------------------------------------------------------------------- /eff-uno-racer/episode1/breadboard2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ttscoff/chris-blogs/main/eff-uno-racer/episode1/breadboard2.png -------------------------------------------------------------------------------- /eff-uno-racer/episode2/breadboard.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ttscoff/chris-blogs/main/eff-uno-racer/episode2/breadboard.jpg -------------------------------------------------------------------------------- /eff-uno-racer/episode3/spoolholder.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ttscoff/chris-blogs/main/eff-uno-racer/episode3/spoolholder.png -------------------------------------------------------------------------------- /license_policy.yml: -------------------------------------------------------------------------------- 1 | license_policies: 2 | - license_key: upl-1.0 3 | label: Approved License 4 | color_code: '#00800' 5 | icon: icon-ok-circle 6 | -------------------------------------------------------------------------------- /eff-uno-racer/episode1/GrandfathersElectronics.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ttscoff/chris-blogs/main/eff-uno-racer/episode1/GrandfathersElectronics.jpg -------------------------------------------------------------------------------- /sonar-project.properties: -------------------------------------------------------------------------------- 1 | sonar.projectKey=oracle-devrel_chris-blogs 2 | sonar.organization=oracle-devrel 3 | 4 | # This is the name and version displayed in the SonarCloud UI. 5 | #sonar.projectName=test 6 | #sonar.projectVersion=1.0 7 | 8 | # Path is relative to the sonar-project.properties file. Replace "\" by "/" on Windows. 9 | #sonar.sources=. 10 | 11 | # Encoding of the source code. Default is default system encoding 12 | #sonar.sourceEncoding=UTF-8 -------------------------------------------------------------------------------- /.github/workflows/release-zip-file.yml: -------------------------------------------------------------------------------- 1 | name: Release ZIP file packaging 2 | 3 | on: 4 | release: 5 | types: [published] 6 | 7 | jobs: 8 | create_zip: 9 | runs-on: ubuntu-latest 10 | steps: 11 | - name: 'Checkout repo' 12 | uses: actions/checkout@v2 13 | - name: 'Make (and upload) ZIP file(s)' 14 | uses: oracle-devrel/action-release-zip-maker@v0.5 15 | id: zip_maker 16 | with: 17 | github_token: ${{ secrets.GITHUB_TOKEN }} 18 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # General 2 | .DS_Store 3 | .AppleDouble 4 | .LSOverride 5 | 6 | # Icon must end with two \r 7 | Icon 8 | 9 | 10 | # Thumbnails 11 | ._* 12 | 13 | # Files that might appear in the root of a volume 14 | .DocumentRevisions-V100 15 | .fseventsd 16 | .Spotlight-V100 17 | .TemporaryItems 18 | .Trashes 19 | .VolumeIcon.icns 20 | .com.apple.timemachine.donotpresent 21 | 22 | # Directories potentially created on remote AFP share 23 | .AppleDB 24 | .AppleDesktop 25 | Network Trash Folder 26 | Temporary Items 27 | .apdisk 28 | 29 | # ignore common security keys 30 | .key 31 | .crt 32 | .csr 33 | .pem -------------------------------------------------------------------------------- /eff-uno-racer/episode2/carpi.py: -------------------------------------------------------------------------------- 1 | from smbus import SMBus 2 | import time 3 | import sys 4 | 5 | if (len(sys.argv) != 3): 6 | print("Error: Not enough arguments") 7 | exit() 8 | 9 | device = int(sys.argv[1]) 10 | value = int(sys.argv[2]) 11 | print("device " + str(device)) 12 | print("value " + str(value)) 13 | 14 | 15 | bus = SMBus(1) # 512M Pi use i2c port 1, 256M Pi use i2c port 0 16 | time.sleep(1) 17 | address = 0x8 18 | 19 | if (value < 256): 20 | bus.write_i2c_block_data(address, device, [value]) 21 | else: 22 | high, low = value >> 4, value & 0x0FF 23 | print(high) 24 | print(low) 25 | bus.write_i2c_block_data(address, device, [high, low]) 26 | 27 | bus.close() 28 | -------------------------------------------------------------------------------- /.github/workflows/sonarcloud.yml: -------------------------------------------------------------------------------- 1 | name: SonarCloud Scan 2 | on: 3 | pull_request_target: 4 | jobs: 5 | sonarcloud: 6 | name: SonarCloud 7 | runs-on: ubuntu-latest 8 | steps: 9 | - name: Checkout repo 10 | uses: actions/checkout@v2 11 | with: 12 | ref: ${{ github.event.pull_request.head.ref }} 13 | repository: ${{ github.event.pull_request.head.repo.full_name }} 14 | fetch-depth: 0 # Shallow clones should be disabled for a better relevancy of analysis 15 | - name: SonarCloud Scan 16 | uses: SonarSource/sonarcloud-github-action@master 17 | env: 18 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # Needed to get PR information, if any 19 | SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Chris builds 2 | 3 | [![License: UPL](https://img.shields.io/badge/license-UPL-green)](https://img.shields.io/badge/license-UPL-green) [![Quality gate](https://sonarcloud.io/api/project_badges/quality_gate?project=oracle-devrel_chris-blogs)](https://sonarcloud.io/dashboard?id=oracle-devrel_chris-blogs) 4 | 5 | ## Introduction 6 | MISSING 7 | 8 | ## Getting Started 9 | MISSING 10 | 11 | ### Prerequisites 12 | MISSING 13 | 14 | ## Notes/Issues 15 | MISSING 16 | 17 | ## URLs 18 | * Nothing at this time 19 | 20 | ## Contributing 21 | This project is open source. Please submit your contributions by forking this repository and submitting a pull request! Oracle appreciates any contributions that are made by the open source community. 22 | 23 | ## License 24 | Copyright (c) 2021 Oracle and/or its affiliates. 25 | 26 | Licensed under the Universal Permissive License (UPL), Version 1.0. 27 | 28 | See [LICENSE](LICENSE) for more details. 29 | -------------------------------------------------------------------------------- /repolinter.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://raw.githubusercontent.com/todogroup/repolinter/master/rulesets/schema.json", 3 | "version": 2, 4 | "axioms": {}, 5 | "rules": { 6 | "readme-file-exists" : { 7 | "level": "error", 8 | "rule": { 9 | "type": "file-existence", 10 | "options": { 11 | "globsAny": ["README*"] 12 | } 13 | } 14 | }, 15 | "license-file-exists" : { 16 | "level": "error", 17 | "rule": { 18 | "type": "file-existence", 19 | "options": { 20 | "globsAny": ["LICENSE*"] 21 | } 22 | } 23 | }, 24 | "copyright-notice-present" : { 25 | "level": "warning", 26 | "rule": { 27 | "type": "file-starts-with", 28 | "options": { 29 | "globsAll": ["**/*"], 30 | "skip-binary-files": true, 31 | "skip-paths-matching": { 32 | "extensions": ["yaml","yml","md","json","xml","tpl","ipynb","pickle","joblib","properties"], 33 | "patterns": ["\\.github"], 34 | "flags": "" 35 | }, 36 | "lineCount": 2, 37 | "patterns": [ 38 | "Copyright \\([cC]\\) [12][90]\\d\\d(\\-[12][90]\\d\\d)? Oracle and/or its affiliates\\." 39 | ], 40 | "succeed-on-non-exist": true 41 | } 42 | } 43 | } 44 | } 45 | } -------------------------------------------------------------------------------- /.github/workflows/license_audit.yml: -------------------------------------------------------------------------------- 1 | name: Audit licenses 2 | on: 3 | pull_request_target: 4 | 5 | jobs: 6 | run_scancode_toolkit: 7 | name: Get inventory of licenses used in project 8 | runs-on: ubuntu-latest 9 | container: 10 | image: ghcr.io/oracledevrel/scancode-toolkit:v21.3.31 11 | credentials: 12 | username: ${{ github.actor }} 13 | password: ${{ secrets.GHCR_PAT }} 14 | steps: 15 | - name: 'Checkout repo' 16 | uses: actions/checkout@v2 17 | with: 18 | ref: ${{ github.event.pull_request.head.ref }} 19 | repository: ${{ github.event.pull_request.head.repo.full_name }} 20 | - name: Run Scancode-toolkit 21 | run: | 22 | scancode -l --ignore licenses.json --ignore .github/**/* --ignore license_policy.yml --license-policy license_policy.yml --only-findings --summary --json-pp licenses.json * 23 | echo "\n\nHere is the licenses.json:\n" 24 | echo $(cat licenses.json) 25 | - name: Look for non-approved licenses 26 | uses: oracle-devrel/action-license-audit@v0.1-alpha2 27 | id: analysis 28 | with: 29 | licenses_file: '/github/workspace/licenses.json' 30 | - name: Analysis results 31 | run: echo "${{ steps.analysis.outputs.unapproved_licenses }}" 32 | - name: Comment if analysis finds unapproved licenses 33 | if: steps.analysis.outputs.unapproved_licenses == 'true' 34 | uses: mshick/add-pr-comment@v1 35 | with: 36 | message: | 37 | :no_entry: **License Inspection** 38 | Requires manual inspection. There are some licenses which dictate further analysis and review. 39 | repo-token: ${{ secrets.GITHUB_TOKEN }} 40 | - name: Halt pipeline on unapproved licenses 41 | if: steps.analysis.outputs.unapproved_licenses == 'true' 42 | run: exit 1 -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2021 Oracle and/or its affiliates. 2 | 3 | The Universal Permissive License (UPL), Version 1.0 4 | 5 | Subject to the condition set forth below, permission is hereby granted to any 6 | person obtaining a copy of this software, associated documentation and/or data 7 | (collectively the "Software"), free of charge and under any and all copyright 8 | rights in the Software, and any and all patent rights owned or freely 9 | licensable by each licensor hereunder covering either (i) the unmodified 10 | Software as contributed to or provided by such licensor, or (ii) the Larger 11 | Works (as defined below), to deal in both 12 | 13 | (a) the Software, and 14 | (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if 15 | one is included with the Software (each a "Larger Work" to which the Software 16 | is contributed by such licensors), 17 | 18 | without restriction, including without limitation the rights to copy, create 19 | derivative works of, display, perform, and distribute the Software and make, 20 | use, sell, offer for sale, import, export, have made, and have sold the 21 | Software and the Larger Work(s), and to sublicense the foregoing rights on 22 | either these or other terms. 23 | 24 | This license is subject to the following condition: 25 | The above copyright notice and either this complete permission notice or at 26 | a minimum a reference to the UPL must be included in all copies or 27 | substantial portions of the Software. 28 | 29 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 30 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 31 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 32 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 33 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 34 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 35 | SOFTWARE. -------------------------------------------------------------------------------- /eff-uno-racer/episode2/carduino.ino: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int servoPin = 10; 5 | int escPin = 11; 6 | 7 | int i2cAddress = 0x8; 8 | 9 | Servo esc; 10 | Servo servo; 11 | 12 | int status = 0; 13 | 14 | #define ERROR_READING 1 15 | #define INVALID_RANGE 2 16 | 17 | 18 | void setup() { 19 | Serial.begin(9600); 20 | 21 | Wire.begin(i2cAddress); 22 | Wire.onReceive(receiveEvent); 23 | Wire.onRequest(requestEvent); 24 | 25 | servo.attach(servoPin, 0, 180); // pin, min pulse width, max pulse width in microseconds 26 | 27 | esc.attach(escPin, 1500, 2000); // pin, min pulse width, max pulse width in microseconds 28 | esc.write(1500); // initialize the ESC 29 | delay(3000); 30 | 31 | Serial.println("starting"); 32 | } 33 | 34 | void loop() { 35 | } 36 | 37 | boolean range(int min, int max, int value) { 38 | return (min <= value) && (value <= max); 39 | } 40 | 41 | void receiveEvent(int byteCount) { 42 | Serial.print("receiveEvent: "); 43 | Serial.println(byteCount); 44 | 45 | if (byteCount > 1) { 46 | byte message = Wire.read(); 47 | 48 | switch (message) { 49 | case 1: { 50 | byte degrees = Wire.read(); 51 | Serial.print("servo: "); 52 | Serial.println(degrees); 53 | 54 | if (range(0, 180, degrees)) { 55 | servo.write(degrees); 56 | } 57 | else { 58 | status = INVALID_RANGE; 59 | } 60 | 61 | break; 62 | } 63 | 64 | case 2: { 65 | int speed = 0; 66 | 67 | if (byteCount == 3) { 68 | byte high = Wire.read(); 69 | byte low = Wire.read(); 70 | Serial.println(high); 71 | Serial.println(low); 72 | speed = 0; 73 | speed = (high << 4) | low; 74 | } 75 | else { 76 | speed = Wire.read(); 77 | } 78 | 79 | Serial.print("esc: "); 80 | Serial.println(speed); 81 | 82 | if (range(1000, 2000, speed)) { 83 | esc.write(speed); 84 | } 85 | else { 86 | status = INVALID_RANGE; 87 | } 88 | 89 | break; 90 | } 91 | 92 | default: { 93 | status = ERROR_READING; 94 | } 95 | } 96 | } 97 | } 98 | 99 | void requestEvent() { 100 | Serial.print("requestEvent "); 101 | Serial.println(status); 102 | Wire.write(status); 103 | } 104 | -------------------------------------------------------------------------------- /.github/workflows/cla.yml: -------------------------------------------------------------------------------- 1 | name: "CLA Assistant" 2 | on: 3 | issue_comment: 4 | types: [created] 5 | pull_request_target: 6 | types: [opened,closed,synchronize] 7 | 8 | jobs: 9 | CLAssistant: 10 | runs-on: ubuntu-latest 11 | steps: 12 | - name: "CLA Assistant" 13 | if: (github.event.comment.body == 'recheck' || github.event.comment.body == 'I have read the CLA Document and I hereby sign the CLA') || github.event_name == 'pull_request_target' 14 | # Beta Release 15 | uses: cla-assistant/github-action@v2.1.2-beta 16 | env: 17 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 18 | # the below token should have repo scope and must be manually added by you in the repository's secret 19 | PERSONAL_ACCESS_TOKEN : ${{ secrets.PERSONAL_ACCESS_TOKEN }} 20 | with: 21 | # for per-repo CLA-acceptance: 22 | # path-to-signatures: 'signatures/oca-20210504/${{ github.repository }}' 23 | # for per-GHO CLA-acceptance: 24 | path-to-signatures: 'signatures/oca-20210504/oracledevrel' 25 | path-to-document: 'https://github.com/oracledevrel/devrel-oca-mgmt/blob/main/oca-20210504.md' # e.g. a CLA or a DCO document 26 | # branch should not be protected 27 | branch: 'main' 28 | allowlist: bot* 29 | 30 | #below are the optional inputs - If the optional inputs are not given, then default values will be taken 31 | remote-organization-name: "oracledevrel" # enter the remote organization name where the signatures should be stored (Default is storing the signatures in the same repository) 32 | remote-repository-name: "devrel-oca-mgmt" # enter the remote repository name where the signatures should be stored (Default is storing the signatures in the same repository) 33 | #create-file-commit-message: 'For example: Creating file for storing CLA Signatures' 34 | #signed-commit-message: 'For example: $contributorName has signed the CLA in #$pullRequestNo' 35 | #custom-notsigned-prcomment: 'pull request comment with Introductory message to ask new contributors to sign' 36 | #custom-pr-sign-comment: 'The signature to be committed in order to sign the CLA' 37 | #custom-allsigned-prcomment: 'pull request comment when all contributors has signed, defaults to **CLA Assistant Lite bot** All Contributors have signed the CLA.' 38 | #lock-pullrequest-aftermerge: false - if you don't want this bot to automatically lock the pull request after merging (default - true) 39 | #use-dco-flag: true - If you are using DCO instead of CLA 40 | -------------------------------------------------------------------------------- /.github/workflows/repolinter.yml: -------------------------------------------------------------------------------- 1 | name: Repolinter 2 | on: 3 | pull_request_target: 4 | 5 | jobs: 6 | run_repolinter: 7 | name: Run Repolinter on pull request 8 | runs-on: ubuntu-latest 9 | container: 10 | image: ghcr.io/oracledevrel/repolinter:v0.11.1 11 | credentials: 12 | username: ${{ github.actor }} 13 | password: ${{ secrets.GHCR_PAT }} 14 | steps: 15 | - name: 'Checkout repo' 16 | uses: actions/checkout@v2 17 | with: 18 | ref: ${{ github.event.pull_request.head.ref }} 19 | repository: ${{ github.event.pull_request.head.repo.full_name }} 20 | - name: Run Repolinter 21 | run: | 22 | set +e 23 | bundle exec /app/bin/repolinter.js lint --format json --rulesetFile repolinter.json . > repolinter_results.json 24 | echo "\n\nHere is the repolinter_results.json:\n" 25 | echo $(cat repolinter_results.json) 26 | exit 0 27 | - name: Analyze the Repolinter results 28 | uses: oracle-devrel/action-repolinter-audit@v0.1-alpha1 29 | id: analysis 30 | with: 31 | json_results_file: '/github/workspace/repolinter_results.json' 32 | - name: Overall analysis results 33 | run: | 34 | echo "Passed: ${{ steps.analysis.outputs.passed }}" 35 | echo "Errored: ${{ steps.analysis.outputs.errored }}" 36 | - name: Comment if analysis finds missing readme 37 | if: steps.analysis.outputs.readme_file_found == 'false' 38 | uses: mshick/add-pr-comment@v1 39 | with: 40 | message: | 41 | :no_entry: **FAILURE: Missing README** 42 | The README file seems to be missing. Please add it. 43 | 44 | Details: 45 | ${{ steps.analysis.outputs.readme_file_details }} 46 | repo-token: ${{ secrets.GITHUB_TOKEN }} 47 | - name: Comment if analysis finds missing license 48 | if: steps.analysis.outputs.license_file_found == 'false' 49 | uses: mshick/add-pr-comment@v1 50 | with: 51 | message: | 52 | :no_entry: **FAILURE: Missing LICENSE** 53 | The LICENSE file seems to be missing. Please add it. 54 | 55 | Details: 56 | ${{ steps.analysis.outputs.license_file_details }} 57 | repo-token: ${{ secrets.GITHUB_TOKEN }} 58 | - name: Comment if analysis finds copyright notice missing 59 | if: steps.analysis.outputs.copyright_found == 'false' 60 | uses: mshick/add-pr-comment@v1 61 | with: 62 | message: | 63 | :warning: **WARNING: Missing Copyright Notice(s)** 64 | It's a good idea to have copyright notices at the top of each file. It looks like at least one file was missing this (though it might be further down in the file - this might be a false-positive). 65 | 66 | Details: 67 | ${{ steps.analysis.outputs.copyright_details }} 68 | repo-token: ${{ secrets.GITHUB_TOKEN }} 69 | - name: Halt pipeline if README is missing 70 | if: steps.analysis.outputs.readme_file_found == 'false' 71 | run: exit 1 72 | - name: Halt pipeline if LICENSE is missing 73 | if: steps.analysis.outputs.license_file_found == 'false' 74 | run: exit 1 75 | -------------------------------------------------------------------------------- /.github/workflows/banned_file_changes_pr.yml: -------------------------------------------------------------------------------- 1 | name: Banned file changes (PR) 2 | on: 3 | # pull_request: 4 | # branches: [ "**/*" ] 5 | pull_request_target: 6 | 7 | jobs: 8 | check_for_banned_file_changes: 9 | name: Look for unsupported (banned) file modifications on PRs 10 | runs-on: ubuntu-latest 11 | steps: 12 | - name: 'Get number of git commits' 13 | uses: oracle-devrel/action-git-num-commits@v0.1-alpha6 14 | id: num_commits 15 | with: 16 | pull_url: ${{ github.event.pull_request.url }} 17 | - name: 'Checkout repo' 18 | uses: actions/checkout@v2 19 | with: 20 | ref: ${{ github.event.pull_request.head.ref }} 21 | repository: ${{ github.event.pull_request.head.repo.full_name }} 22 | fetch-depth: ${{ steps.num_commits.outputs.fetch_depth }} 23 | - name: Get file changes 24 | uses: oracle-devrel/action-git-files-changed@v0.1-alpha2 25 | id: files 26 | with: 27 | pull_url: ${{ github.event.pull_request.url }} 28 | - name: Look for changes to .github 29 | if: contains(steps.files.outputs.all_files_changed, '.github') 30 | run: | 31 | echo 'Changes to files in .github are not allowed.' 32 | - name: Comment if .github changed 33 | if: contains(steps.files.outputs.all_files_changed, '.github') 34 | uses: mshick/add-pr-comment@v1 35 | with: 36 | message: | 37 | :no_entry: **Banned Files Modified** 38 | Changes to files in `.github` are not permitted. Please revert your changes and re-submit a new PR. Simply changing the file back to its original state and re-committing won't work (you must revert the changes made to it). 39 | repo-token: ${{ secrets.GITHUB_TOKEN }} 40 | - name: Look for changes to license_policy.yml 41 | if: contains(steps.files.outputs.all_files_changed, '"license_policy.yml"') 42 | run: | 43 | echo 'Changes to license_policy.yml are not allowed.' 44 | - name: Comment if license_policy.yml changed 45 | if: contains(steps.files.outputs.all_files_changed, '"license_policy.yml"') 46 | uses: mshick/add-pr-comment@v1 47 | with: 48 | message: | 49 | :no_entry: **Banned Files Modified** 50 | Changes to `license_policy.yml` are not permitted. Please revert your changes and re-submit a new PR. Simply changing the file back to its original state and re-committing won't work (you must revert the changes made to it). 51 | repo-token: ${{ secrets.GITHUB_TOKEN }} 52 | - name: Look for changes to repolinter.json 53 | if: contains(steps.files.outputs.all_files_changed, '"repolinter.json"') 54 | uses: mshick/add-pr-comment@v1 55 | with: 56 | message: | 57 | :no_entry: **Banned Files Modified** 58 | Changes to `repolinter.json` are not permitted. Please revert your changes and re-submit a new PR. Simply changing the file back to its original state and re-committing won't work (you must revert the changes made to it). 59 | repo-token: ${{ secrets.GITHUB_TOKEN }} 60 | - name: Comment if repolinter.json changed 61 | if: contains(steps.files.outputs.all_files_changed, '"repolinter.json"') 62 | run: | 63 | echo 'Changes to repolinter.json are not allowed.' 64 | - name: Look for changes to sonar-project.properties 65 | if: contains(steps.files.outputs.all_files_changed, '"sonar-project.properties"') 66 | uses: mshick/add-pr-comment@v1 67 | with: 68 | message: | 69 | :no_entry: **Banned Files Modified** 70 | Changes to `sonar-project.properties` are not permitted. Please revert your changes and re-submit a new PR. Simply changing the file back to its original state and re-committing won't work (you must revert the changes made to it). 71 | repo-token: ${{ secrets.GITHUB_TOKEN }} 72 | - name: Comment if sonar-project.properties changed 73 | if: contains(steps.files.outputs.all_files_changed, '"sonar-project.properties"') 74 | run: | 75 | echo 'Changes to sonar-project.properties are not allowed.' 76 | - name: Fail on banned file changes 77 | if: contains(steps.files.outputs.all_files_changed, '.github') || contains(steps.files.outputs.all_files_changed, '"license_policy.yml"') || contains(steps.files.outputs.all_files_changed, '"repolinter.json"') || contains(steps.files.outputs.all_files_changed, '"sonar-project.properties"') 78 | run: | 79 | exit 1 -------------------------------------------------------------------------------- /eff-uno-racer/episode1/new-project.md: -------------------------------------------------------------------------------- 1 | # Starting a New Project — Pi Zero Custom Breadboard 2 | by Chris Bensen 3 | 4 | ![Pi Zero Custom Breadboard](breadboard.jpg) 5 | 6 | Every time I start a new project it’s different. Different set of challenges, different tools, different infrastructure and requirements. An entirely different end product. 7 | 8 | I usually work on new projects, prototyping things that nobody has done before. Usually we know what the end product needs to be, but sometimes we’re discovering that as we go. I’m a big fan of Kaizen, which is Japanese for “continuous improvement”. I like to start off by taking a step back and looking at what is required, and with 80% of the knowledge, make a gut decision based on experience and jump right in. 9 | 10 | Of course, I follow my Seven Step Process to Creating an Amazing Demo. This isn’t too different from an Agile process, but it’s less structured. Almost like Kanban. I start with the hardest problems first, but if I can’t figure out where to start, I will just start with what I know. It’s sometimes better to feel accomplished and have something to show for it than to spin your wheels. But I don’t like wasting my time and throwing the work away, so it’s always a balance. Sometimes throwing work away is exactly what is required and isn’t really throwing work away; it was required work to gain the knowledge needed to continue. 11 | 12 | [Episode 1 — Custom Breadboard for Raspberry Pi Zero](https://youtu.be/-BF6zZbBVFA) 13 | 14 | Episode 1 — Custom Breadboard for Raspberry Pi Zero 15 | The “fail fast and early” mantra is near and dear to me, but I don’t like it in the traditional “hacker” sense. What I mean is more related to decision making. There are some decisions that are best delayed, and others that should be made as soon as possible. Knowing when to make a decision is a skill, and one I think can be taught. Everyone makes mistakes, so the trick with any team is to setup a no-blame culture where people can accept their mistake, fess up to it, and move on. In my experience, those are the teams that are the most successful and the most fun to work with. 16 | My Grandpa always taught me to use the right too for the job. Now, he was just a rocket scientist who also built houses and knew a thing or two about electronics and explained Einstein’s theory of General Relativity to me when I was 10, but in my experience the same thing applies to any job. Everything is relative. If you only have one skill, like using a hammer, everything looks like a nail. So when I discover that I need a tool, I either find it or make it. Pragmatic Programmer is a book that I often refer to. (Disclaimer, I only read the book jacket but I feel like I got the gist of the concept and highly recommend the book.) 17 | 18 | ![](GrandfathersElectronics.jpg) 19 | 20 | Last week I started a new project. This is partially an edge or IoT project (depending on how you look at it); A Raspbery Pi Zero will have some sensors and motors, connect to the Oracle Cloud and data will be visualized in a web browser in real-time. This will involve some LEGO™. There are a lot of things that have been researched and are known, and a lot of things that we have absolutely no idea how they will work. Honestly, this is going to be fun because it is so nuts. That’s the best kind of project. No pressure. 21 | 22 | ![](breadboard2.png) 23 | 24 | We picked GitHub (for what seems like obvious reasons nowadays) for version control. Stay tuned for that. Because there will be multiple pieces, the programming language will be determined based on what works best for the job. Is “Beyond full stack” a thing? I can say that performance is key here. Java + GraalVM would be preferred, but there will be some Javascript and Python and probably some C++ —but I might try Go or Rust, or use GraalVM native image. 25 | The first step is the breadboarding. Whenever I start a project, the prototyping phase is a mess of spaghetti. This makes it difficult when moving the project between my computer desk inside the house and workbench where the soldering iron is in the garage. I decided to solve this problem for my next project by making a custom prototype board and building it as clean as possible. Then I’ll share it all with you! So if you’re interested in making your own, head over to Thingiverse and checkout the Pi Zero Custom Breadboard. The three holes in the CAD rendering at the top (from left to right) are the power switch, 2.1mm power supply, and potentiometer. Here is a list of all the parts: 26 | 27 | - Potentiometer 28 | - 2.1mm jack (but I like these 2.1mm jacks better) 29 | - Power Supply 30 | - Breadboard 31 | - Raspberry Pi Zero W 32 | - Assembled T-Cobbler 33 | - Pololu 5v 2.5a Step-Down Voltage Regulator 34 | - Solid Core 22 AWG Wire 35 | - Sandisk Micro SD Card 36 | - Cabinet Door Bumpers 37 | - Rocket Switch (I used an old switch but this one appears to have the same specs) 38 | - (3) M2.5 x 6mm Phillips rounded head screw (this is as close as I can find 39 | - (12) M2.5 x 4mm Phillips rounded head screw (this is as close as I can find) 40 | - (4) M2.5 x .45mm Heat-set plastic inserts 41 | - (4) Button head Hex M2.5 x .45mm 5mm long 18–8 stainless screw 42 | - (2) Seal Heat Shrink Butt Connectors 43 | 44 | I laser cut the main board from 1/4" poplar plywood, but have included a 3D printed version as well. These could be merged to be one big print, but I like to print things in pieces sometimes to account for modularity and print failure. I also printed the LEGO™ parts with a .25mm print head while I printed the rest with a .4mm print head. I used standard Red Ultimaker PLA. Overall it’s about a day of 3D printing. 45 | Now I’m ready to start prototyping in the most organized way possible. I have no delusions, it’ll still get messy. Stay tuned for the next part in the series where I setup the Oracle Cloud services and the Pi Zero. You won’t want to miss it. 46 | -------------------------------------------------------------------------------- /eff-uno-racer/episode3/episode3.md: -------------------------------------------------------------------------------- 1 | # Episode 3 - Building the Race Car Frame 2 | By Chris Bensen 3 | 4 | ![Model of Eff-Uno Racer](model.png) 5 | 6 | In my previous two episodes (links at the bottom of this article) I built a custom breadboard setup for a Raspberry Pi and Arduino. Although it can be used for any project, I 3D printed a pad of bricks and connected up an RC servo and DC brushless motor via and ESC for a very specific project, I'm building a race car! 7 | 8 | And I apologize for not coming out and saying what I'm building but rather presenting it in some sort of teaser clickbait fashion. I just wasn't ready to reveal it and my management wanted me to take you all on a journey of the process rather than just 6-months of working in a closet with a big reveal at the end. But now is the time in the process to reveal a bit more. Think of it as getting all ya'll involved. I am building a cloud connected LEGO (c) open wheel race car. That's a mouthful. I was calling it #CloudCar but that sounds too much like "clown car". I can't legally say some of these words, such as eff-uno, so let's call it the **Eff-Uno Racer**, or **FUR**. And because everything needs to have a version number, let's call it **FUR1**. Note that I had to add the 'R' otherwise the name would sound obscene. 9 | 10 | After I reread that last paragraph I realized maybe I am building a clown car. Well, it should be an exciting one! 11 | 12 | I basing my project off the [LEGO (c) Kit 8440](https://www.bricklink.com/catalogItemInv.asp?S=8440-1) because it already exists and the parts list is easily available. So you will see a lot of similarities. There are some amazing things out there for LEGO (c) builders that not everyone may be aware of such as open source LEGO (c) CAD tools called [Bricksmith](https://bricksmith.sourceforge.io), [LDView](https://tcobbs.github.io/ldview/) and [LEO CAD](https://www.leocad.org). Bricksmith has some problems on the latest version of macOS so I'm mostly using LEO CAD at the moment. I am also using Fusion 360, despite not being completely pleased with it, to create my own custom parts to interface between the RC parts and the LEGO (c). 13 | 14 | ## The major parts of this project 15 | 16 | 1. The LEGO (c) Frame + Custom 3D printed adapters for RC parts 17 | 1. The electronics - Raspberry Pi 4, Arduino, Pi Camera, RC Servo motor and Brushless DC motor + ESC (there will be more but this is enough for now) 18 | 1. The Pi software - Running Oracle Linux, GraalVM and Java 19 | 1. The Cloud software - Using [Oracle Cloud](https://www.oracle.com/cloud/free/?source=:ex:tb:::::&SC=:ex:tb:::::&pcode=WWMK210625P00074) 20 | 1. The Client software - TBD 21 | 22 | The car is the first hurdle and arguably the most important because it is the main character in this series. Nobody would watch the cloud drive a car around if there was no car. So first things first, I'm building a car. A really really cool car. A really good car. Not a hacked together junker. This is a fast race car! I am building a car that any of you can build yourself as inexpensively as possible with is easy to follow directions. This is no easy feat. Add to that the custom paint job and a global supply chain that is in the toilet and there's a few challenges I didn't foresee. It's difficult but I'm up for a challenge, and this is a challenge! And we've hardly discussed the software. There is a lot here so stay tuned! 23 | 24 | ## The Status 25 | 26 | So far process on #1 is going well. #2 is coming along. I'm building a custom PCB and hope to share more about that in a month or two. #3 and #4 have been prototyped but need a lot more work. I need to get a working car in the hands of some other engineers before much more work can be done here. What fun is doing something like this all by myself. I love collaboration. And if you have ideas or want to work on something, drop me a line! 27 | 28 | As the project proceeds I have to be pragmatic and create things that will save time later. There is always a trade off here of time spent now vs later. For example, during this weeks video I received some Protopasta filament, and they have amazing cardboard spool holders but they are a slightly different size than what my Ultimaker printer accepts. So I created a spool holder. [Download](https://www.thingiverse.com/thing:4942247) and print the spool holder or edit the 3D model. 29 | 30 | ![Protopasta Spool Holder](spoolholder.png) 31 | 32 | ## Where to go From Here 33 | 34 | FUR1 will be as much LEGO (c) as possible so you can simply use your existing boxes of your favorite bricks layin' around or buy the specific pieces needed. Only a few interface parts for the RC parts and electronics will be made. Plans will be made available to make your own. All 3D models will be available on [Thingiverse](https://www.thingiverse.com/thing:4940804) and source code will be on [GitHub](https://github.com/oracle-devrel/eff-uno-racer) follow along on the various [blogs](https://chrisbensen.medium.com/), [YouTube](https://www.youtube.com/c/ChrisBensen), [Oracle Developer website](http://developer.oracle.com?source=:ex:tb:::::&SC=:ex:tb:::::&pcode=WWMK210625P00074), [Oracle Developers YouTube Channel](https://www.youtube.com/channel/UCdDhYMT2USoLdh4SZIsu_1g) and [Twitter](https://twitter.com/chrisbensen). 35 | 36 | ## Q/A 37 | 38 | Q: FUR1 implies there will be a FUR2? 39 | 40 | A: Yes! Maybe even a FUR3. It will also fork to be a FUR1b possibly with more RC than LEGO (c) as we do the testing and find it falls apart too early when driving it FAST! 41 | 42 | Q: Who is sponsoring this awesome project? 43 | 44 | A: I'm glad you asked. Oracle Developer Relations have sponsored this project because Oracle has some amazing tech. Not only do they have the most robust operating system on the planet and the number one programming language (yeah, you heard me, Java rocks), and the fastest implementation of the JVM with GraalVM, but they have a really solid [cloud solution](https://www.oracle.com/cloud/free/?source=:ex:tb:::::&SC=:ex:tb:::::&pcode=WWMK210625P00074) that will be the backbone to this project. 45 | 46 | Q: I don't think you can pull off such a crazy project. 47 | 48 | A: I've done others that are arguably crazier. I built [The World's Largest Raspberry Pi Cluster (that we know of)](https://www.youtube.com/watch?v=KbVcRQQ9PNw) and [World’s Largest Working Lego Computer](https://www.youtube.com/watch?v=Y5m0R9tTdR0). All of these run Raspberry Pi, Oracle Linux, GraalVM and Java. 49 | 50 | Q: When can I expect to see more of this project? 51 | 52 | A: Twitter [https://twitter.com/chrisbensen](https://twitter.com/chrisbensen) has the most updates at the moment. 53 | 54 | --- 55 | 56 | Episode 1 - Custom Raspberry Pi Zero Breadboard 57 | Short: https://youtu.be/-BF6zZbBVFA 58 | Extended: https://youtu.be/GUiLuG1Drjg 59 | Thing: https://www.thingiverse.com/thing:4868187 60 | Blog: https://chrisbensen.medium.com/starting-a-new-project-pi-zero-custom-breadboard-834df6414ac6 61 | 62 | 63 | Episode 2 - Pi Controlled Motors 64 | Short: https://youtu.be/9aLBQ6m8_kI 65 | Extended: https://www.youtube.com/watch?v=0F65hw3ntPk 66 | Oracle devs blog: https://medium.com/oracledevs/pi-controlled-motors-b5cf81eea42f 67 | Blog: https://chrisbensen.medium.com/pi-controlled-motors-b5cf81eea42f 68 | -------------------------------------------------------------------------------- /eff-uno-racer/episode2/pi-motors.md: -------------------------------------------------------------------------------- 1 | # Pi Controlled Servo Motors 2 | By Chris Bensen 3 | 4 | ![Pi, Arduino, IC2, Brushless Motors](breadboard.jpg) 5 | 6 | ## A Rabbit Hole 7 | 8 | All too often someone shows something they built and maybe a short video or blog post about how it was done, but the directions are far from complete and the rationale behind the choices is lacking. The reason I’m doing this series is to show the process and the rationale behind the choices. At the end we will have something that’s pretty cool. Trust me. The problem is that things always take more time than expected. I thought I’d be a little further than where I’m currently at, but there’s been some discovery and research along the way. If everything went together smoothly, then I’d already have made one of these. 9 | 10 | When building this, I have to balance a few things. First is getting it to work. Second is performance. If I can do both at the same time, that’s a bonus, but I can and will go back and evaluate the performance later. For this project performance comes in two flavors: response time and battery usage. This will have to be tuned, so getting things running for real-world evaluation is paramount. Third, and most important, is documenting the process. Sometimes things go smoothly and work as planned. Other times they do not. I suppose that’s why I’m doing this; to show that building things is messy and to provide some insight, education, and possibly some entertainment (because not a lot has gone right at this point). 11 | 12 | Now, I am only one person and I don’t know everything. Anyone that claims they know everything is lying. What I do know is that I can figure things out --- and get myself into trouble. I also know how to read directions, ask friends and experts for advice, and if that fails, try, try, try again. A little bit of each went into this. 13 | 14 | The reason I’m saying all this is I ran into few problems, four to be exact. You’ll read about my journey in this process and all of the decisions, as well as the mistakes. Those are worth mentioning here so you can look for them in the article: 15 | 16 | - Power Supply 17 | - Common ground 18 | - Pi runs at 3.3v and Arduino at 5v 19 | - Few development tools run on the Pi Zero 20 | - [Updated Breadboard](https://www.thingiverse.com/thing:4896228) 21 | 22 | ## Setting up the Pi 23 | 24 | At this point I have a Pi Zero, Pi spy camera, servo and ESC connected to a brushless motor. Eventually more things will be added, but this is enough to get started. I figured we'd get started by setting up the Pi. 25 | 26 | There are a lot of ways to write an OS image to an SD card, but I have found the Raspberry Pi Imager [https://www.raspberrypi.org/software/] the easiest, especially if you want to use the standard Pi OS. I usually use [Oracle Linux](https://www.oracle.com/linux/downloads/linux-arm-downloads.html) because I have an entire operating system team to help me out, but unfortunately Oracle Linux doesn’t support the Raspberry Pi Zero (because Oracle Linux is 64-bit while the Pi Zero is 32-bit), so I’m using Pi OS. 27 | 28 | ![](PiImager.png) 29 | 30 | The Pi Zero is pretty slow, unlike a Pi 4, so you don’t want to do your development on the device. There is where Visual Studio Code shines. However, the VS Code Remote SSH extension does not support the Pi. There are two ways that I can do this: 31 | 32 | 1. Create a GitHub repo and edit locally on my desktop, push the changes, and pull them on the Pi 33 | 2. Use a combination of local editor and scp for copying the local file to the pi, ssh into the Pi, and run the script. 34 | 35 | Another problem, and one I didn’t expect, was that GraalVM does not support the Pi. For Pi 3 or Pi 4 you would do download GraalVM for Pi (ARM) and run its Java binary: 36 | 37 | ``` 38 | > wget https://github.com/graalvm/graalvm-ce-builds/releases/download/vm-21.1.0/graalvm-ce-java16-linux-aarch64-21.1.0.tar.gz 39 | 40 | > tar -xzf graalvm-ce-java16-linux-aarch64-21.1.0.tar.gz 41 | export PATH=/home/pi/graalvm-ce-java16-21.1.0/bin:$PATH 42 | > java 43 | -bash: /home/pi/graalvm-ce-java16-21.1.0/bin/java: cannot execute binary file: Exec format error 44 | ```` 45 | 46 | Ah, right, ARM-7 on a 32-bit OS. I’m beginning to see why not many developers use the Pi Zero. It may be small but it just doesn’t have the support the regular Pi has, and it’s a little low on CPU and Memory. 47 | 48 | Well, everyone programs the Pi with Python anyway, right? 49 | 50 | [Video](https://youtu.be/9aLBQ6m8_kI) 51 | 52 | ## Unexpected Hardware: Arduino 53 | 54 | At this point I shook my head. Just like anything, balancing a big project requires multitasking. I’ve been juggling too many other parts of the project and didn’t give the electronics a lot of focus. The Pi Zero doesn’t have PWM pins, and after a few tests with the Pi 4, the PWM signal isn’t reliable enough. This is because the Pi is running a preemptive multitasking operating system so the PWM signal --- which must be clean --- is a little sporadic, or what I like to call "herky jerky." I need a dedicated microcontroller. 55 | 56 | Introducing an Arduino to this project isn’t trivial. I actually went back and forth a bit, but settled (for now) on an Arduino Micro. I have a few of these laying around, and they are small and fairly powerful. More on why I choose this Arduino later. 57 | 58 | The voltage regulator I was using was rated for 2.5amp, and when I added the Arduino, the Pi was stuck in a reboot cycle due to being underpowered. What confused me is that it was working until I configured something which required a reboot, so I wasn’t looking at the voltage regulator. The other reason I wasn’t looking at the voltage regulator is that 2.5amp actually *should* be enough power, but it turned out that the combination of the monitor, USB hub, mouse, and keyboard pulled more than that. Why the monitor pulls 2amp is beyond me; it has its own power supply! This is exactly why I went to such lengths to build a custom prototype breadboard. 59 | 60 | One problem I have is that when going between debugging at my desk and the device on the garage workbench, power and ground changes a bit, causing problems. When I moved the breadboard to my computer to debug, the power changed from only the power supply to the power supply *plus* the computer’s USB. And now the grounds are not the same. All devices that are communicating must have the same ground, but I find that switching between running the device I’m making and plugging in the USB cable for programming/debugging can affect things or require slight wiring changes. If you have a solution for this, I’d love to hear how you have solved it. 61 | 62 | I swapped the voltage regulator and solved the power problems. In the final project I should be able to go back to the original unit, but I’m considering designing a custom PCB so this is easier to develop and assemble. 63 | 64 | ## Communicating Between Raspberry Pi and Arduino 65 | 66 | Communicating between an RPi and an Arduino on I2C is a bit of a mess if you are using the `Wire.h` library. The short answer is that RPi is using a repetitive start signal, while Arduino is not. Repetitive start signal on the I2C interface tells the device to start answering for the call. In case of the Arduino, asking and answering is in two separated calls. Therefore, you cannot send a block. However, I found I could use the `SMBus.write_i2c_block_data()` without any problems because this is sent a bit differently. This is good, because if I had to send every byte individually, things would be really slow. After looking at this I added some optimizations; let me know in the comments if you can spot them. 67 | 68 | Here is the Arduino [carduino.ino](carduino.ino) sketch: 69 | 70 | ``` 71 | #include 72 | #include 73 | 74 | int servoPin = 10; 75 | int escPin = 11; 76 | 77 | int i2cAddress = 0x8; 78 | 79 | Servo esc; 80 | Servo servo; 81 | 82 | int status = 0; 83 | 84 | #define ERROR_READING 1 85 | #define INVALID_RANGE 2 86 | 87 | 88 | void setup() { 89 | Serial.begin(9600); 90 | 91 | Wire.begin(i2cAddress); 92 | Wire.onReceive(receiveEvent); 93 | Wire.onRequest(requestEvent); 94 | 95 | // pin, min pulse width, max pulse width in microseconds 96 | servo.attach(servoPin, 0, 180); 97 | 98 | // pin, min pulse width, max pulse width in microseconds 99 | esc.attach(escPin, 1500, 2000); 100 | esc.write(1500); // initialize the ESC 101 | delay(3000); 102 | 103 | Serial.println("starting"); 104 | } 105 | 106 | void loop() { 107 | } 108 | 109 | boolean range(int min, int max, int value) { 110 | return (min <= value) && (value <= max); 111 | } 112 | 113 | void receiveEvent(int byteCount) { 114 | Serial.print("receiveEvent: "); 115 | Serial.println(byteCount); 116 | 117 | if (byteCount > 1) { 118 | byte message = Wire.read(); 119 | 120 | switch (message) { 121 | case 1: { 122 | byte position = Wire.read(); 123 | Serial.print("servo: "); 124 | Serial.println(position); 125 | 126 | if (range(0, 180, position)) { 127 | servo.write(position); 128 | } 129 | else { 130 | status = INVALID_RANGE; 131 | } 132 | 133 | break; 134 | } 135 | 136 | case 2: { 137 | int speed = 0; 138 | 139 | if (byteCount == 3) { 140 | byte high = Wire.read(); 141 | byte low = Wire.read(); 142 | Serial.println(high); 143 | Serial.println(low); 144 | speed = 0; 145 | speed = (high << 4) | low; 146 | } 147 | else { 148 | speed = Wire.read(); 149 | } 150 | 151 | Serial.print("esc: "); 152 | Serial.println(speed); 153 | 154 | if (range(1000, 2000, speed)) { 155 | esc.write(speed); 156 | } 157 | else { 158 | status = INVALID_RANGE; 159 | } 160 | 161 | break; 162 | } 163 | 164 | default: { 165 | status = ERROR_READING; 166 | } 167 | } 168 | } 169 | } 170 | 171 | void requestEvent() { 172 | Serial.print("requestEvent "); 173 | Serial.println(status); 174 | Wire.write(status); 175 | } 176 | ``` 177 | 178 | Once the Arduino is set up and plugged into the Pi’s I2C pins --- oh wait, the Arduino is 5v and the Pi is 3.3v. Logic can be sent to the Arduino, but the Arduino can't send logic to the Pi. [Logic Level Converter](https://learn.sparkfun.com/tutorials/bi-directional-logic-level-converter-hookup-guide/all) to the rescue! This little board will convert bi-directionally without frying anything. The breadboard has a few more bits and pieces than first expected, but it’s coming along. 179 | 180 | Connecting an I2C device to a Pi is fairly straight forward once you know how. Adafruit has a [detailed list of steps](https://learn.adafruit.com/adafruits-raspberry-pi-lesson-4-gpio-setup/configuring-i2c): 181 | 182 | 1. `> sudo apt-get install -y python-smbus` 183 | 2. `> sudo apt-get install -y i2c-tools` 184 | 3. `> sudo raspi-config` 185 | 4. Choose Interfacing Options -> Advanced Options -> I2C ->j Yes 186 | 5. Reboot the Pi: `sudo reboot` 187 | 6. Wait until the Pi is booted, log back in again and open up a terminal. Power up the Arduino and check that the Pi is detecting the I2C device: 188 | 189 | ``` 190 | > sudo i2cdetect -y 1 191 | 0 1 2 3 4 5 6 7 8 9 a b c d e f 192 | 00: -- -- -- -- -- 08 -- -- -- -- -- -- -- 193 | 10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 194 | 20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 195 | 30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 196 | 40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 197 | 50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 198 | 60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 199 | 70: -- -- -- -- -- -- -- -- 200 | ``` 201 | 202 | Notice the Arduino is seen on address 8. 203 | 204 | Back to the Pi. I open two terminal windows on my desktop, create a directory called `pi` and `cd` both terminals to the directory. In one window I `ssh` into the Pi, and in the second window I set up an `scp` command. Here are the two commands: 205 | 206 | ``` 207 | > ssh pi@192.168.1.165 208 | > scp testservo.py pi@192.168.1.165:/home/pi 209 | ``` 210 | 211 | Next, I open up an editor to the folder and create a file called [carpi.py](carpi.py) (I initially started working with a potentiometer and didn’t get around to renaming the file yet): 212 | 213 | ```python 214 | from smbus import SMBus 215 | import time 216 | import sys 217 | 218 | if (len(sys.argv) != 3): 219 | print("Error: Not enough arguments") 220 | exit() 221 | 222 | device = int(sys.argv[1]) 223 | value = int(sys.argv[2]) 224 | print("device " + str(device)) 225 | print("value " + str(value)) 226 | 227 | 228 | bus = SMBus(1) # 512M Pi use i2c port 1, 256M Pi use i2c port 0 229 | time.sleep(1) 230 | address = 0x8 231 | 232 | if (value < 256): 233 | bus.write_i2c_block_data(address, device, [value]) 234 | else: 235 | high, low = value >> 4, value & 0x0FF 236 | print(high) 237 | print(low) 238 | bus.write_i2c_block_data(address, device, [high, low]) 239 | 240 | bus.close() 241 | ``` 242 | 243 | Usage: `python3 carpi.py [device] [value]` 244 | 245 | Example: `python3 carpi.py 1 180` 246 | 247 | The first argument is the device, 1 is the servo motor, and 2 is the brushless motor. The servo motor has a value of 0--180. The brushless motor has a value of 1000--2000 where 1500 is stop and 2000 is full throttle forward. 248 | 249 | [Video](https://www.youtube.com/watch?v=0F65hw3ntPk) 250 | 251 | ## Conclusion 252 | 253 | I’m ending this episode with a Pi Zero, Arduino Micro, 5v Voltage Regulator, ESC connected to a brushless motor, and a servo motor. Because of the Pi communicating with the Arduino, I also need a logic level converter. I’m not going to provide links to the parts because I’m not 100% sure I like what I have (for example, the brushless DC motor does not go in reverse). I have spent a couple days trying to figure out why with no success. 254 | 255 | I was reluctant to add an Arduino, but once I realized it was necessary to add a microcontroller that could produce a clean PWM signal for the brushless motor, the only decision was which microcontroller. There are a lot of microcontrollers out there, but I decided to use an Arduino Micro because it will do the job; it's small and doesn’t pull a lot of power. The other choices the Arduino Pro Mini and a Teensy. The Arduino Pro Mini comes in a 3.3v variant that would have made life a lot simpler because it operates at the same voltage as the Pi, so a line level converter would not be needed. However, the Pro Min in the 5v and 3.3v is not fast enough. The Teensy is even faster than the Arduino Micro, and the cost is perfect at around $20 but I have more experience with the Arduino Micro, so I went with that. I will consider switching to a Teensy before I finalize the project. 256 | 257 | Now, I’ve worked with ESCs before. They are pretty easy to work with, but the directions need to specify a few things that my directions did not. That’s what you get for trying to use a low budget ESP and Motor. At this point, I actually did a search and went page by page reading and trying each and every thing on every page --- including the comments --- until I ran across the fact that ESCs for cars and multicopters are different. Airplane and most multicopter ESCs --- which is what I’ve used --- use 1000 for stop and 2000 for full throttle. Some of these also have reverse so that the vehicle can fly inverted. Car and boat ESC's use 1000 for full reverse, 1500 as stop and 2000 for full forward. 258 | 259 | It’s at this point that I would show you a wiring diagram, but since things went haywire (no pun indented), I will just list the connections I made and a photo: 260 | 261 | * Arduino Micro VCC -> 5v Voltage Regulator + 262 | * Arduino Micro GND -> 5v Voltage Regulator + 263 | * Arduino Micro 2-> Level Converter HV1 264 | * Arduino Micro 3-> Level Converter HV2 265 | * Arduino Micro 10 -> Servo data (white wire) 266 | * Arduino Micro 11 -> ESC data (white wire) 267 | * Arduino Micro A0 -> Potentiometer wipe (center wire) 268 | 269 | --- 270 | 271 | * Pi SDA -> Level Converter LV1 272 | * Pi SCL -> Level Converter LV2 273 | * Pi 3.3v -> Level Converter HV 274 | 275 | --- 276 | 277 | * Level Converter GND (both of them) -> Common ground 278 | * Level Converter HV -> 5v Voltage Regulator 279 | 280 | --- 281 | 282 | * 5v Voltage Regulator VIN -> 12v Power Supply + 283 | * 5v Voltage Regulator GND -> 12v Power Supply – 284 | * 5v Voltage Regulator VCC -> Micro USB for Pi, Arduino Micro VCC 285 | * 5v Voltage Regulator GND -> Micro USB for Pi, Arduino Micro GND 286 | 287 | 288 | ## References 289 | 290 | - A little light reading about [I2C on the Pi](https://stackoverflow.com/questions/24812185/python-smbus-write-byte-and-values-greater-than-1-byte-255) 291 | - [Meaning of cmd param in write_i2c_block_data](https://raspberrypi.stackexchange.com/questions/8469/meaning-of-cmd-param-in-write-i2c-block-data) 292 | - [Programming ESC](https://www.instructables.com/ESC-Programming-on-Arduino-Hobbyking-ESC/) 293 | --------------------------------------------------------------------------------