From a407af087d3fa0e5dc5f994ea40d291e55193bcb Mon Sep 17 00:00:00 2001 From: Evan Pratten Date: Wed, 20 Nov 2019 10:04:59 -0500 Subject: [PATCH] Added RT robot post --- _posts/2019-11-18-Realtime-robot-code.md | 185 ++++++++++++ _site/about/index.html | 4 +- _site/assets/css/main.css | 85 +++--- _site/blog/2018/06/27/becomeranter.html | 4 +- _site/blog/2019/04/30/frc-languages.html | 4 +- .../05/27/building-safe-vision-comms.html | 4 +- _site/blog/2019/06/12/styiling-github.html | 4 +- _site/blog/2019/06/16/graphing-w2a.html | 4 +- _site/blog/2019/06/17/amm2m1-release.html | 4 +- _site/blog/2019/06/21/robot-experiences.html | 4 +- _site/blog/2019/06/23/googlectf.html | 4 +- _site/blog/2019/06/24/languagehunt2.html | 4 +- _site/blog/2019/06/26/bashsmash.html | 4 +- _site/blog/2019/06/27/pwnlink.html | 4 +- _site/blog/2019/06/27/python.html | 4 +- _site/blog/2019/07/01/devdns.html | 4 +- _site/blog/2019/07/06/scrapingfrcgithub.html | 4 +- _site/blog/2019/07/13/lookback-gmad.html | 4 +- _site/blog/2019/07/15/mindmap.html | 4 +- _site/blog/2019/08/10/why-i-carry-nfc.html | 4 +- _site/blog/2019/08/12/setting-up-ja.html | 4 +- _site/blog/2019/08/24/shift2.html | 4 +- _site/blog/2019/08/27/github-cleanup.html | 4 +- _site/blog/2019/09/07/wrong-python.html | 4 +- _site/blog/index.html | 31 +- _site/documentation.html | 4 +- _site/feed.xml | 276 +++++++++++------- _site/fossl-feeds.html | 4 +- _site/index.html | 4 +- _site/projects.html | 4 +- _site/redirects.json | 2 +- assets/css/main.css | 85 +++--- .../python/__pycache__/rtrbt.cpython-36.pyc | Bin 0 -> 1546 bytes assets/python/rtrbt.py | 64 ++++ 34 files changed, 602 insertions(+), 230 deletions(-) create mode 100644 _posts/2019-11-18-Realtime-robot-code.md create mode 100644 assets/python/__pycache__/rtrbt.cpython-36.pyc create mode 100644 assets/python/rtrbt.py diff --git a/_posts/2019-11-18-Realtime-robot-code.md b/_posts/2019-11-18-Realtime-robot-code.md new file mode 100644 index 0000000..82a2081 --- /dev/null +++ b/_posts/2019-11-18-Realtime-robot-code.md @@ -0,0 +1,185 @@ +--- +layout: post +title: "Programming a live robot" +description: "Living on the edge is an understatement" +date: 2019-11-20 10:04:00 +categories: random frc +redirect_from: + - /post/e9gdhj90/ + - /e9gdhj90/ +--- + +> *"So.. what if we could skip asking for driver inputs, and just have the robot operators control the bot through a commandline interface?"* + +This is exactly the kind of question I randomly ask while sitting in the middle of class, staring at my laptop. So, here is a post about my real-time programming adventure! + +## Geting started + +To get started, I needed a few things. Firstly, I have a laptop running [a Linux distribution](/about/#my-gear). This allows me to use [SSH](https://en.wikipedia.org/wiki/Secure_Shell) and [SCP](https://en.wikipedia.org/wiki/Secure_copy). There are Windows versions of both of these programs, but I find the "linux experience" easier to use. Secondly, I have grabbed one of [5024](https://www.thebluealliance.com/team/5024)'s [robots](https://cs.5024.ca/webdocs/docs/robots) to be subjected to my experiment. The components I care about are: + + - A RoboRIO running 2019v12 firmware + - 2 [TalonSRX](https://www.ctr-electronics.com/talon-srx.html) motor controllers + - An FRC router + +Most importantly, the RoboRIO has [RobotPy](https://robotpy.readthedocs.io/en/stable/install/robot.html#install-robotpy) and the [CTRE Libraries](https://robotpy.readthedocs.io/en/stable/install/ctre.html) installed. + +### SSH connection + +To get some code running on the robot, we must first connect to it via SSH. Depending on your connection to the RoboRIO, this step may be different. Generally, the following command will work just fine to connect (assuming your computer has an [mDNS](https://en.wikipedia.org/wiki/Multicast_DNS) service): + +```sh +ssh admin@roborio--frc.local +``` + +If you have issues, try one of the following addresses instead: + +``` +roborio--FRC +roborio--FRC.lan +roborio--FRC.frc-field.local +10.TE.AM.2 +172.22.11.2 # Only works on a USB connection +``` + +If you are asked for a password, and have not set one, press Enter 3 times (Don't ask why.. this just works). + +## REPL-based control + +If you have seen my work before, you'll know that I use Python for basically everything. This project is no exception. Conveniently, the RoboRIO is a linux-based device, and can run a Python3 [REPL](https://en.wikipedia.org/wiki/Read%E2%80%93eval%E2%80%93print_loop). This allows real-time robot programming using a REPL via SSH. + +WPILib requires a robot class to act as a "callback" for robot actions. My idea was to build a special robot class with static methods to allow me to start it, then use the REPL to interact with some control methods (like `setSpeed` and `stop`). + +After connecting to the robot via SSH, a Python REPL can be started by running `python3`. If there is already robot code running, it will be automatically killed in the next step. + +With Python running, we will need 2 libraries imported. `wpilib` and `ctre`. When importing `wpilib` a message may appear to notify you that the old robot code has been stopped. + +```python +>>> import wpilib +Killing previously running FRC program... +FRC pid 1445 did not die within 0ms. Force killing with kill -9 +>>> import ctre +``` +Keep in mind, this is a REPL. Lines that start with `>>>` or `...` are *user input*. Everything else is produced by code. + +Next, we need to write a little code to get the robot operational. To save time, I wrote this "library" to do most of the work for me. Just save this as `rtrbt.py` somewhere, then use SCP to copy it to `/home/lvuser/rtrbt.py`. + +```python +# RealTime FRC Robot control helper +# By: Evan Pratten + +# Import normal robot stuff +import wpilib +import ctre + +# Handle WPI trickery +try: + from unittest.mock import patch +except ImportError: + from mock import patch +import sys +from threading import Thread + + +## Internal methods ## +_controllers = [] +_thread: Thread + + +class _RTRobot(wpilib.TimedRobot): + + def robotInit(self): + + # Create motors + _controllers.append(ctre.WPI_TalonSRX(1)) + _controllers.append(ctre.WPI_TalonSRX(2)) + + # Set safe modes + _controllers[0].setSafetyEnabled(False) + _controllers[1].setSafetyEnabled(False) + + + +def _start(): + # Handle fake args + args = ["run", "run"] + with patch.object(sys, "argv", args): + print(sys.argv) + wpilib.run(_RTRobot) + +## Utils ## + + +def startRobot(): + """ Start the robot code """ + global _thread + _thread = Thread(target=_start) + _thread.start() + + +def setMotor(id, speed): + """ Set a motor speed """ + _controllers[id].set(speed) + +def arcadeDrive(speed, rotation): + """ Control the robot with arcade inputs """ + + l = speed + rotation + r = speed - rotation + + setMotor(0, l) + setMotor(1, r) +``` + +The idea is to create a simple robot program with global hooks into the motor controllers. Python's mocking tools are used to fake commandline arguments to trick robotpy into thinking this script is being run via the RIO's robotCommand. + +Once this script has been placed on the robot, SSH back in as `lvuser` (not `admin`), and run `python3`. If using `rtrbt.py`, the imports mentioned above are handled for you. To start the robot, just run the following: + +```python +>>> from rtrbt import * +>>> startRobot() +``` + +WPILib will dump some logs into the terminal (and probably some spam) from it's own thread. Don't worry if you can't see the REPL prompt. It's probably just hidden due to the use of multiple threads in the same shell. Pressing Enter should show it again. + +I added 2 functions for controlling motors. The first, `setMotor`, will set either the left (0), or right (1) motor to the specified speed. `arcadeDrive` will allow you to specify a speed and rotational force for the robot's drivetrain. + +To kill the code and exit, press CTRL + D then CTRL + C. + +Here is an example where I start the bot, then tell it to drive forward, then kill the left motor: +```python +Python 3.6.8 (default, Oct 7 2019, 12:59:55) +[GCC 8.3.0] on linux +Type "help", "copyright", "credits" or "license" for more information. +>>> from rtrbt import * +>>> startRobot() +['run', 'run'] +17:53:46:472 INFO : wpilib : WPILib version 2019.2.3 +17:53:46:473 INFO : wpilib : HAL base version 2019.2.3; +17:53:46:473 INFO : wpilib : robotpy-ctre version 2019.3.2 +17:53:46:473 INFO : wpilib : robotpy-cscore version 2019.1.0 +17:53:46:473 INFO : faulthandler : registered SIGUSR2 for PID 5447 +17:53:46:474 INFO : nt : NetworkTables initialized in server mode +17:53:46:497 INFO : robot : Default IterativeRobot.disabledInit() method... Override me! +17:53:46:498 INFO : robot : Default IterativeRobot.disabledPeriodic() method... Override me! +17:53:46:498 INFO : robot : Default IterativeRobot.robotPeriodic() method... Override me! +>>> +>>> arcadeDrive(1.0, 0.0) +>>> setMotor(0, 0.0) +>>> +^C +Exception ignored in: +Traceback (most recent call last): + File "/usr/lib/python3.6/threading.py", line 1294, in _shutdown + t.join() + File "/usr/lib/python3.6/threading.py", line 1056, in join + self._wait_for_tstate_lock() + File "/usr/lib/python3.6/threading.py", line 1072, in _wait_for_tstate_lock + elif lock.acquire(block, timeout): +KeyboardInterrupt +``` + +The message at the end occurs when killing the code. + +## Conclusion + +I have no idea why any of this would be useful, or if it is even field legal.. It's just a fun project for a monday morning. \ No newline at end of file diff --git a/_site/about/index.html b/_site/about/index.html index bed2246..67af25a 100644 --- a/_site/about/index.html +++ b/_site/about/index.html @@ -14,7 +14,7 @@ +{"@type":"WebSite","url":"http://0.0.0.0:4000/about/","name":"Evan Pratten","description":"Computer wizard, student, @frc5024 programming team lead, and radio enthusiast.","headline":"Evan Pratten","@context":"https://schema.org"} @@ -219,7 +219,7 @@ sub rsa4096/0xA61A2F1676E35144 2019-08-11 [] [expires: 2025-08-09] Site design by: Evan Pratten | - This site was last updated at: 2019-11-17 10:22:12 -0500 + This site was last updated at: 2019-11-20 10:04:40 -0500 diff --git a/_site/assets/css/main.css b/_site/assets/css/main.css index c5b8279..c8a4d8f 100644 --- a/_site/assets/css/main.css +++ b/_site/assets/css/main.css @@ -1,25 +1,18 @@ -body{ - margin:0; - padding:0; - - +body { + margin: 0; + padding: 0; font-family: 'IBM Plex Mono', monospace; - font-family: 'IBM Plex Sans', sans-serif; - - } -.foot{ - -} +.foot {} -.site-info{ - color:rgb(199, 195, 195); +.site-info { + color: rgb(199, 195, 195); background-color: #FFF; } -.header-gap{ +.header-gap { /* height: 30px; background-color: #ebeef1; */ } @@ -31,8 +24,6 @@ body{ background-repeat: no-repeat; background-size: cover; background-position: center; - - } .table-fix { @@ -44,11 +35,9 @@ table { margin-bottom: 1rem; color: #212529; vertical-align: top; - } -table th, -table td { +table th, table td { padding: 0.5rem; border-bottom: 1px solid #dee2e6; } @@ -74,23 +63,23 @@ thead th { .header .container { height: 100%; display: flex; - align-items: center; /* align vertical */ + align-items: center; + /* align vertical */ } .hidden { display: none !important; } - img { - max-width:100%; + max-width: 100%; } -.centre{ +.centre { text-align: center; } -h1, h2, h3, h4, h5, h6{ +h1, h2, h3, h4, h5, h6 { font-family: 'IBM Plex Mono', monospace; } @@ -105,7 +94,6 @@ a h5 { /* border-radius: 15px; transform: translateY(-30px); */ background-color: #fff; - } .home.container { @@ -115,8 +103,8 @@ a h5 { background-color: #fff; } -.container .profile{ - width:30vw; +.container .profile { + width: 30vw; max-width: 242px; transform: translateY(calc(10vh * -1)); border-color: #fff; @@ -130,25 +118,25 @@ a h5 { border-radius: 5%; } -.home-header{ - height:100%; +.home-header { + height: 100%; background-image: url('/assets/images/banner.jpg'); background-repeat: no-repeat; background-size: cover; background-position: center; } -.site-ctr{ - min-height:100vh; +.site-ctr { + min-height: 100vh; } .tagline { text-align: center; max-width: 600px; - margin:auto; + margin: auto; } -.container .info{ +.container .info { transform: translateY(calc(13vh * -1)); padding: 20px; } @@ -161,6 +149,7 @@ a h5 { /* #particles-js{ position: absolute; } */ + /* .reactive-bg{ position:relative @@ -192,6 +181,7 @@ blockquote { padding: 0.5em 10px; /* quotes: "\201C""\201D""\2018""\2019"; */ } + blockquote:before { color: #ccc; /* content: open-quote; */ @@ -200,6 +190,35 @@ blockquote:before { margin-right: 0.25em; vertical-align: -0.4em; } + blockquote p { display: inline; +} + +kbd { + margin: 0px 0.1em; + padding: 0.1em 0.6em; + border-radius: 3px; + border: 1px solid rgb(204, 204, 204); + color: rgb(51, 51, 51); + line-height: 1.4; + font-size: 10px; + display: inline-block; + box-shadow: 0px 1px 0px rgba(0,0,0,0.2), inset 0px 0px 0px 2px #ffffff; + background-color: rgb(247, 247, 247); + -moz-box-shadow: 0 1px 0px rgba(0, 0, 0, 0.2), 0 0 0 2px #ffffff inset; + -webkit-box-shadow: 0 1px 0px rgba(0, 0, 0, 0.2), 0 0 0 2px #ffffff inset; + -moz-border-radius: 3px; + -webkit-border-radius: 3px; + text-shadow: 0 1px 0 #fff; +} + +.highlight { + background-color: #faf9f9; + border-radius:5px; +} + +pre { + padding:3px; +} } \ No newline at end of file diff --git a/_site/blog/2018/06/27/becomeranter.html b/_site/blog/2018/06/27/becomeranter.html index a2a418a..0e6868b 100644 --- a/_site/blog/2018/06/27/becomeranter.html +++ b/_site/blog/2018/06/27/becomeranter.html @@ -16,7 +16,7 @@ +{"datePublished":"2018-06-27T14:32:00-04:00","dateModified":"2018-06-27T14:32:00-04:00","@type":"BlogPosting","mainEntityOfPage":{"@type":"WebPage","@id":"http://0.0.0.0:4000/blog/2018/06/27/becomeranter"},"url":"http://0.0.0.0:4000/blog/2018/06/27/becomeranter","description":"if/else ++","headline":"Using a python script to create devRant posts based on the style and content of another user","@context":"https://schema.org"} @@ -140,7 +140,7 @@ pip3 install tensorflow-gpu #for gpu processing Site design by: Evan Pratten | - This site was last updated at: 2019-11-17 10:22:12 -0500 + This site was last updated at: 2019-11-20 10:04:40 -0500 diff --git a/_site/blog/2019/04/30/frc-languages.html b/_site/blog/2019/04/30/frc-languages.html index 1f60aa8..cfd0412 100644 --- a/_site/blog/2019/04/30/frc-languages.html +++ b/_site/blog/2019/04/30/frc-languages.html @@ -16,7 +16,7 @@ +{"datePublished":"2019-04-30T14:32:00-04:00","dateModified":"2019-04-30T14:32:00-04:00","@type":"BlogPosting","mainEntityOfPage":{"@type":"WebPage","@id":"http://0.0.0.0:4000/blog/2019/04/30/frc-languages"},"url":"http://0.0.0.0:4000/blog/2019/04/30/frc-languages","description":"Our programming team is looking to switch languages in the 2020 season. Here is the what, why, and how.","headline":"The language hunt","@context":"https://schema.org"} @@ -104,7 +104,7 @@ Site design by: Evan Pratten | - This site was last updated at: 2019-11-17 10:22:12 -0500 + This site was last updated at: 2019-11-20 10:04:40 -0500 diff --git a/_site/blog/2019/05/27/building-safe-vision-comms.html b/_site/blog/2019/05/27/building-safe-vision-comms.html index a9d4902..4487464 100644 --- a/_site/blog/2019/05/27/building-safe-vision-comms.html +++ b/_site/blog/2019/05/27/building-safe-vision-comms.html @@ -16,7 +16,7 @@ +{"datePublished":"2019-05-27T05:22:00-04:00","dateModified":"2019-05-27T05:22:00-04:00","@type":"BlogPosting","mainEntityOfPage":{"@type":"WebPage","@id":"http://0.0.0.0:4000/blog/2019/05/27/building-safe-vision-comms"},"url":"http://0.0.0.0:4000/blog/2019/05/27/building-safe-vision-comms","description":"Computer vision on an FRC robot has some problems. RoboRIO is not powerfull enough NetworkTables is not fast enough A TCP connection is great until you lose connection mDNS discovery is not reliable on the field UDP can skip frames","headline":"Building a safe and easy system for sending computer vision data from a raspberry pi to a roborio","@context":"https://schema.org"} @@ -117,7 +117,7 @@ Site design by: Evan Pratten | - This site was last updated at: 2019-11-17 10:22:12 -0500 + This site was last updated at: 2019-11-20 10:04:40 -0500 diff --git a/_site/blog/2019/06/12/styiling-github.html b/_site/blog/2019/06/12/styiling-github.html index e6e6811..ac8e5d4 100644 --- a/_site/blog/2019/06/12/styiling-github.html +++ b/_site/blog/2019/06/12/styiling-github.html @@ -16,7 +16,7 @@ +{"datePublished":"2019-06-12T09:09:00-04:00","dateModified":"2019-06-12T09:09:00-04:00","@type":"BlogPosting","mainEntityOfPage":{"@type":"WebPage","@id":"http://0.0.0.0:4000/blog/2019/06/12/styiling-github"},"url":"http://0.0.0.0:4000/blog/2019/06/12/styiling-github","description":"I have been using GitHub since 2017, and have been getting tired of GitHub’s theme. I didn’t need a huge change, just a small refresh. So, to solve this, I whipped out Stylus and made a nice little CSS file for it.","headline":"GitHub’s CSS is boring. So I refreshed the design","@context":"https://schema.org"} @@ -128,7 +128,7 @@ Site design by: Evan Pratten | - This site was last updated at: 2019-11-17 10:22:12 -0500 + This site was last updated at: 2019-11-20 10:04:40 -0500 diff --git a/_site/blog/2019/06/16/graphing-w2a.html b/_site/blog/2019/06/16/graphing-w2a.html index 8b2dcad..55de383 100644 --- a/_site/blog/2019/06/16/graphing-w2a.html +++ b/_site/blog/2019/06/16/graphing-w2a.html @@ -16,7 +16,7 @@ +{"datePublished":"2019-06-16T11:51:00-04:00","dateModified":"2019-06-16T11:51:00-04:00","@type":"BlogPosting","mainEntityOfPage":{"@type":"WebPage","@id":"http://0.0.0.0:4000/blog/2019/06/16/graphing-w2a"},"url":"http://0.0.0.0:4000/blog/2019/06/16/graphing-w2a","description":"AKA. Why programmer + reddit + matplotlib is a bad idea.","headline":"Graphing the relation between wheels and awards for FRC","@context":"https://schema.org"} @@ -142,7 +142,7 @@ Site design by: Evan Pratten | - This site was last updated at: 2019-11-17 10:22:12 -0500 + This site was last updated at: 2019-11-20 10:04:40 -0500 diff --git a/_site/blog/2019/06/17/amm2m1-release.html b/_site/blog/2019/06/17/amm2m1-release.html index 28b20cf..b8bacf4 100644 --- a/_site/blog/2019/06/17/amm2m1-release.html +++ b/_site/blog/2019/06/17/amm2m1-release.html @@ -16,7 +16,7 @@ +{"datePublished":"2019-06-17T06:20:00-04:00","dateModified":"2019-06-17T06:20:00-04:00","@type":"BlogPosting","mainEntityOfPage":{"@type":"WebPage","@id":"http://0.0.0.0:4000/blog/2019/06/17/amm2m1-release"},"url":"http://0.0.0.0:4000/blog/2019/06/17/amm2m1-release","description":"Releasing a new song with friends at school","headline":"I made a new song!","@context":"https://schema.org"} @@ -101,7 +101,7 @@ Your browser does not support audio players Site design by: Evan Pratten | - This site was last updated at: 2019-11-17 10:22:12 -0500 + This site was last updated at: 2019-11-20 10:04:40 -0500 diff --git a/_site/blog/2019/06/21/robot-experiences.html b/_site/blog/2019/06/21/robot-experiences.html index c83790b..5442b6c 100644 --- a/_site/blog/2019/06/21/robot-experiences.html +++ b/_site/blog/2019/06/21/robot-experiences.html @@ -16,7 +16,7 @@ +{"datePublished":"2019-06-21T11:14:00-04:00","dateModified":"2019-06-21T11:14:00-04:00","@type":"BlogPosting","mainEntityOfPage":{"@type":"WebPage","@id":"http://0.0.0.0:4000/blog/2019/06/21/robot-experiences"},"url":"http://0.0.0.0:4000/blog/2019/06/21/robot-experiences","description":"Robots are pretty cool","headline":"What I have learned from 2 years of FRC programming","@context":"https://schema.org"} @@ -141,7 +141,7 @@ Site design by: Evan Pratten | - This site was last updated at: 2019-11-17 10:22:12 -0500 + This site was last updated at: 2019-11-20 10:04:40 -0500 diff --git a/_site/blog/2019/06/23/googlectf.html b/_site/blog/2019/06/23/googlectf.html index 58fd104..992d94f 100644 --- a/_site/blog/2019/06/23/googlectf.html +++ b/_site/blog/2019/06/23/googlectf.html @@ -16,7 +16,7 @@ +{"datePublished":"2019-06-23T18:04:00-04:00","dateModified":"2019-06-23T18:04:00-04:00","@type":"BlogPosting","mainEntityOfPage":{"@type":"WebPage","@id":"http://0.0.0.0:4000/blog/2019/06/23/googlectf"},"url":"http://0.0.0.0:4000/blog/2019/06/23/googlectf","description":"But exams got in the way and took all the fun","headline":"I gave Google’s CTF a short try and learned a thing or two","@context":"https://schema.org"} @@ -99,7 +99,7 @@ Site design by: Evan Pratten | - This site was last updated at: 2019-11-17 10:22:12 -0500 + This site was last updated at: 2019-11-20 10:04:40 -0500 diff --git a/_site/blog/2019/06/24/languagehunt2.html b/_site/blog/2019/06/24/languagehunt2.html index 98dd12c..87a42c1 100644 --- a/_site/blog/2019/06/24/languagehunt2.html +++ b/_site/blog/2019/06/24/languagehunt2.html @@ -16,7 +16,7 @@ +{"datePublished":"2019-06-24T17:36:00-04:00","dateModified":"2019-06-24T17:36:00-04:00","@type":"BlogPosting","mainEntityOfPage":{"@type":"WebPage","@id":"http://0.0.0.0:4000/blog/2019/06/24/languagehunt2"},"url":"http://0.0.0.0:4000/blog/2019/06/24/languagehunt2","description":"A quick followup","headline":"The language hunt: Part 2","@context":"https://schema.org"} @@ -99,7 +99,7 @@ Site design by: Evan Pratten | - This site was last updated at: 2019-11-17 10:22:12 -0500 + This site was last updated at: 2019-11-20 10:04:40 -0500 diff --git a/_site/blog/2019/06/26/bashsmash.html b/_site/blog/2019/06/26/bashsmash.html index 258734c..4a129fb 100644 --- a/_site/blog/2019/06/26/bashsmash.html +++ b/_site/blog/2019/06/26/bashsmash.html @@ -16,7 +16,7 @@ +{"datePublished":"2019-06-26T11:48:00-04:00","dateModified":"2019-06-26T11:48:00-04:00","@type":"BlogPosting","mainEntityOfPage":{"@type":"WebPage","@id":"http://0.0.0.0:4000/blog/2019/06/26/bashsmash"},"url":"http://0.0.0.0:4000/blog/2019/06/26/bashsmash","description":"A tool for driving people crazy","headline":"BashSmash","@context":"https://schema.org"} @@ -208,7 +208,7 @@ __() {/???/???/???n?f Site design by: Evan Pratten | - This site was last updated at: 2019-11-17 10:22:12 -0500 + This site was last updated at: 2019-11-20 10:04:40 -0500 diff --git a/_site/blog/2019/06/27/pwnlink.html b/_site/blog/2019/06/27/pwnlink.html index 8cd2854..92f9e06 100644 --- a/_site/blog/2019/06/27/pwnlink.html +++ b/_site/blog/2019/06/27/pwnlink.html @@ -16,7 +16,7 @@ +{"datePublished":"2019-06-27T13:16:00-04:00","dateModified":"2019-06-27T13:16:00-04:00","@type":"BlogPosting","mainEntityOfPage":{"@type":"WebPage","@id":"http://0.0.0.0:4000/blog/2019/06/27/pwnlink"},"url":"http://0.0.0.0:4000/blog/2019/06/27/pwnlink","description":"cleartext passwords + external management = death wish","headline":"I had some fun with a router","@context":"https://schema.org"} @@ -129,7 +129,7 @@ Site design by: Evan Pratten | - This site was last updated at: 2019-11-17 10:22:12 -0500 + This site was last updated at: 2019-11-20 10:04:40 -0500 diff --git a/_site/blog/2019/06/27/python.html b/_site/blog/2019/06/27/python.html index 81a7d09..aa2d24b 100644 --- a/_site/blog/2019/06/27/python.html +++ b/_site/blog/2019/06/27/python.html @@ -16,7 +16,7 @@ +{"datePublished":"2019-06-27T03:00:00-04:00","dateModified":"2019-06-27T03:00:00-04:00","@type":"BlogPosting","mainEntityOfPage":{"@type":"WebPage","@id":"http://0.0.0.0:4000/blog/2019/06/27/python"},"url":"http://0.0.0.0:4000/blog/2019/06/27/python","description":"Python is a little too forgiving","headline":"Hunting snakes with a shotgun","@context":"https://schema.org"} @@ -194,7 +194,7 @@ Site design by: Evan Pratten | - This site was last updated at: 2019-11-17 10:22:12 -0500 + This site was last updated at: 2019-11-20 10:04:40 -0500 diff --git a/_site/blog/2019/07/01/devdns.html b/_site/blog/2019/07/01/devdns.html index 90009c5..42acb68 100644 --- a/_site/blog/2019/07/01/devdns.html +++ b/_site/blog/2019/07/01/devdns.html @@ -16,7 +16,7 @@ +{"datePublished":"2019-07-01T18:13:00-04:00","dateModified":"2019-07-01T18:13:00-04:00","@type":"BlogPosting","mainEntityOfPage":{"@type":"WebPage","@id":"http://0.0.0.0:4000/blog/2019/07/01/devdns"},"url":"http://0.0.0.0:4000/blog/2019/07/01/devdns","description":"The DNS over devRant service","headline":"devDNS","@context":"https://schema.org"} @@ -118,7 +118,7 @@ Site design by: Evan Pratten | - This site was last updated at: 2019-11-17 10:22:12 -0500 + This site was last updated at: 2019-11-20 10:04:40 -0500 diff --git a/_site/blog/2019/07/06/scrapingfrcgithub.html b/_site/blog/2019/07/06/scrapingfrcgithub.html index 74ffbdb..ecc9c9e 100644 --- a/_site/blog/2019/07/06/scrapingfrcgithub.html +++ b/_site/blog/2019/07/06/scrapingfrcgithub.html @@ -16,7 +16,7 @@ +{"datePublished":"2019-07-06T11:08:00-04:00","dateModified":"2019-07-06T11:08:00-04:00","@type":"BlogPosting","mainEntityOfPage":{"@type":"WebPage","@id":"http://0.0.0.0:4000/blog/2019/07/06/scrapingfrcgithub"},"url":"http://0.0.0.0:4000/blog/2019/07/06/scrapingfrcgithub","description":"There are a lot of teams…","headline":"Scraping FRC team’s GitHub accounts to gather large amounts of data","@context":"https://schema.org"} @@ -191,7 +191,7 @@ Site design by: Evan Pratten | - This site was last updated at: 2019-11-17 10:22:12 -0500 + This site was last updated at: 2019-11-20 10:04:40 -0500 diff --git a/_site/blog/2019/07/13/lookback-gmad.html b/_site/blog/2019/07/13/lookback-gmad.html index c34dd29..12eafc9 100644 --- a/_site/blog/2019/07/13/lookback-gmad.html +++ b/_site/blog/2019/07/13/lookback-gmad.html @@ -16,7 +16,7 @@ +{"datePublished":"2019-07-13T10:43:00-04:00","dateModified":"2019-07-13T10:43:00-04:00","@type":"BlogPosting","mainEntityOfPage":{"@type":"WebPage","@id":"http://0.0.0.0:4000/blog/2019/07/13/lookback-gmad"},"url":"http://0.0.0.0:4000/blog/2019/07/13/lookback-gmad","description":"Fun, Simple, and Quick","headline":"Taking a look back at GMAD","@context":"https://schema.org"} @@ -112,7 +112,7 @@ Site design by: Evan Pratten | - This site was last updated at: 2019-11-17 10:22:12 -0500 + This site was last updated at: 2019-11-20 10:04:40 -0500 diff --git a/_site/blog/2019/07/15/mindmap.html b/_site/blog/2019/07/15/mindmap.html index 677a27a..678a119 100644 --- a/_site/blog/2019/07/15/mindmap.html +++ b/_site/blog/2019/07/15/mindmap.html @@ -16,7 +16,7 @@ +{"datePublished":"2019-07-15T14:38:00-04:00","dateModified":"2019-07-15T14:38:00-04:00","@type":"BlogPosting","mainEntityOfPage":{"@type":"WebPage","@id":"http://0.0.0.0:4000/blog/2019/07/15/mindmap"},"url":"http://0.0.0.0:4000/blog/2019/07/15/mindmap","description":"Step 1","headline":"Mind map generation with Python","@context":"https://schema.org"} @@ -206,7 +206,7 @@ Site design by: Evan Pratten | - This site was last updated at: 2019-11-17 10:22:12 -0500 + This site was last updated at: 2019-11-20 10:04:40 -0500 diff --git a/_site/blog/2019/08/10/why-i-carry-nfc.html b/_site/blog/2019/08/10/why-i-carry-nfc.html index f2fdc49..601fd53 100644 --- a/_site/blog/2019/08/10/why-i-carry-nfc.html +++ b/_site/blog/2019/08/10/why-i-carry-nfc.html @@ -16,7 +16,7 @@ +{"datePublished":"2019-08-10T16:57:00-04:00","dateModified":"2019-08-10T16:57:00-04:00","@type":"BlogPosting","mainEntityOfPage":{"@type":"WebPage","@id":"http://0.0.0.0:4000/blog/2019/08/10/why-i-carry-nfc"},"url":"http://0.0.0.0:4000/blog/2019/08/10/why-i-carry-nfc","description":"Reasons why I always carry NFC cards with me","headline":"My weird piece of EDC","@context":"https://schema.org"} @@ -124,7 +124,7 @@ Site design by: Evan Pratten | - This site was last updated at: 2019-11-17 10:22:12 -0500 + This site was last updated at: 2019-11-20 10:04:40 -0500 diff --git a/_site/blog/2019/08/12/setting-up-ja.html b/_site/blog/2019/08/12/setting-up-ja.html index 6bb401d..d648c84 100644 --- a/_site/blog/2019/08/12/setting-up-ja.html +++ b/_site/blog/2019/08/12/setting-up-ja.html @@ -16,7 +16,7 @@ +{"datePublished":"2019-08-12T15:40:00-04:00","dateModified":"2019-08-12T15:40:00-04:00","@type":"BlogPosting","mainEntityOfPage":{"@type":"WebPage","@id":"http://0.0.0.0:4000/blog/2019/08/12/setting-up-ja"},"url":"http://0.0.0.0:4000/blog/2019/08/12/setting-up-ja","description":"I3wm makes everything 10x harder than it should be","headline":"How I set up ひらがな input on my laptop","@context":"https://schema.org"} @@ -169,7 +169,7 @@ ibus-daemon -drx Site design by: Evan Pratten | - This site was last updated at: 2019-11-17 10:22:12 -0500 + This site was last updated at: 2019-11-20 10:04:40 -0500 diff --git a/_site/blog/2019/08/24/shift2.html b/_site/blog/2019/08/24/shift2.html index a09c829..065cd1c 100644 --- a/_site/blog/2019/08/24/shift2.html +++ b/_site/blog/2019/08/24/shift2.html @@ -16,7 +16,7 @@ +{"datePublished":"2019-08-24T09:13:00-04:00","dateModified":"2019-08-24T09:13:00-04:00","@type":"BlogPosting","mainEntityOfPage":{"@type":"WebPage","@id":"http://0.0.0.0:4000/blog/2019/08/24/shift2"},"url":"http://0.0.0.0:4000/blog/2019/08/24/shift2","description":"XOR is pretty cool","headline":"Keyed data encoding with Python","@context":"https://schema.org"} @@ -154,7 +154,7 @@ shift2 -h Site design by: Evan Pratten | - This site was last updated at: 2019-11-17 10:22:12 -0500 + This site was last updated at: 2019-11-20 10:04:40 -0500 diff --git a/_site/blog/2019/08/27/github-cleanup.html b/_site/blog/2019/08/27/github-cleanup.html index 6ba1de0..502d8bd 100644 --- a/_site/blog/2019/08/27/github-cleanup.html +++ b/_site/blog/2019/08/27/github-cleanup.html @@ -16,7 +16,7 @@ +{"datePublished":"2019-08-27T08:37:00-04:00","dateModified":"2019-08-27T08:37:00-04:00","@type":"BlogPosting","mainEntityOfPage":{"@type":"WebPage","@id":"http://0.0.0.0:4000/blog/2019/08/27/github-cleanup"},"url":"http://0.0.0.0:4000/blog/2019/08/27/github-cleanup","description":"Spring cleaning is fun when it isn’t spring, and a computer does all the work","headline":"I did some cleaning","@context":"https://schema.org"} @@ -125,7 +125,7 @@ Starting from the top, scroll through, and middle click on anything you want to Site design by: Evan Pratten | - This site was last updated at: 2019-11-17 10:22:12 -0500 + This site was last updated at: 2019-11-20 10:04:40 -0500 diff --git a/_site/blog/2019/09/07/wrong-python.html b/_site/blog/2019/09/07/wrong-python.html index bbe2454..9c4d628 100644 --- a/_site/blog/2019/09/07/wrong-python.html +++ b/_site/blog/2019/09/07/wrong-python.html @@ -16,7 +16,7 @@ +{"datePublished":"2019-09-07T09:13:00-04:00","dateModified":"2019-09-07T09:13:00-04:00","@type":"BlogPosting","mainEntityOfPage":{"@type":"WebPage","@id":"http://0.0.0.0:4000/blog/2019/09/07/wrong-python"},"url":"http://0.0.0.0:4000/blog/2019/09/07/wrong-python","description":"In the name of science!","headline":"Doing Python OOP the wrong way","@context":"https://schema.org"} @@ -174,7 +174,7 @@ fn printMyNumber(MyClass* self){ Site design by: Evan Pratten | - This site was last updated at: 2019-11-17 10:22:12 -0500 + This site was last updated at: 2019-11-20 10:04:40 -0500 diff --git a/_site/blog/index.html b/_site/blog/index.html index aba54ce..3c6c444 100644 --- a/_site/blog/index.html +++ b/_site/blog/index.html @@ -14,7 +14,7 @@ +{"@type":"WebPage","url":"http://0.0.0.0:4000/blog/","description":"Computer wizard, student, @frc5024 programming team lead, and radio enthusiast.","headline":"Evan Pratten","@context":"https://schema.org"} @@ -79,22 +79,22 @@ Featured Post
-
Turning a web IDE into a disposable linux environment +
Programming a live robot
-

My Python code keeps popping shells

- View +

Living on the edge is an understatement

+ View
--> - +
-
Turning a web IDE into a disposable linux environment +
Programming a live robot
-

My Python code keeps popping shells

+

Living on the edge is an understatement

@@ -107,6 +107,21 @@ + +
+
Turning a web IDE into a disposable linux environment
+ +
+

My Python code keeps popping shells

+
+ + + + + + + +
Using an RNN to generate Bill Wurtz notes
@@ -550,7 +565,7 @@ Site design by:
Evan Pratten | - This site was last updated at: 2019-11-17 10:22:12 -0500 + This site was last updated at: 2019-11-20 10:04:40 -0500
diff --git a/_site/documentation.html b/_site/documentation.html index 48d984e..a8cf8a6 100644 --- a/_site/documentation.html +++ b/_site/documentation.html @@ -14,7 +14,7 @@ +{"@type":"WebPage","url":"http://0.0.0.0:4000/documentation","description":"Computer wizard, student, @frc5024 programming team lead, and radio enthusiast.","headline":"Evan Pratten","@context":"https://schema.org"} @@ -67,7 +67,7 @@ Site design by: Evan Pratten | - This site was last updated at: 2019-11-17 10:22:12 -0500 + This site was last updated at: 2019-11-20 10:04:40 -0500 diff --git a/_site/feed.xml b/_site/feed.xml index 2b5a9ee..6a8aeee 100644 --- a/_site/feed.xml +++ b/_site/feed.xml @@ -1,4 +1,175 @@ -Jekyll2019-11-17T10:22:12-05:00http://0.0.0.0:4000/feed.xmlEvan PrattenComputer wizard, student, <a href="https://frc5024.github.io">@frc5024</a> programming team lead, and radio enthusiast.Using an RNN to generate Bill Wurtz notes2019-10-05T14:54:00-04:002019-10-05T14:54:00-04:00http://0.0.0.0:4000/blog/2019/10/05/BillWurtz<p><a href="https://billwurtz.com/">Bill Wurtz</a> is an American musician who became <a href="https://socialblade.com/youtube/user/billwurtz/realtime">reasonably famous</a> through short musical videos posted to Vine and YouTube. I was searching through his website the other day, and stumbled upon a page labeled <a href="https://billwurtz.com/notebook.html"><em>notebook</em></a>, and thought I should check it out.</p> +Jekyll2019-11-20T10:04:40-05:00http://0.0.0.0:4000/feed.xmlEvan PrattenComputer wizard, student, <a href="https://frc5024.github.io">@frc5024</a> programming team lead, and radio enthusiast.Programming a live robot2019-11-20T05:04:00-05:002019-11-20T05:04:00-05:00http://0.0.0.0:4000/blog/2019/11/20/Realtime-robot-code<blockquote> + <p><em>“So.. what if we could skip asking for driver inputs, and just have the robot operators control the bot through a commandline interface?”</em></p> +</blockquote> + +<p>This is exactly the kind of question I randomly ask while sitting in the middle of class, staring at my laptop. So, here is a post about my real-time programming adventure!</p> + +<h2 id="geting-started">Geting started</h2> + +<p>To get started, I needed a few things. Firstly, I have a laptop running <a href="/about/#my-gear">a Linux distribution</a>. This allows me to use <a href="https://en.wikipedia.org/wiki/Secure_Shell">SSH</a> and <a href="https://en.wikipedia.org/wiki/Secure_copy">SCP</a>. There are Windows versions of both of these programs, but I find the “linux experience” easier to use. Secondly, I have grabbed one of <a href="https://www.thebluealliance.com/team/5024">5024</a>’s <a href="https://cs.5024.ca/webdocs/docs/robots">robots</a> to be subjected to my experiment. The components I care about are:</p> + +<ul> + <li>A RoboRIO running 2019v12 firmware</li> + <li>2 <a href="https://www.ctr-electronics.com/talon-srx.html">TalonSRX</a> motor controllers</li> + <li>An FRC router</li> +</ul> + +<p>Most importantly, the RoboRIO has <a href="https://robotpy.readthedocs.io/en/stable/install/robot.html#install-robotpy">RobotPy</a> and the <a href="https://robotpy.readthedocs.io/en/stable/install/ctre.html">CTRE Libraries</a> installed.</p> + +<h3 id="ssh-connection">SSH connection</h3> + +<p>To get some code running on the robot, we must first connect to it via SSH. Depending on your connection to the RoboRIO, this step may be different. Generally, the following command will work just fine to connect (assuming your computer has an <a href="https://en.wikipedia.org/wiki/Multicast_DNS">mDNS</a> service):</p> + +<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>ssh admin@roborio-&lt;team&gt;-frc.local +</code></pre></div></div> + +<p>If you have issues, try one of the following addresses instead:</p> + +<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>roborio-&lt;team&gt;-FRC +roborio-&lt;team&gt;-FRC.lan +roborio-&lt;team&gt;-FRC.frc-field.local +10.TE.AM.2 +172.22.11.2 # Only works on a USB connection +</code></pre></div></div> + +<p>If you are asked for a password, and have not set one, press <kbd>Enter</kbd> 3 times (Don’t ask why.. this just works).</p> + +<h2 id="repl-based-control">REPL-based control</h2> + +<p>If you have seen my work before, you’ll know that I use Python for basically everything. This project is no exception. Conveniently, the RoboRIO is a linux-based device, and can run a Python3 <a href="https://en.wikipedia.org/wiki/Read%E2%80%93eval%E2%80%93print_loop">REPL</a>. This allows real-time robot programming using a REPL via SSH.</p> + +<p>WPILib requires a robot class to act as a “callback” for robot actions. My idea was to build a special robot class with static methods to allow me to start it, then use the REPL to interact with some control methods (like <code class="highlighter-rouge">setSpeed</code> and <code class="highlighter-rouge">stop</code>).</p> + +<p>After connecting to the robot via SSH, a Python REPL can be started by running <code class="highlighter-rouge">python3</code>. If there is already robot code running, it will be automatically killed in the next step.</p> + +<p>With Python running, we will need 2 libraries imported. <code class="highlighter-rouge">wpilib</code> and <code class="highlighter-rouge">ctre</code>. When importing <code class="highlighter-rouge">wpilib</code> a message may appear to notify you that the old robot code has been stopped.</p> + +<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">&gt;&gt;&gt;</span> <span class="kn">import</span> <span class="nn">wpilib</span> +<span class="n">Killing</span> <span class="n">previously</span> <span class="n">running</span> <span class="n">FRC</span> <span class="n">program</span><span class="o">...</span> +<span class="n">FRC</span> <span class="n">pid</span> <span class="mi">1445</span> <span class="n">did</span> <span class="ow">not</span> <span class="n">die</span> <span class="n">within</span> <span class="mi">0</span><span class="n">ms</span><span class="o">.</span> <span class="n">Force</span> <span class="n">killing</span> <span class="k">with</span> <span class="n">kill</span> <span class="o">-</span><span class="mi">9</span> +<span class="o">&gt;&gt;&gt;</span> <span class="kn">import</span> <span class="nn">ctre</span> +</code></pre></div></div> +<p>Keep in mind, this is a REPL. Lines that start with <code class="highlighter-rouge">&gt;&gt;&gt;</code> or <code class="highlighter-rouge">...</code> are <em>user input</em>. Everything else is produced by code.</p> + +<p>Next, we need to write a little code to get the robot operational. To save time, I wrote this “library” to do most of the work for me. Just save this as <code class="highlighter-rouge">rtrbt.py</code> somewhere, then use SCP to copy it to <code class="highlighter-rouge">/home/lvuser/rtrbt.py</code>.</p> + +<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># RealTime FRC Robot control helper +# By: Evan Pratten &lt;ewpratten&gt; +</span> +<span class="c1"># Import normal robot stuff +</span><span class="kn">import</span> <span class="nn">wpilib</span> +<span class="kn">import</span> <span class="nn">ctre</span> + +<span class="c1"># Handle WPI trickery +</span><span class="k">try</span><span class="p">:</span> + <span class="kn">from</span> <span class="nn">unittest.mock</span> <span class="kn">import</span> <span class="n">patch</span> +<span class="k">except</span> <span class="nb">ImportError</span><span class="p">:</span> + <span class="kn">from</span> <span class="nn">mock</span> <span class="kn">import</span> <span class="n">patch</span> +<span class="kn">import</span> <span class="nn">sys</span> +<span class="kn">from</span> <span class="nn">threading</span> <span class="kn">import</span> <span class="n">Thread</span> + + +<span class="c1">## Internal methods ## +</span><span class="n">_controllers</span> <span class="o">=</span> <span class="p">[]</span> +<span class="n">_thread</span><span class="p">:</span> <span class="n">Thread</span> + + +<span class="k">class</span> <span class="nc">_RTRobot</span><span class="p">(</span><span class="n">wpilib</span><span class="o">.</span><span class="n">TimedRobot</span><span class="p">):</span> + + <span class="k">def</span> <span class="nf">robotInit</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span> + + <span class="c1"># Create motors +</span> <span class="n">_controllers</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">ctre</span><span class="o">.</span><span class="n">WPI_TalonSRX</span><span class="p">(</span><span class="mi">1</span><span class="p">))</span> + <span class="n">_controllers</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">ctre</span><span class="o">.</span><span class="n">WPI_TalonSRX</span><span class="p">(</span><span class="mi">2</span><span class="p">))</span> + + <span class="c1"># Set safe modes +</span> <span class="n">_controllers</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">.</span><span class="n">setSafetyEnabled</span><span class="p">(</span><span class="bp">False</span><span class="p">)</span> + <span class="n">_controllers</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span><span class="o">.</span><span class="n">setSafetyEnabled</span><span class="p">(</span><span class="bp">False</span><span class="p">)</span> + + + +<span class="k">def</span> <span class="nf">_start</span><span class="p">():</span> + <span class="c1"># Handle fake args +</span> <span class="n">args</span> <span class="o">=</span> <span class="p">[</span><span class="s">"run"</span><span class="p">,</span> <span class="s">"run"</span><span class="p">]</span> + <span class="k">with</span> <span class="n">patch</span><span class="o">.</span><span class="nb">object</span><span class="p">(</span><span class="n">sys</span><span class="p">,</span> <span class="s">"argv"</span><span class="p">,</span> <span class="n">args</span><span class="p">):</span> + <span class="k">print</span><span class="p">(</span><span class="n">sys</span><span class="o">.</span><span class="n">argv</span><span class="p">)</span> + <span class="n">wpilib</span><span class="o">.</span><span class="n">run</span><span class="p">(</span><span class="n">_RTRobot</span><span class="p">)</span> + +<span class="c1">## Utils ## +</span> + +<span class="k">def</span> <span class="nf">startRobot</span><span class="p">():</span> + <span class="s">""" Start the robot code """</span> + <span class="k">global</span> <span class="n">_thread</span> + <span class="n">_thread</span> <span class="o">=</span> <span class="n">Thread</span><span class="p">(</span><span class="n">target</span><span class="o">=</span><span class="n">_start</span><span class="p">)</span> + <span class="n">_thread</span><span class="o">.</span><span class="n">start</span><span class="p">()</span> + + +<span class="k">def</span> <span class="nf">setMotor</span><span class="p">(</span><span class="nb">id</span><span class="p">,</span> <span class="n">speed</span><span class="p">):</span> + <span class="s">""" Set a motor speed """</span> + <span class="n">_controllers</span><span class="p">[</span><span class="nb">id</span><span class="p">]</span><span class="o">.</span><span class="nb">set</span><span class="p">(</span><span class="n">speed</span><span class="p">)</span> + +<span class="k">def</span> <span class="nf">arcadeDrive</span><span class="p">(</span><span class="n">speed</span><span class="p">,</span> <span class="n">rotation</span><span class="p">):</span> + <span class="s">""" Control the robot with arcade inputs """</span> + + <span class="n">l</span> <span class="o">=</span> <span class="n">speed</span> <span class="o">+</span> <span class="n">rotation</span> + <span class="n">r</span> <span class="o">=</span> <span class="n">speed</span> <span class="o">-</span> <span class="n">rotation</span> + + <span class="n">setMotor</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="n">l</span><span class="p">)</span> + <span class="n">setMotor</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="n">r</span><span class="p">)</span> +</code></pre></div></div> + +<p>The idea is to create a simple robot program with global hooks into the motor controllers. Python’s mocking tools are used to fake commandline arguments to trick robotpy into thinking this script is being run via the RIO’s robotCommand.</p> + +<p>Once this script has been placed on the robot, SSH back in as <code class="highlighter-rouge">lvuser</code> (not <code class="highlighter-rouge">admin</code>), and run <code class="highlighter-rouge">python3</code>. If using <code class="highlighter-rouge">rtrbt.py</code>, the imports mentioned above are handled for you. To start the robot, just run the following:</p> + +<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">&gt;&gt;&gt;</span> <span class="kn">from</span> <span class="nn">rtrbt</span> <span class="kn">import</span> <span class="o">*</span> +<span class="o">&gt;&gt;&gt;</span> <span class="n">startRobot</span><span class="p">()</span> +</code></pre></div></div> + +<p>WPILib will dump some logs into the terminal (and probably some spam) from it’s own thread. Don’t worry if you can’t see the REPL prompt. It’s probably just hidden due to the use of multiple threads in the same shell. Pressing <kbd>Enter</kbd> should show it again.</p> + +<p>I added 2 functions for controlling motors. The first, <code class="highlighter-rouge">setMotor</code>, will set either the left (0), or right (1) motor to the specified speed. <code class="highlighter-rouge">arcadeDrive</code> will allow you to specify a speed and rotational force for the robot’s drivetrain.</p> + +<p>To kill the code and exit, press <kbd>CTRL</kbd> + <kbd>D</kbd> then <kbd>CTRL</kbd> + <kbd>C</kbd>.</p> + +<p>Here is an example where I start the bot, then tell it to drive forward, then kill the left motor:</p> +<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">Python</span> <span class="mf">3.6.8</span> <span class="p">(</span><span class="n">default</span><span class="p">,</span> <span class="n">Oct</span> <span class="mi">7</span> <span class="mi">2019</span><span class="p">,</span> <span class="mi">12</span><span class="p">:</span><span class="mi">59</span><span class="p">:</span><span class="mi">55</span><span class="p">)</span> +<span class="p">[</span><span class="n">GCC</span> <span class="mf">8.3.0</span><span class="p">]</span> <span class="n">on</span> <span class="n">linux</span> +<span class="n">Type</span> <span class="s">"help"</span><span class="p">,</span> <span class="s">"copyright"</span><span class="p">,</span> <span class="s">"credits"</span> <span class="ow">or</span> <span class="s">"license"</span> <span class="k">for</span> <span class="n">more</span> <span class="n">information</span><span class="o">.</span> +<span class="o">&gt;&gt;&gt;</span> <span class="kn">from</span> <span class="nn">rtrbt</span> <span class="kn">import</span> <span class="o">*</span> +<span class="o">&gt;&gt;&gt;</span> <span class="n">startRobot</span><span class="p">()</span> +<span class="p">[</span><span class="s">'run'</span><span class="p">,</span> <span class="s">'run'</span><span class="p">]</span> +<span class="mi">17</span><span class="p">:</span><span class="mi">53</span><span class="p">:</span><span class="mi">46</span><span class="p">:</span><span class="mi">472</span> <span class="n">INFO</span> <span class="p">:</span> <span class="n">wpilib</span> <span class="p">:</span> <span class="n">WPILib</span> <span class="n">version</span> <span class="mf">2019.2.3</span> +<span class="mi">17</span><span class="p">:</span><span class="mi">53</span><span class="p">:</span><span class="mi">46</span><span class="p">:</span><span class="mi">473</span> <span class="n">INFO</span> <span class="p">:</span> <span class="n">wpilib</span> <span class="p">:</span> <span class="n">HAL</span> <span class="n">base</span> <span class="n">version</span> <span class="mf">2019.2.3</span><span class="p">;</span> +<span class="mi">17</span><span class="p">:</span><span class="mi">53</span><span class="p">:</span><span class="mi">46</span><span class="p">:</span><span class="mi">473</span> <span class="n">INFO</span> <span class="p">:</span> <span class="n">wpilib</span> <span class="p">:</span> <span class="n">robotpy</span><span class="o">-</span><span class="n">ctre</span> <span class="n">version</span> <span class="mf">2019.3.2</span> +<span class="mi">17</span><span class="p">:</span><span class="mi">53</span><span class="p">:</span><span class="mi">46</span><span class="p">:</span><span class="mi">473</span> <span class="n">INFO</span> <span class="p">:</span> <span class="n">wpilib</span> <span class="p">:</span> <span class="n">robotpy</span><span class="o">-</span><span class="n">cscore</span> <span class="n">version</span> <span class="mf">2019.1.0</span> +<span class="mi">17</span><span class="p">:</span><span class="mi">53</span><span class="p">:</span><span class="mi">46</span><span class="p">:</span><span class="mi">473</span> <span class="n">INFO</span> <span class="p">:</span> <span class="n">faulthandler</span> <span class="p">:</span> <span class="n">registered</span> <span class="n">SIGUSR2</span> <span class="k">for</span> <span class="n">PID</span> <span class="mi">5447</span> +<span class="mi">17</span><span class="p">:</span><span class="mi">53</span><span class="p">:</span><span class="mi">46</span><span class="p">:</span><span class="mi">474</span> <span class="n">INFO</span> <span class="p">:</span> <span class="n">nt</span> <span class="p">:</span> <span class="n">NetworkTables</span> <span class="n">initialized</span> <span class="ow">in</span> <span class="n">server</span> <span class="n">mode</span> +<span class="mi">17</span><span class="p">:</span><span class="mi">53</span><span class="p">:</span><span class="mi">46</span><span class="p">:</span><span class="mi">497</span> <span class="n">INFO</span> <span class="p">:</span> <span class="n">robot</span> <span class="p">:</span> <span class="n">Default</span> <span class="n">IterativeRobot</span><span class="o">.</span><span class="n">disabledInit</span><span class="p">()</span> <span class="n">method</span><span class="o">...</span> <span class="n">Override</span> <span class="n">me</span><span class="err">!</span> +<span class="mi">17</span><span class="p">:</span><span class="mi">53</span><span class="p">:</span><span class="mi">46</span><span class="p">:</span><span class="mi">498</span> <span class="n">INFO</span> <span class="p">:</span> <span class="n">robot</span> <span class="p">:</span> <span class="n">Default</span> <span class="n">IterativeRobot</span><span class="o">.</span><span class="n">disabledPeriodic</span><span class="p">()</span> <span class="n">method</span><span class="o">...</span> <span class="n">Override</span> <span class="n">me</span><span class="err">!</span> +<span class="mi">17</span><span class="p">:</span><span class="mi">53</span><span class="p">:</span><span class="mi">46</span><span class="p">:</span><span class="mi">498</span> <span class="n">INFO</span> <span class="p">:</span> <span class="n">robot</span> <span class="p">:</span> <span class="n">Default</span> <span class="n">IterativeRobot</span><span class="o">.</span><span class="n">robotPeriodic</span><span class="p">()</span> <span class="n">method</span><span class="o">...</span> <span class="n">Override</span> <span class="n">me</span><span class="err">!</span> +<span class="o">&gt;&gt;&gt;</span> +<span class="o">&gt;&gt;&gt;</span> <span class="n">arcadeDrive</span><span class="p">(</span><span class="mf">1.0</span><span class="p">,</span> <span class="mf">0.0</span><span class="p">)</span> +<span class="o">&gt;&gt;&gt;</span> <span class="n">setMotor</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mf">0.0</span><span class="p">)</span> +<span class="o">&gt;&gt;&gt;</span> +<span class="o">^</span><span class="n">C</span> +<span class="nb">Exception</span> <span class="n">ignored</span> <span class="ow">in</span><span class="p">:</span> <span class="o">&lt;</span><span class="n">module</span> <span class="s">'threading'</span> <span class="k">from</span> <span class="s">'/usr/lib/python3.6/threading.py'</span><span class="o">&gt;</span> +<span class="n">Traceback</span> <span class="p">(</span><span class="n">most</span> <span class="n">recent</span> <span class="n">call</span> <span class="n">last</span><span class="p">):</span> + <span class="n">File</span> <span class="s">"/usr/lib/python3.6/threading.py"</span><span class="p">,</span> <span class="n">line</span> <span class="mi">1294</span><span class="p">,</span> <span class="ow">in</span> <span class="n">_shutdown</span> + <span class="n">t</span><span class="o">.</span><span class="n">join</span><span class="p">()</span> + <span class="n">File</span> <span class="s">"/usr/lib/python3.6/threading.py"</span><span class="p">,</span> <span class="n">line</span> <span class="mi">1056</span><span class="p">,</span> <span class="ow">in</span> <span class="n">join</span> + <span class="bp">self</span><span class="o">.</span><span class="n">_wait_for_tstate_lock</span><span class="p">()</span> + <span class="n">File</span> <span class="s">"/usr/lib/python3.6/threading.py"</span><span class="p">,</span> <span class="n">line</span> <span class="mi">1072</span><span class="p">,</span> <span class="ow">in</span> <span class="n">_wait_for_tstate_lock</span> + <span class="k">elif</span> <span class="n">lock</span><span class="o">.</span><span class="n">acquire</span><span class="p">(</span><span class="n">block</span><span class="p">,</span> <span class="n">timeout</span><span class="p">):</span> +<span class="nb">KeyboardInterrupt</span> +</code></pre></div></div> + +<p>The message at the end occurs when killing the code.</p> + +<h2 id="conclusion">Conclusion</h2> + +<p>I have no idea why any of this would be useful, or if it is even field legal.. It’s just a fun project for a monday morning.</p>“So.. what if we could skip asking for driver inputs, and just have the robot operators control the bot through a commandline interface?”Using an RNN to generate Bill Wurtz notes2019-10-05T14:54:00-04:002019-10-05T14:54:00-04:00http://0.0.0.0:4000/blog/2019/10/05/BillWurtz<p><a href="https://billwurtz.com/">Bill Wurtz</a> is an American musician who became <a href="https://socialblade.com/youtube/user/billwurtz/realtime">reasonably famous</a> through short musical videos posted to Vine and YouTube. I was searching through his website the other day, and stumbled upon a page labeled <a href="https://billwurtz.com/notebook.html"><em>notebook</em></a>, and thought I should check it out.</p> <p>Bill’s notebook is a large (about 580 posts) collection of random thoughts, ideas, and sometimes just collections of words. A prime source of entertainment, and neural network inputs..</p> @@ -568,105 +739,4 @@ ibus-daemon <span class="nt">-drx</span> <p>If you would like to add a distro or three to the website, feel free to make a pull request over on <a href="https://github.com/Ewpratten/GiveMeADistro">GitHub</a>.</p> <h2 id="why-make-a-post-about-it-a-year-later">Why make a post about it a year later?</h2> -<p>I just really enjoyed working with the project and sharing it with friends, so I figured I should mention it here too. Maybe it will inspire someone to make something cool!</p>One day, back in June of 2018, I was both looking for a new project to work on, and trying to decide which Linux distro to install on one of my computers. From this, a little project was born. Give Me a Distro (or, GMAD, as I like to call it) is a little website that chooses a random distribution of Linux and shows a description of what you are about to get yourself into, and a download link for the latest ISO.Scraping FRC team’s GitHub accounts to gather large amounts of data2019-07-06T11:08:00-04:002019-07-06T11:08:00-04:00http://0.0.0.0:4000/blog/2019/07/06/ScrapingFRCGithub<p>I was curious about the most used languages for FRC, so I build a Python script to find out what they where.</p> - -<h2 id="some-basic-data">Some basic data</h2> -<p>Before we get to the heavy work done by my script, let’s start with some general data.</p> - -<p>Thanks to the <a href="https://www.thebluealliance.com/apidocs/v3">TBA API</a>, I know that there are 6917 registered teams. 492 of them have registered at least one account on GitHub.</p> - -<h2 id="how-the-script-works">How the script works</h2> -<p>The script is split into steps:</p> -<ul> - <li>Get a list of every registered team</li> - <li>Check for a github account attached to every registered team - <ul> - <li>If a team has an account, it is added to the dataset</li> - </ul> - </li> - <li>Load each github profile - <ul> - <li>If it is a private account, move on</li> - <li>Use Regex to find all languages used</li> - </ul> - </li> - <li>Compile data and sort</li> -</ul> - -<h3 id="getting-a-list-of-accounts">Getting a list of accounts</h3> -<p>This is probably the simplest step in the whole process. I used the auto-generated <a href="https://github.com/TBA-API/tba-api-client-python">tbaapiv3client</a> python library’s <code class="highlighter-rouge">get_teams_keys(key)</code> function, and kept incrementing <code class="highlighter-rouge">key</code> until I got an empty array. All returned data was then added together into a big list of team keys.</p> - -<h3 id="checking-for-a-teams-github-account">Checking for a team’s github account</h3> -<p>The <a href="https://www.thebluealliance.com/apidocs/v3">TBA API</a> helpfully provides a <code class="highlighter-rouge">/api/v3/team/&lt;number&gt;/social_media</code> API endpoint that will give the GitHub username for any team you request. (or nothing if they don’t use github)</p> - -<p>A <code class="highlighter-rouge">for</code> loop on this with a list of every team number did the trick for finding accounts.</p> - -<h3 id="fetching-language-info">Fetching language info</h3> -<p>To remove the need for an Oauth login to use the script, GitHub data is retrieved using standard HTTPS requests instead of AJAX requests to the API. This gets around the tiny rate limit, but takes a bit longer to complete.</p> - -<p>To check for language usage, a simple Regex pattern can be used: <code class="highlighter-rouge">/programmingLanguage"\&gt;(.*)\&lt;/gm</code></p> - -<p>When combined with an <code class="highlighter-rouge">re.findall()</code>, this pattern will return a list of all recent languages used by a team.</p> - -<h3 id="data-saves--backup-solution">Data saves / backup solution</h3> -<p>To deal with the fact that large amounts of data are being requested, and people might want to pause the script, I have created a system to allow for “savestates”.</p> - -<p>On launch of the script, it will check for a <code class="highlighter-rouge">./data.json</code> file. If this does not exist, one will be created. Otherwise, the contents will be read. This file contains both all the saved data, and some counters.</p> - -<p>Each stage of the script contains a counter, and will increment the counter every time a team has been processed. This way, if the script is stopped and restarted, the parsers will just keep working from where they left off. This was very helpful when writing the script as, I needed to stop and start it every time I needed to implement a new feature.</p> - -<p>All parsing data is saved to the json file every time the script completes, or it detects a <code class="highlighter-rouge">SIGKILL</code>.</p> - -<h2 id="what-i-learned">What I learned</h2> -<p>After letting the script run for about an hour, I got a bunch of data from every registered team.</p> - -<p>This data includes every project (both on and offseason) from each team, so teams that build t-shirt cannons using the CTRE HERO, would have C# in their list of languages. Things like that.</p> - -<p>Unsurprisingly, by far the most popular programming language is Java, with 3232 projects. These projects where all mostly, or entirely written in Java. Next up, we have C++ with 725 projects, and Python with 468 projects.</p> - -<p>After Java, C++, and Python, we start running in to languages used for dashboards, design, lessons, and offseason projects. Before I get to everything else, here is the usage of the rest of the valid languages for FRC robots:</p> -<ul> - <li>C (128)</li> - <li>LabView (153)</li> - <li>Kotlin (96)</li> - <li>Rust (4)</li> -</ul> - -<p>Now, the rest of the languages below Python:</p> -<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>295 occurrences of JavaScript -153 occurrences of LabVIEW -128 occurrences of C -96 occurrences of Kotlin -72 occurrences of Arduino -71 occurrences of C# -69 occurrences of CSS -54 occurrences of PHP -40 occurrences of Shell -34 occurrences of Ruby -16 occurrences of Swift -16 occurrences of Jupyter Notebook -15 occurrences of Scala -12 occurrences of D -12 occurrences of TypeScript -9 occurrences of Dart -8 occurrences of Processing -7 occurrences of CoffeeScript -6 occurrences of Go -6 occurrences of Groovy -6 occurrences of Objective-C -4 occurrences of Rust -3 occurrences of MATLAB -3 occurrences of R -1 occurrences of Visual Basic -1 occurrences of Clojure -1 occurrences of Cuda -</code></pre></div></div> - -<p>I have removed markup and shell languages from that list because most of them are probably auto-generated.</p> - -<p>In terms of github account names, 133 teams follow FRC convention and use a username starting with <code class="highlighter-rouge">frc</code>, followed by their team number, 95 teams use <code class="highlighter-rouge">team</code> then their number, and 264 teams use something else.</p> - -<h2 id="using-the-script">Using the script</h2> -<p>This script is not on PYPI this time. You can obtain a copy from my GitHub repo: <a href="https://github.com/Ewpratten/frc-code-stats">https://github.com/Ewpratten/frc-code-stats</a></p> - -<p>First, make sure both <code class="highlighter-rouge">python3.7</code> and <code class="highlighter-rouge">python3-pip</code> are installed on your computer. Next, delete the <code class="highlighter-rouge">data.json</code> file. Then, install the requirements with <code class="highlighter-rouge">pip3 install -r requirements.txt</code>. Finally, run with <code class="highlighter-rouge">python3 main.py</code> to start the script. Now, go outside and enjoy nature for about an hour, and your data should be loaded!.</p>I was curious about the most used languages for FRC, so I build a Python script to find out what they where. \ No newline at end of file +<p>I just really enjoyed working with the project and sharing it with friends, so I figured I should mention it here too. Maybe it will inspire someone to make something cool!</p>One day, back in June of 2018, I was both looking for a new project to work on, and trying to decide which Linux distro to install on one of my computers. From this, a little project was born. Give Me a Distro (or, GMAD, as I like to call it) is a little website that chooses a random distribution of Linux and shows a description of what you are about to get yourself into, and a download link for the latest ISO. \ No newline at end of file diff --git a/_site/fossl-feeds.html b/_site/fossl-feeds.html index d327ff9..3c8ff75 100644 --- a/_site/fossl-feeds.html +++ b/_site/fossl-feeds.html @@ -14,7 +14,7 @@ +{"@type":"WebPage","url":"http://0.0.0.0:4000/fossl-feeds","description":"RSS feeds from our blogs","headline":"FOSS/L RSS Feeds","@context":"https://schema.org"} @@ -103,7 +103,7 @@ https://blog.mrtnrdl.de/feed.xml Site design by: Evan Pratten | - This site was last updated at: 2019-11-17 10:22:12 -0500 + This site was last updated at: 2019-11-20 10:04:40 -0500 diff --git a/_site/index.html b/_site/index.html index ece52d1..6cc2ede 100644 --- a/_site/index.html +++ b/_site/index.html @@ -14,7 +14,7 @@ +{"@type":"WebSite","url":"http://0.0.0.0:4000/","name":"Evan Pratten","description":"Computer wizard, student, @frc5024 programming team lead, and radio enthusiast.","headline":"Evan Pratten","@context":"https://schema.org"} @@ -116,7 +116,7 @@ Site design by: Evan Pratten | - This site was last updated at: 2019-11-17 10:22:12 -0500 + This site was last updated at: 2019-11-20 10:04:40 -0500 diff --git a/_site/projects.html b/_site/projects.html index bce394c..d11490f 100644 --- a/_site/projects.html +++ b/_site/projects.html @@ -14,7 +14,7 @@ +{"@type":"WebPage","url":"http://0.0.0.0:4000/projects","description":"Computer wizard, student, @frc5024 programming team lead, and radio enthusiast.","headline":"My Projects","@context":"https://schema.org"} @@ -273,7 +273,7 @@ Site design by: Evan Pratten | - This site was last updated at: 2019-11-17 10:22:12 -0500 + This site was last updated at: 2019-11-20 10:04:40 -0500 diff --git a/_site/redirects.json b/_site/redirects.json index ccf7886..b5ac375 100644 --- a/_site/redirects.json +++ b/_site/redirects.json @@ -1 +1 @@ -{"/post/ef7b3166/":"http://0.0.0.0:4000/blog/2019/09/11/buildingimgfrombin","/ef7b3166/":"http://0.0.0.0:4000/blog/2019/09/11/buildingimgfrombin","/post/e9gb3490/":"http://0.0.0.0:4000/blog/2019/09/19/i-want-to-build-a-sat","/e9gb3490/":"http://0.0.0.0:4000/blog/2019/09/19/i-want-to-build-a-sat","/post/e9g9d6s90/":"http://0.0.0.0:4000/blog/2019/09/28/offseason1","/e9g9d6s90/":"http://0.0.0.0:4000/blog/2019/09/28/offseason1","/post/99g9j2r90/":"http://0.0.0.0:4000/blog/2019/10/05/billwurtz","/99g9j2r90/":"http://0.0.0.0:4000/blog/2019/10/05/billwurtz","/post/e9g9dfs90/":"http://0.0.0.0:4000/blog/2019/11/09/easyshell","/e9g9dfs90/":"http://0.0.0.0:4000/blog/2019/11/09/easyshell","/r/5kcomm":"https://imgur.com/a/77bnlZN","/r/locngn":"https://github.com/frc5024/uBase/blob/lib-upgrade/src/main/java/frc/lib5k/spatial/LocalizationEngine.java","/music":"https://retrylife.bandcamp.com/"} \ No newline at end of file +{"/post/ef7b3166/":"http://0.0.0.0:4000/blog/2019/09/11/buildingimgfrombin","/ef7b3166/":"http://0.0.0.0:4000/blog/2019/09/11/buildingimgfrombin","/post/e9gb3490/":"http://0.0.0.0:4000/blog/2019/09/19/i-want-to-build-a-sat","/e9gb3490/":"http://0.0.0.0:4000/blog/2019/09/19/i-want-to-build-a-sat","/post/e9g9d6s90/":"http://0.0.0.0:4000/blog/2019/09/28/offseason1","/e9g9d6s90/":"http://0.0.0.0:4000/blog/2019/09/28/offseason1","/post/99g9j2r90/":"http://0.0.0.0:4000/blog/2019/10/05/billwurtz","/99g9j2r90/":"http://0.0.0.0:4000/blog/2019/10/05/billwurtz","/post/e9g9dfs90/":"http://0.0.0.0:4000/blog/2019/11/09/easyshell","/e9g9dfs90/":"http://0.0.0.0:4000/blog/2019/11/09/easyshell","/post/e9gdhj90/":"http://0.0.0.0:4000/blog/2019/11/20/realtime-robot-code","/e9gdhj90/":"http://0.0.0.0:4000/blog/2019/11/20/realtime-robot-code","/r/5kcomm":"https://imgur.com/a/77bnlZN","/r/locngn":"https://github.com/frc5024/uBase/blob/lib-upgrade/src/main/java/frc/lib5k/spatial/LocalizationEngine.java","/music":"https://retrylife.bandcamp.com/"} \ No newline at end of file diff --git a/assets/css/main.css b/assets/css/main.css index c5b8279..c8a4d8f 100644 --- a/assets/css/main.css +++ b/assets/css/main.css @@ -1,25 +1,18 @@ -body{ - margin:0; - padding:0; - - +body { + margin: 0; + padding: 0; font-family: 'IBM Plex Mono', monospace; - font-family: 'IBM Plex Sans', sans-serif; - - } -.foot{ - -} +.foot {} -.site-info{ - color:rgb(199, 195, 195); +.site-info { + color: rgb(199, 195, 195); background-color: #FFF; } -.header-gap{ +.header-gap { /* height: 30px; background-color: #ebeef1; */ } @@ -31,8 +24,6 @@ body{ background-repeat: no-repeat; background-size: cover; background-position: center; - - } .table-fix { @@ -44,11 +35,9 @@ table { margin-bottom: 1rem; color: #212529; vertical-align: top; - } -table th, -table td { +table th, table td { padding: 0.5rem; border-bottom: 1px solid #dee2e6; } @@ -74,23 +63,23 @@ thead th { .header .container { height: 100%; display: flex; - align-items: center; /* align vertical */ + align-items: center; + /* align vertical */ } .hidden { display: none !important; } - img { - max-width:100%; + max-width: 100%; } -.centre{ +.centre { text-align: center; } -h1, h2, h3, h4, h5, h6{ +h1, h2, h3, h4, h5, h6 { font-family: 'IBM Plex Mono', monospace; } @@ -105,7 +94,6 @@ a h5 { /* border-radius: 15px; transform: translateY(-30px); */ background-color: #fff; - } .home.container { @@ -115,8 +103,8 @@ a h5 { background-color: #fff; } -.container .profile{ - width:30vw; +.container .profile { + width: 30vw; max-width: 242px; transform: translateY(calc(10vh * -1)); border-color: #fff; @@ -130,25 +118,25 @@ a h5 { border-radius: 5%; } -.home-header{ - height:100%; +.home-header { + height: 100%; background-image: url('/assets/images/banner.jpg'); background-repeat: no-repeat; background-size: cover; background-position: center; } -.site-ctr{ - min-height:100vh; +.site-ctr { + min-height: 100vh; } .tagline { text-align: center; max-width: 600px; - margin:auto; + margin: auto; } -.container .info{ +.container .info { transform: translateY(calc(13vh * -1)); padding: 20px; } @@ -161,6 +149,7 @@ a h5 { /* #particles-js{ position: absolute; } */ + /* .reactive-bg{ position:relative @@ -192,6 +181,7 @@ blockquote { padding: 0.5em 10px; /* quotes: "\201C""\201D""\2018""\2019"; */ } + blockquote:before { color: #ccc; /* content: open-quote; */ @@ -200,6 +190,35 @@ blockquote:before { margin-right: 0.25em; vertical-align: -0.4em; } + blockquote p { display: inline; +} + +kbd { + margin: 0px 0.1em; + padding: 0.1em 0.6em; + border-radius: 3px; + border: 1px solid rgb(204, 204, 204); + color: rgb(51, 51, 51); + line-height: 1.4; + font-size: 10px; + display: inline-block; + box-shadow: 0px 1px 0px rgba(0,0,0,0.2), inset 0px 0px 0px 2px #ffffff; + background-color: rgb(247, 247, 247); + -moz-box-shadow: 0 1px 0px rgba(0, 0, 0, 0.2), 0 0 0 2px #ffffff inset; + -webkit-box-shadow: 0 1px 0px rgba(0, 0, 0, 0.2), 0 0 0 2px #ffffff inset; + -moz-border-radius: 3px; + -webkit-border-radius: 3px; + text-shadow: 0 1px 0 #fff; +} + +.highlight { + background-color: #faf9f9; + border-radius:5px; +} + +pre { + padding:3px; +} } \ No newline at end of file diff --git a/assets/python/__pycache__/rtrbt.cpython-36.pyc b/assets/python/__pycache__/rtrbt.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..00aa1b4d453d6195cc3e5d20b5320a8fdb372042 GIT binary patch literal 1546 zcmZ8h&5q+l5bhr*asGzvfR<&27E2&RF3ACL03kGDSkN4ZU@~YHODoH9_ax3bwyEyy zD5H!(%3cvS-hoHpIk@@CX#x4@r~Q8Cw1JlrkLUx3+s`Gd^5lmk%^TIC1>X>4?L#57ajPTGkTr3QG0)8xp-E8*$kWL zky&fyhdyU>7PhtjYv((rJk@x`R7106cPGQ1YO2;N7WS2|+BhDlj_Tt0mg=cKjswM~ zYbfyNOw^A2{Jg

vD6Rwsl1gGAukxeQv(sW$ z*o5OIdT5l`j?~VyE0$969lrd2E^g;azQ>lH@@lW*_cO)tl*Z(Sg5D4wAnV&< zqv}OTky|LTOoOSKaarnIRbFC2hrRP3PNK6oEAr{-vv6RvoyHg1Zl31xEYk|F>lvM0 z{KcS)(f&IgFN&2O>&p^iYjr*@p;+p~nlWe#n=HN1qj_o<>)9wR#<9V8W?XLUqR7W! zVP;3=rfLJRaFVC?5ymt=c1#ZVKpya`!&{O@cbg`TyC{!WI*O`J6s-!i&dBaX(J$*b zt3A-iFb?HjM-l_n9eaq)5G%fL^SkU3No{N{2VbCpS>tnY{hE6vwrnT=c#OG_n3h*(k@S##IjJP9^U8~1{&MI8omVxB88K8zvoRQYj!hJPa!si3t;Xw4=T?FlWG0}A`vv`%?c`Qg$JE|B#Ag>+< zQ;HYZg$^9cK~g9kkhF1qt}QYS5+k?+s#av3;H!p%v4@T%0Yq`taW1Fs5zY-!&Ll#7 zAIF4vpod0kj%(t;vMoae^Q}|6D>!lWb}-d8h=WyO3kXc9wF)Lf0WJIhS=4qYDv>IL zL#{nI4vCK&zNarg!|g8POhAD49SXumw{s{yL1W9d{9Sg9ncnh8>{?pXz*g)8)gR_x zl2zC6)yKhcT}pf8U83HD7?Kz{O!IPWP2fro8W + +# Import norma robot stuff +import wpilib +import ctre + +# Handle WPI trickery +try: + from unittest.mock import patch +except ImportError: + from mock import patch +import sys +from threading import Thread + + +## Internal mathods ## +_controllers = [] +_thread: Thread + + +class _RTRobot(wpilib.TimedRobot): + + def robotInit(self): + + # Create motors + _controllers.append(ctre.WPI_TalonSRX(1)) + _controllers.append(ctre.WPI_TalonSRX(2)) + + # Set safe modes + _controllers[0].setSafetyEnabled(False) + _controllers[1].setSafetyEnabled(False) + + + +def _start(): + # Handle fake args + args = ["run", "run"] + with patch.object(sys, "argv", args): + print(sys.argv) + wpilib.run(_RTRobot) + +## Utils ## + + +def startRobot(): + """ Start the robot code """ + global _thread + _thread = Thread(target=_start) + _thread.start() + + +def setMotor(id, speed): + """ Set a motor speed """ + _controllers[id].set(speed) + +def arcadeDrive(speed, rotation): + """ Control the robot with arcade inputs """ + + l = speed + rotation + r = speed - rotation + + setMotor(0, l) + setMotor(1, r) \ No newline at end of file