1

Added RT robot post

This commit is contained in:
Evan Pratten 2019-11-20 10:04:59 -05:00
parent fae2cb7f9f
commit a407af087d
No known key found for this signature in database
GPG Key ID: 93AC7B3D071356D3
34 changed files with 602 additions and 230 deletions

View File

@ -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-<team>-frc.local
```
If you have issues, try one of the following addresses instead:
```
roborio-<team>-FRC
roborio-<team>-FRC.lan
roborio-<team>-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 <kbd>Enter</kbd> 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 <ewpratten>
# 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 <kbd>Enter</kbd> 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 <kbd>CTRL</kbd> + <kbd>D</kbd> then <kbd>CTRL</kbd> + <kbd>C</kbd>.
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: <module 'threading' from '/usr/lib/python3.6/threading.py'>
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.

View File

@ -14,7 +14,7 @@
<meta property="og:url" content="http://0.0.0.0:4000/about/" />
<meta property="og:site_name" content="Evan Pratten" />
<script type="application/ld+json">
{"headline":"Evan Pratten","@type":"WebSite","url":"http://0.0.0.0:4000/about/","name":"Evan Pratten","description":"Computer wizard, student, @frc5024 programming team lead, and radio enthusiast.","@context":"https://schema.org"}</script>
{"@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"}</script>
<!-- End Jekyll SEO tag -->
@ -219,7 +219,7 @@ sub rsa4096/0xA61A2F1676E35144 2019-08-11 [] [expires: 2025-08-09]
<span class="site-info">
Site design by: <a href="https://retrylife.ca">Evan Pratten</a> |
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
</span>
</div>

View File

@ -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;
}
}

View File

@ -16,7 +16,7 @@
<meta property="og:type" content="article" />
<meta property="article:published_time" content="2018-06-27T14:32:00-04:00" />
<script type="application/ld+json">
{"headline":"Using a python script to create devRant posts based on the style and content of another user","dateModified":"2018-06-27T14:32:00-04:00","datePublished":"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 ++","@context":"https://schema.org"}</script>
{"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"}</script>
<!-- End Jekyll SEO tag -->
@ -140,7 +140,7 @@ pip3 install tensorflow-gpu #for gpu processing
<span class="site-info">
Site design by: <a href="https://retrylife.ca">Evan Pratten</a> |
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
</span>
</div>

View File

@ -16,7 +16,7 @@
<meta property="og:type" content="article" />
<meta property="article:published_time" content="2019-04-30T14:32:00-04:00" />
<script type="application/ld+json">
{"headline":"The language hunt","dateModified":"2019-04-30T14:32:00-04:00","datePublished":"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.","@context":"https://schema.org"}</script>
{"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"}</script>
<!-- End Jekyll SEO tag -->
@ -104,7 +104,7 @@
<span class="site-info">
Site design by: <a href="https://retrylife.ca">Evan Pratten</a> |
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
</span>
</div>

View File

@ -16,7 +16,7 @@
<meta property="og:type" content="article" />
<meta property="article:published_time" content="2019-05-27T05:22:00-04:00" />
<script type="application/ld+json">
{"headline":"Building a safe and easy system for sending computer vision data from a raspberry pi to a roborio","dateModified":"2019-05-27T05:22:00-04:00","datePublished":"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","@context":"https://schema.org"}</script>
{"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"}</script>
<!-- End Jekyll SEO tag -->
@ -117,7 +117,7 @@
<span class="site-info">
Site design by: <a href="https://retrylife.ca">Evan Pratten</a> |
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
</span>
</div>

View File

@ -16,7 +16,7 @@
<meta property="og:type" content="article" />
<meta property="article:published_time" content="2019-06-12T09:09:00-04:00" />
<script type="application/ld+json">
{"headline":"GitHubs CSS is boring. So I refreshed the design","dateModified":"2019-06-12T09:09:00-04:00","datePublished":"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 GitHubs theme. I didnt 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.","@context":"https://schema.org"}</script>
{"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 GitHubs theme. I didnt 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":"GitHubs CSS is boring. So I refreshed the design","@context":"https://schema.org"}</script>
<!-- End Jekyll SEO tag -->
@ -128,7 +128,7 @@
<span class="site-info">
Site design by: <a href="https://retrylife.ca">Evan Pratten</a> |
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
</span>
</div>

View File

@ -16,7 +16,7 @@
<meta property="og:type" content="article" />
<meta property="article:published_time" content="2019-06-16T11:51:00-04:00" />
<script type="application/ld+json">
{"headline":"Graphing the relation between wheels and awards for FRC","dateModified":"2019-06-16T11:51:00-04:00","datePublished":"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.","@context":"https://schema.org"}</script>
{"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"}</script>
<!-- End Jekyll SEO tag -->
@ -142,7 +142,7 @@
<span class="site-info">
Site design by: <a href="https://retrylife.ca">Evan Pratten</a> |
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
</span>
</div>

View File

@ -16,7 +16,7 @@
<meta property="og:type" content="article" />
<meta property="article:published_time" content="2019-06-17T06:20:00-04:00" />
<script type="application/ld+json">
{"headline":"I made a new song!","dateModified":"2019-06-17T06:20:00-04:00","datePublished":"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","@context":"https://schema.org"}</script>
{"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"}</script>
<!-- End Jekyll SEO tag -->
@ -101,7 +101,7 @@ Your browser does not support audio players
<span class="site-info">
Site design by: <a href="https://retrylife.ca">Evan Pratten</a> |
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
</span>
</div>

View File

@ -16,7 +16,7 @@
<meta property="og:type" content="article" />
<meta property="article:published_time" content="2019-06-21T11:14:00-04:00" />
<script type="application/ld+json">
{"headline":"What I have learned from 2 years of FRC programming","dateModified":"2019-06-21T11:14:00-04:00","datePublished":"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","@context":"https://schema.org"}</script>
{"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"}</script>
<!-- End Jekyll SEO tag -->
@ -141,7 +141,7 @@
<span class="site-info">
Site design by: <a href="https://retrylife.ca">Evan Pratten</a> |
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
</span>
</div>

View File

@ -16,7 +16,7 @@
<meta property="og:type" content="article" />
<meta property="article:published_time" content="2019-06-23T18:04:00-04:00" />
<script type="application/ld+json">
{"headline":"I gave Googles CTF a short try and learned a thing or two","dateModified":"2019-06-23T18:04:00-04:00","datePublished":"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","@context":"https://schema.org"}</script>
{"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 Googles CTF a short try and learned a thing or two","@context":"https://schema.org"}</script>
<!-- End Jekyll SEO tag -->
@ -99,7 +99,7 @@
<span class="site-info">
Site design by: <a href="https://retrylife.ca">Evan Pratten</a> |
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
</span>
</div>

View File

@ -16,7 +16,7 @@
<meta property="og:type" content="article" />
<meta property="article:published_time" content="2019-06-24T17:36:00-04:00" />
<script type="application/ld+json">
{"headline":"The language hunt: Part 2","dateModified":"2019-06-24T17:36:00-04:00","datePublished":"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","@context":"https://schema.org"}</script>
{"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"}</script>
<!-- End Jekyll SEO tag -->
@ -99,7 +99,7 @@
<span class="site-info">
Site design by: <a href="https://retrylife.ca">Evan Pratten</a> |
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
</span>
</div>

View File

@ -16,7 +16,7 @@
<meta property="og:type" content="article" />
<meta property="article:published_time" content="2019-06-26T11:48:00-04:00" />
<script type="application/ld+json">
{"headline":"BashSmash","dateModified":"2019-06-26T11:48:00-04:00","datePublished":"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","@context":"https://schema.org"}</script>
{"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"}</script>
<!-- End Jekyll SEO tag -->
@ -208,7 +208,7 @@ __<span class="o">()</span> <span class="o">{</span>/???/???/???n?f <span class=
<span class="site-info">
Site design by: <a href="https://retrylife.ca">Evan Pratten</a> |
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
</span>
</div>

View File

@ -16,7 +16,7 @@
<meta property="og:type" content="article" />
<meta property="article:published_time" content="2019-06-27T13:16:00-04:00" />
<script type="application/ld+json">
{"headline":"I had some fun with a router","dateModified":"2019-06-27T13:16:00-04:00","datePublished":"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","@context":"https://schema.org"}</script>
{"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"}</script>
<!-- End Jekyll SEO tag -->
@ -129,7 +129,7 @@
<span class="site-info">
Site design by: <a href="https://retrylife.ca">Evan Pratten</a> |
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
</span>
</div>

View File

@ -16,7 +16,7 @@
<meta property="og:type" content="article" />
<meta property="article:published_time" content="2019-06-27T03:00:00-04:00" />
<script type="application/ld+json">
{"headline":"Hunting snakes with a shotgun","dateModified":"2019-06-27T03:00:00-04:00","datePublished":"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","@context":"https://schema.org"}</script>
{"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"}</script>
<!-- End Jekyll SEO tag -->
@ -194,7 +194,7 @@
<span class="site-info">
Site design by: <a href="https://retrylife.ca">Evan Pratten</a> |
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
</span>
</div>

View File

@ -16,7 +16,7 @@
<meta property="og:type" content="article" />
<meta property="article:published_time" content="2019-07-01T18:13:00-04:00" />
<script type="application/ld+json">
{"headline":"devDNS","dateModified":"2019-07-01T18:13:00-04:00","datePublished":"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","@context":"https://schema.org"}</script>
{"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"}</script>
<!-- End Jekyll SEO tag -->
@ -118,7 +118,7 @@
<span class="site-info">
Site design by: <a href="https://retrylife.ca">Evan Pratten</a> |
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
</span>
</div>

View File

@ -16,7 +16,7 @@
<meta property="og:type" content="article" />
<meta property="article:published_time" content="2019-07-06T11:08:00-04:00" />
<script type="application/ld+json">
{"headline":"Scraping FRC teams GitHub accounts to gather large amounts of data","dateModified":"2019-07-06T11:08:00-04:00","datePublished":"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…","@context":"https://schema.org"}</script>
{"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 teams GitHub accounts to gather large amounts of data","@context":"https://schema.org"}</script>
<!-- End Jekyll SEO tag -->
@ -191,7 +191,7 @@
<span class="site-info">
Site design by: <a href="https://retrylife.ca">Evan Pratten</a> |
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
</span>
</div>

View File

@ -16,7 +16,7 @@
<meta property="og:type" content="article" />
<meta property="article:published_time" content="2019-07-13T10:43:00-04:00" />
<script type="application/ld+json">
{"headline":"Taking a look back at GMAD","dateModified":"2019-07-13T10:43:00-04:00","datePublished":"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","@context":"https://schema.org"}</script>
{"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"}</script>
<!-- End Jekyll SEO tag -->
@ -112,7 +112,7 @@
<span class="site-info">
Site design by: <a href="https://retrylife.ca">Evan Pratten</a> |
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
</span>
</div>

View File

@ -16,7 +16,7 @@
<meta property="og:type" content="article" />
<meta property="article:published_time" content="2019-07-15T14:38:00-04:00" />
<script type="application/ld+json">
{"headline":"Mind map generation with Python","dateModified":"2019-07-15T14:38:00-04:00","datePublished":"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","@context":"https://schema.org"}</script>
{"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"}</script>
<!-- End Jekyll SEO tag -->
@ -206,7 +206,7 @@
<span class="site-info">
Site design by: <a href="https://retrylife.ca">Evan Pratten</a> |
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
</span>
</div>

View File

@ -16,7 +16,7 @@
<meta property="og:type" content="article" />
<meta property="article:published_time" content="2019-08-10T16:57:00-04:00" />
<script type="application/ld+json">
{"headline":"My weird piece of EDC","dateModified":"2019-08-10T16:57:00-04:00","datePublished":"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","@context":"https://schema.org"}</script>
{"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"}</script>
<!-- End Jekyll SEO tag -->
@ -124,7 +124,7 @@
<span class="site-info">
Site design by: <a href="https://retrylife.ca">Evan Pratten</a> |
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
</span>
</div>

View File

@ -16,7 +16,7 @@
<meta property="og:type" content="article" />
<meta property="article:published_time" content="2019-08-12T15:40:00-04:00" />
<script type="application/ld+json">
{"headline":"How I set up ひらがな input on my laptop","dateModified":"2019-08-12T15:40:00-04:00","datePublished":"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","@context":"https://schema.org"}</script>
{"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"}</script>
<!-- End Jekyll SEO tag -->
@ -169,7 +169,7 @@ ibus-daemon <span class="nt">-drx</span>
<span class="site-info">
Site design by: <a href="https://retrylife.ca">Evan Pratten</a> |
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
</span>
</div>

View File

@ -16,7 +16,7 @@
<meta property="og:type" content="article" />
<meta property="article:published_time" content="2019-08-24T09:13:00-04:00" />
<script type="application/ld+json">
{"headline":"Keyed data encoding with Python","dateModified":"2019-08-24T09:13:00-04:00","datePublished":"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","@context":"https://schema.org"}</script>
{"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"}</script>
<!-- End Jekyll SEO tag -->
@ -154,7 +154,7 @@ shift2 <span class="nt">-h</span>
<span class="site-info">
Site design by: <a href="https://retrylife.ca">Evan Pratten</a> |
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
</span>
</div>

View File

@ -16,7 +16,7 @@
<meta property="og:type" content="article" />
<meta property="article:published_time" content="2019-08-27T08:37:00-04:00" />
<script type="application/ld+json">
{"headline":"I did some cleaning","dateModified":"2019-08-27T08:37:00-04:00","datePublished":"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 isnt spring, and a computer does all the work","@context":"https://schema.org"}</script>
{"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 isnt spring, and a computer does all the work","headline":"I did some cleaning","@context":"https://schema.org"}</script>
<!-- End Jekyll SEO tag -->
@ -125,7 +125,7 @@ Starting from the top, scroll through, and middle click on anything you want to
<span class="site-info">
Site design by: <a href="https://retrylife.ca">Evan Pratten</a> |
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
</span>
</div>

View File

@ -16,7 +16,7 @@
<meta property="og:type" content="article" />
<meta property="article:published_time" content="2019-09-07T09:13:00-04:00" />
<script type="application/ld+json">
{"headline":"Doing Python OOP the wrong way","dateModified":"2019-09-07T09:13:00-04:00","datePublished":"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!","@context":"https://schema.org"}</script>
{"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"}</script>
<!-- End Jekyll SEO tag -->
@ -174,7 +174,7 @@ fn printMyNumber(MyClass* self){
<span class="site-info">
Site design by: <a href="https://retrylife.ca">Evan Pratten</a> |
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
</span>
</div>

View File

@ -14,7 +14,7 @@
<meta property="og:url" content="http://0.0.0.0:4000/blog/" />
<meta property="og:site_name" content="Evan Pratten" />
<script type="application/ld+json">
{"headline":"Evan Pratten","@type":"WebPage","url":"http://0.0.0.0:4000/blog/","description":"Computer wizard, student, @frc5024 programming team lead, and radio enthusiast.","@context":"https://schema.org"}</script>
{"@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"}</script>
<!-- End Jekyll SEO tag -->
@ -79,22 +79,22 @@
Featured Post
</div>
<div class="card-body">
<h5 class="card-title">Turning a web IDE into a disposable linux environment
<h5 class="card-title">Programming a live robot
</h5>
<p class="card-text">My Python code keeps popping shells</p>
<a href="/blog/2019/11/09/easyshell" class="btn btn-primary">View</a>
<p class="card-text">Living on the edge is an understatement</p>
<a href="/blog/2019/11/20/realtime-robot-code" class="btn btn-primary">View</a>
</div>
</div>
</div> -->
<a href="/blog/2019/11/09/easyshell" class="list-group-item list-group-item-action">
<a href="/blog/2019/11/20/realtime-robot-code" class="list-group-item list-group-item-action">
<div class="d-flex w-100 justify-content-between">
<div class="card-body">
<h5 class="mb-1">Turning a web IDE into a disposable linux environment
<h5 class="mb-1">Programming a live robot
</h5>
<p class="card-text">My Python code keeps popping shells</p>
<p class="card-text">Living on the edge is an understatement</p>
</div>
</div>
</a>
@ -107,6 +107,21 @@
<a href="/blog/2019/11/09/easyshell" class="list-group-item list-group-item-action">
<div class="d-flex w-100 justify-content-between">
<h5 class="mb-1">Turning a web IDE into a disposable linux environment</h5>
<!-- <small>2019-11-09 19:00:00 -0500</small> -->
</div>
<p class="card-text">My Python code keeps popping shells</p>
</a>
<a href="/blog/2019/10/05/billwurtz" class="list-group-item list-group-item-action">
<div class="d-flex w-100 justify-content-between">
<h5 class="mb-1">Using an RNN to generate Bill Wurtz notes</h5>
@ -550,7 +565,7 @@
<span class="site-info">
Site design by: <a href="https://retrylife.ca">Evan Pratten</a> |
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
</span>
</div>

View File

@ -14,7 +14,7 @@
<meta property="og:url" content="http://0.0.0.0:4000/documentation" />
<meta property="og:site_name" content="Evan Pratten" />
<script type="application/ld+json">
{"headline":"Evan Pratten","@type":"WebPage","url":"http://0.0.0.0:4000/documentation","description":"Computer wizard, student, @frc5024 programming team lead, and radio enthusiast.","@context":"https://schema.org"}</script>
{"@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"}</script>
<!-- End Jekyll SEO tag -->
@ -67,7 +67,7 @@
<span class="site-info">
Site design by: <a href="https://retrylife.ca">Evan Pratten</a> |
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
</span>
</div>

View File

@ -1,4 +1,175 @@
<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="3.8.6">Jekyll</generator><link href="http://0.0.0.0:4000/feed.xml" rel="self" type="application/atom+xml" /><link href="http://0.0.0.0:4000/" rel="alternate" type="text/html" /><updated>2019-11-17T10:22:12-05:00</updated><id>http://0.0.0.0:4000/feed.xml</id><title type="html">Evan Pratten</title><subtitle>Computer wizard, student, &lt;a href=&quot;https://frc5024.github.io&quot;&gt;@frc5024&lt;/a&gt; programming team lead, and radio enthusiast.</subtitle><entry><title type="html">Using an RNN to generate Bill Wurtz notes</title><link href="http://0.0.0.0:4000/blog/2019/10/05/billwurtz" rel="alternate" type="text/html" title="Using an RNN to generate Bill Wurtz notes" /><published>2019-10-05T14:54:00-04:00</published><updated>2019-10-05T14:54:00-04:00</updated><id>http://0.0.0.0:4000/blog/2019/10/05/BillWurtz</id><content type="html" xml:base="http://0.0.0.0:4000/blog/2019/10/05/billwurtz">&lt;p&gt;&lt;a href=&quot;https://billwurtz.com/&quot;&gt;Bill Wurtz&lt;/a&gt; is an American musician who became &lt;a href=&quot;https://socialblade.com/youtube/user/billwurtz/realtime&quot;&gt;reasonably famous&lt;/a&gt; through short musical videos posted to Vine and YouTube. I was searching through his website the other day, and stumbled upon a page labeled &lt;a href=&quot;https://billwurtz.com/notebook.html&quot;&gt;&lt;em&gt;notebook&lt;/em&gt;&lt;/a&gt;, and thought I should check it out.&lt;/p&gt;
<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="3.8.6">Jekyll</generator><link href="http://0.0.0.0:4000/feed.xml" rel="self" type="application/atom+xml" /><link href="http://0.0.0.0:4000/" rel="alternate" type="text/html" /><updated>2019-11-20T10:04:40-05:00</updated><id>http://0.0.0.0:4000/feed.xml</id><title type="html">Evan Pratten</title><subtitle>Computer wizard, student, &lt;a href=&quot;https://frc5024.github.io&quot;&gt;@frc5024&lt;/a&gt; programming team lead, and radio enthusiast.</subtitle><entry><title type="html">Programming a live robot</title><link href="http://0.0.0.0:4000/blog/2019/11/20/realtime-robot-code" rel="alternate" type="text/html" title="Programming a live robot" /><published>2019-11-20T05:04:00-05:00</published><updated>2019-11-20T05:04:00-05:00</updated><id>http://0.0.0.0:4000/blog/2019/11/20/Realtime-robot-code</id><content type="html" xml:base="http://0.0.0.0:4000/blog/2019/11/20/realtime-robot-code">&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;“So.. what if we could skip asking for driver inputs, and just have the robot operators control the bot through a commandline interface?”&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;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!&lt;/p&gt;
&lt;h2 id=&quot;geting-started&quot;&gt;Geting started&lt;/h2&gt;
&lt;p&gt;To get started, I needed a few things. Firstly, I have a laptop running &lt;a href=&quot;/about/#my-gear&quot;&gt;a Linux distribution&lt;/a&gt;. This allows me to use &lt;a href=&quot;https://en.wikipedia.org/wiki/Secure_Shell&quot;&gt;SSH&lt;/a&gt; and &lt;a href=&quot;https://en.wikipedia.org/wiki/Secure_copy&quot;&gt;SCP&lt;/a&gt;. There are Windows versions of both of these programs, but I find the “linux experience” easier to use. Secondly, I have grabbed one of &lt;a href=&quot;https://www.thebluealliance.com/team/5024&quot;&gt;5024&lt;/a&gt;s &lt;a href=&quot;https://cs.5024.ca/webdocs/docs/robots&quot;&gt;robots&lt;/a&gt; to be subjected to my experiment. The components I care about are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A RoboRIO running 2019v12 firmware&lt;/li&gt;
&lt;li&gt;2 &lt;a href=&quot;https://www.ctr-electronics.com/talon-srx.html&quot;&gt;TalonSRX&lt;/a&gt; motor controllers&lt;/li&gt;
&lt;li&gt;An FRC router&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Most importantly, the RoboRIO has &lt;a href=&quot;https://robotpy.readthedocs.io/en/stable/install/robot.html#install-robotpy&quot;&gt;RobotPy&lt;/a&gt; and the &lt;a href=&quot;https://robotpy.readthedocs.io/en/stable/install/ctre.html&quot;&gt;CTRE Libraries&lt;/a&gt; installed.&lt;/p&gt;
&lt;h3 id=&quot;ssh-connection&quot;&gt;SSH connection&lt;/h3&gt;
&lt;p&gt;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 &lt;a href=&quot;https://en.wikipedia.org/wiki/Multicast_DNS&quot;&gt;mDNS&lt;/a&gt; service):&lt;/p&gt;
&lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;ssh admin@roborio-&amp;lt;team&amp;gt;-frc.local
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;If you have issues, try one of the following addresses instead:&lt;/p&gt;
&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;roborio-&amp;lt;team&amp;gt;-FRC
roborio-&amp;lt;team&amp;gt;-FRC.lan
roborio-&amp;lt;team&amp;gt;-FRC.frc-field.local
10.TE.AM.2
172.22.11.2 # Only works on a USB connection
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;If you are asked for a password, and have not set one, press &lt;kbd&gt;Enter&lt;/kbd&gt; 3 times (Dont ask why.. this just works).&lt;/p&gt;
&lt;h2 id=&quot;repl-based-control&quot;&gt;REPL-based control&lt;/h2&gt;
&lt;p&gt;If you have seen my work before, youll 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 &lt;a href=&quot;https://en.wikipedia.org/wiki/Read%E2%80%93eval%E2%80%93print_loop&quot;&gt;REPL&lt;/a&gt;. This allows real-time robot programming using a REPL via SSH.&lt;/p&gt;
&lt;p&gt;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 &lt;code class=&quot;highlighter-rouge&quot;&gt;setSpeed&lt;/code&gt; and &lt;code class=&quot;highlighter-rouge&quot;&gt;stop&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;After connecting to the robot via SSH, a Python REPL can be started by running &lt;code class=&quot;highlighter-rouge&quot;&gt;python3&lt;/code&gt;. If there is already robot code running, it will be automatically killed in the next step.&lt;/p&gt;
&lt;p&gt;With Python running, we will need 2 libraries imported. &lt;code class=&quot;highlighter-rouge&quot;&gt;wpilib&lt;/code&gt; and &lt;code class=&quot;highlighter-rouge&quot;&gt;ctre&lt;/code&gt;. When importing &lt;code class=&quot;highlighter-rouge&quot;&gt;wpilib&lt;/code&gt; a message may appear to notify you that the old robot code has been stopped.&lt;/p&gt;
&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;wpilib&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;Killing&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;previously&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;running&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;FRC&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;program&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;...&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;FRC&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pid&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1445&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;did&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;not&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;die&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;within&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ms&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Force&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;killing&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;with&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;kill&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;9&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;ctre&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Keep in mind, this is a REPL. Lines that start with &lt;code class=&quot;highlighter-rouge&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/code&gt; or &lt;code class=&quot;highlighter-rouge&quot;&gt;...&lt;/code&gt; are &lt;em&gt;user input&lt;/em&gt;. Everything else is produced by code.&lt;/p&gt;
&lt;p&gt;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 &lt;code class=&quot;highlighter-rouge&quot;&gt;rtrbt.py&lt;/code&gt; somewhere, then use SCP to copy it to &lt;code class=&quot;highlighter-rouge&quot;&gt;/home/lvuser/rtrbt.py&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;# RealTime FRC Robot control helper
# By: Evan Pratten &amp;lt;ewpratten&amp;gt;
&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# Import normal robot stuff
&lt;/span&gt;&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;wpilib&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;ctre&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# Handle WPI trickery
&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;try&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;unittest.mock&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;patch&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;except&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;ImportError&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;mock&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;patch&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;sys&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;threading&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Thread&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;## Internal methods ##
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_controllers&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;_thread&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Thread&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;_RTRobot&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;wpilib&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;TimedRobot&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;robotInit&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# Create motors
&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_controllers&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;append&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ctre&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;WPI_TalonSRX&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;_controllers&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;append&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ctre&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;WPI_TalonSRX&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# Set safe modes
&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_controllers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;setSafetyEnabled&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;False&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;_controllers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;setSafetyEnabled&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;False&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;_start&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;():&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# Handle fake args
&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;args&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;run&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;run&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;with&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;patch&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;object&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sys&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;argv&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sys&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;argv&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;wpilib&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;run&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_RTRobot&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;## Utils ##
&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;startRobot&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;():&lt;/span&gt;
&lt;span class=&quot;s&quot;&gt;&quot;&quot;&quot; Start the robot code &quot;&quot;&quot;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;global&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_thread&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;_thread&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Thread&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;target&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_start&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;_thread&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;start&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;setMotor&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;speed&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
&lt;span class=&quot;s&quot;&gt;&quot;&quot;&quot; Set a motor speed &quot;&quot;&quot;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;_controllers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;speed&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;arcadeDrive&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;speed&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;rotation&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
&lt;span class=&quot;s&quot;&gt;&quot;&quot;&quot; Control the robot with arcade inputs &quot;&quot;&quot;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;l&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;speed&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;rotation&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;r&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;speed&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;rotation&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;setMotor&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;l&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;setMotor&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;The idea is to create a simple robot program with global hooks into the motor controllers. Pythons mocking tools are used to fake commandline arguments to trick robotpy into thinking this script is being run via the RIOs robotCommand.&lt;/p&gt;
&lt;p&gt;Once this script has been placed on the robot, SSH back in as &lt;code class=&quot;highlighter-rouge&quot;&gt;lvuser&lt;/code&gt; (not &lt;code class=&quot;highlighter-rouge&quot;&gt;admin&lt;/code&gt;), and run &lt;code class=&quot;highlighter-rouge&quot;&gt;python3&lt;/code&gt;. If using &lt;code class=&quot;highlighter-rouge&quot;&gt;rtrbt.py&lt;/code&gt;, the imports mentioned above are handled for you. To start the robot, just run the following:&lt;/p&gt;
&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;rtrbt&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;startRobot&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;WPILib will dump some logs into the terminal (and probably some spam) from its own thread. Dont worry if you cant see the REPL prompt. Its probably just hidden due to the use of multiple threads in the same shell. Pressing &lt;kbd&gt;Enter&lt;/kbd&gt; should show it again.&lt;/p&gt;
&lt;p&gt;I added 2 functions for controlling motors. The first, &lt;code class=&quot;highlighter-rouge&quot;&gt;setMotor&lt;/code&gt;, will set either the left (0), or right (1) motor to the specified speed. &lt;code class=&quot;highlighter-rouge&quot;&gt;arcadeDrive&lt;/code&gt; will allow you to specify a speed and rotational force for the robots drivetrain.&lt;/p&gt;
&lt;p&gt;To kill the code and exit, press &lt;kbd&gt;CTRL&lt;/kbd&gt; + &lt;kbd&gt;D&lt;/kbd&gt; then &lt;kbd&gt;CTRL&lt;/kbd&gt; + &lt;kbd&gt;C&lt;/kbd&gt;.&lt;/p&gt;
&lt;p&gt;Here is an example where I start the bot, then tell it to drive forward, then kill the left motor:&lt;/p&gt;
&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;Python&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;3.6.8&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;default&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Oct&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;7&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2019&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;12&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;59&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;55&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;GCC&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;8.3.0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;on&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;linux&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;Type&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;help&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;copyright&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;credits&quot;&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;or&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;license&quot;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;more&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;information&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;rtrbt&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;startRobot&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'run'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;'run'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;mi&quot;&gt;17&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;53&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;46&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;472&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;INFO&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;wpilib&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;WPILib&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;version&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;2019.2.3&lt;/span&gt;
&lt;span class=&quot;mi&quot;&gt;17&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;53&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;46&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;473&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;INFO&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;wpilib&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;HAL&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;base&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;version&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;2019.2.3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;mi&quot;&gt;17&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;53&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;46&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;473&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;INFO&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;wpilib&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;robotpy&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ctre&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;version&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;2019.3.2&lt;/span&gt;
&lt;span class=&quot;mi&quot;&gt;17&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;53&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;46&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;473&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;INFO&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;wpilib&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;robotpy&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cscore&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;version&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;2019.1.0&lt;/span&gt;
&lt;span class=&quot;mi&quot;&gt;17&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;53&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;46&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;473&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;INFO&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;faulthandler&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;registered&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;SIGUSR2&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;PID&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;5447&lt;/span&gt;
&lt;span class=&quot;mi&quot;&gt;17&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;53&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;46&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;474&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;INFO&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;nt&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;NetworkTables&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;initialized&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;server&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mode&lt;/span&gt;
&lt;span class=&quot;mi&quot;&gt;17&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;53&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;46&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;497&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;INFO&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;robot&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Default&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;IterativeRobot&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;disabledInit&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;method&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;...&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Override&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;me&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;!&lt;/span&gt;
&lt;span class=&quot;mi&quot;&gt;17&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;53&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;46&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;498&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;INFO&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;robot&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Default&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;IterativeRobot&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;disabledPeriodic&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;method&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;...&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Override&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;me&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;!&lt;/span&gt;
&lt;span class=&quot;mi&quot;&gt;17&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;53&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;46&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;498&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;INFO&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;robot&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Default&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;IterativeRobot&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;robotPeriodic&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;method&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;...&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Override&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;me&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;!&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;arcadeDrive&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;1.0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;0.0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;setMotor&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;0.0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;^&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;C&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;Exception&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ignored&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;module&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;'threading'&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;'/usr/lib/python3.6/threading.py'&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;Traceback&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;most&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;recent&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;call&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;last&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;File&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;/usr/lib/python3.6/threading.py&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;line&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1294&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_shutdown&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;join&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;File&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;/usr/lib/python3.6/threading.py&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;line&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1056&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;join&lt;/span&gt;
&lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_wait_for_tstate_lock&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;File&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;/usr/lib/python3.6/threading.py&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;line&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1072&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_wait_for_tstate_lock&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;elif&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;lock&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;acquire&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;block&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;timeout&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;KeyboardInterrupt&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;The message at the end occurs when killing the code.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;I have no idea why any of this would be useful, or if it is even field legal.. Its just a fun project for a monday morning.&lt;/p&gt;</content><author><name></name></author><summary type="html">“So.. what if we could skip asking for driver inputs, and just have the robot operators control the bot through a commandline interface?”</summary></entry><entry><title type="html">Using an RNN to generate Bill Wurtz notes</title><link href="http://0.0.0.0:4000/blog/2019/10/05/billwurtz" rel="alternate" type="text/html" title="Using an RNN to generate Bill Wurtz notes" /><published>2019-10-05T14:54:00-04:00</published><updated>2019-10-05T14:54:00-04:00</updated><id>http://0.0.0.0:4000/blog/2019/10/05/BillWurtz</id><content type="html" xml:base="http://0.0.0.0:4000/blog/2019/10/05/billwurtz">&lt;p&gt;&lt;a href=&quot;https://billwurtz.com/&quot;&gt;Bill Wurtz&lt;/a&gt; is an American musician who became &lt;a href=&quot;https://socialblade.com/youtube/user/billwurtz/realtime&quot;&gt;reasonably famous&lt;/a&gt; through short musical videos posted to Vine and YouTube. I was searching through his website the other day, and stumbled upon a page labeled &lt;a href=&quot;https://billwurtz.com/notebook.html&quot;&gt;&lt;em&gt;notebook&lt;/em&gt;&lt;/a&gt;, and thought I should check it out.&lt;/p&gt;
&lt;p&gt;Bills 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..&lt;/p&gt;
@ -568,105 +739,4 @@ ibus-daemon &lt;span class=&quot;nt&quot;&gt;-drx&lt;/span&gt;
&lt;p&gt;If you would like to add a distro or three to the website, feel free to make a pull request over on &lt;a href=&quot;https://github.com/Ewpratten/GiveMeADistro&quot;&gt;GitHub&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;why-make-a-post-about-it-a-year-later&quot;&gt;Why make a post about it a year later?&lt;/h2&gt;
&lt;p&gt;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!&lt;/p&gt;</content><author><name></name></author><summary type="html">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.</summary></entry><entry><title type="html">Scraping FRC teams GitHub accounts to gather large amounts of data</title><link href="http://0.0.0.0:4000/blog/2019/07/06/scrapingfrcgithub" rel="alternate" type="text/html" title="Scraping FRC team's GitHub accounts to gather large amounts of data" /><published>2019-07-06T11:08:00-04:00</published><updated>2019-07-06T11:08:00-04:00</updated><id>http://0.0.0.0:4000/blog/2019/07/06/ScrapingFRCGithub</id><content type="html" xml:base="http://0.0.0.0:4000/blog/2019/07/06/scrapingfrcgithub">&lt;p&gt;I was curious about the most used languages for FRC, so I build a Python script to find out what they where.&lt;/p&gt;
&lt;h2 id=&quot;some-basic-data&quot;&gt;Some basic data&lt;/h2&gt;
&lt;p&gt;Before we get to the heavy work done by my script, lets start with some general data.&lt;/p&gt;
&lt;p&gt;Thanks to the &lt;a href=&quot;https://www.thebluealliance.com/apidocs/v3&quot;&gt;TBA API&lt;/a&gt;, I know that there are 6917 registered teams. 492 of them have registered at least one account on GitHub.&lt;/p&gt;
&lt;h2 id=&quot;how-the-script-works&quot;&gt;How the script works&lt;/h2&gt;
&lt;p&gt;The script is split into steps:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Get a list of every registered team&lt;/li&gt;
&lt;li&gt;Check for a github account attached to every registered team
&lt;ul&gt;
&lt;li&gt;If a team has an account, it is added to the dataset&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Load each github profile
&lt;ul&gt;
&lt;li&gt;If it is a private account, move on&lt;/li&gt;
&lt;li&gt;Use Regex to find all languages used&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Compile data and sort&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;getting-a-list-of-accounts&quot;&gt;Getting a list of accounts&lt;/h3&gt;
&lt;p&gt;This is probably the simplest step in the whole process. I used the auto-generated &lt;a href=&quot;https://github.com/TBA-API/tba-api-client-python&quot;&gt;tbaapiv3client&lt;/a&gt; python librarys &lt;code class=&quot;highlighter-rouge&quot;&gt;get_teams_keys(key)&lt;/code&gt; function, and kept incrementing &lt;code class=&quot;highlighter-rouge&quot;&gt;key&lt;/code&gt; until I got an empty array. All returned data was then added together into a big list of team keys.&lt;/p&gt;
&lt;h3 id=&quot;checking-for-a-teams-github-account&quot;&gt;Checking for a teams github account&lt;/h3&gt;
&lt;p&gt;The &lt;a href=&quot;https://www.thebluealliance.com/apidocs/v3&quot;&gt;TBA API&lt;/a&gt; helpfully provides a &lt;code class=&quot;highlighter-rouge&quot;&gt;/api/v3/team/&amp;lt;number&amp;gt;/social_media&lt;/code&gt; API endpoint that will give the GitHub username for any team you request. (or nothing if they dont use github)&lt;/p&gt;
&lt;p&gt;A &lt;code class=&quot;highlighter-rouge&quot;&gt;for&lt;/code&gt; loop on this with a list of every team number did the trick for finding accounts.&lt;/p&gt;
&lt;h3 id=&quot;fetching-language-info&quot;&gt;Fetching language info&lt;/h3&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;p&gt;To check for language usage, a simple Regex pattern can be used: &lt;code class=&quot;highlighter-rouge&quot;&gt;/programmingLanguage&quot;\&amp;gt;(.*)\&amp;lt;/gm&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;When combined with an &lt;code class=&quot;highlighter-rouge&quot;&gt;re.findall()&lt;/code&gt;, this pattern will return a list of all recent languages used by a team.&lt;/p&gt;
&lt;h3 id=&quot;data-saves--backup-solution&quot;&gt;Data saves / backup solution&lt;/h3&gt;
&lt;p&gt;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”.&lt;/p&gt;
&lt;p&gt;On launch of the script, it will check for a &lt;code class=&quot;highlighter-rouge&quot;&gt;./data.json&lt;/code&gt; 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.&lt;/p&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;p&gt;All parsing data is saved to the json file every time the script completes, or it detects a &lt;code class=&quot;highlighter-rouge&quot;&gt;SIGKILL&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id=&quot;what-i-learned&quot;&gt;What I learned&lt;/h2&gt;
&lt;p&gt;After letting the script run for about an hour, I got a bunch of data from every registered team.&lt;/p&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;p&gt;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:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;C (128)&lt;/li&gt;
&lt;li&gt;LabView (153)&lt;/li&gt;
&lt;li&gt;Kotlin (96)&lt;/li&gt;
&lt;li&gt;Rust (4)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Now, the rest of the languages below Python:&lt;/p&gt;
&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;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
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;I have removed markup and shell languages from that list because most of them are probably auto-generated.&lt;/p&gt;
&lt;p&gt;In terms of github account names, 133 teams follow FRC convention and use a username starting with &lt;code class=&quot;highlighter-rouge&quot;&gt;frc&lt;/code&gt;, followed by their team number, 95 teams use &lt;code class=&quot;highlighter-rouge&quot;&gt;team&lt;/code&gt; then their number, and 264 teams use something else.&lt;/p&gt;
&lt;h2 id=&quot;using-the-script&quot;&gt;Using the script&lt;/h2&gt;
&lt;p&gt;This script is not on PYPI this time. You can obtain a copy from my GitHub repo: &lt;a href=&quot;https://github.com/Ewpratten/frc-code-stats&quot;&gt;https://github.com/Ewpratten/frc-code-stats&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;First, make sure both &lt;code class=&quot;highlighter-rouge&quot;&gt;python3.7&lt;/code&gt; and &lt;code class=&quot;highlighter-rouge&quot;&gt;python3-pip&lt;/code&gt; are installed on your computer. Next, delete the &lt;code class=&quot;highlighter-rouge&quot;&gt;data.json&lt;/code&gt; file. Then, install the requirements with &lt;code class=&quot;highlighter-rouge&quot;&gt;pip3 install -r requirements.txt&lt;/code&gt;. Finally, run with &lt;code class=&quot;highlighter-rouge&quot;&gt;python3 main.py&lt;/code&gt; to start the script. Now, go outside and enjoy nature for about an hour, and your data should be loaded!.&lt;/p&gt;</content><author><name></name></author><summary type="html">I was curious about the most used languages for FRC, so I build a Python script to find out what they where.</summary></entry></feed>
&lt;p&gt;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!&lt;/p&gt;</content><author><name></name></author><summary type="html">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.</summary></entry></feed>

View File

@ -14,7 +14,7 @@
<meta property="og:url" content="http://0.0.0.0:4000/fossl-feeds" />
<meta property="og:site_name" content="Evan Pratten" />
<script type="application/ld+json">
{"headline":"FOSS/L RSS Feeds","@type":"WebPage","url":"http://0.0.0.0:4000/fossl-feeds","description":"RSS feeds from our blogs","@context":"https://schema.org"}</script>
{"@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"}</script>
<!-- End Jekyll SEO tag -->
@ -103,7 +103,7 @@ https://blog.mrtnrdl.de/feed.xml
<span class="site-info">
Site design by: <a href="https://retrylife.ca">Evan Pratten</a> |
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
</span>
</div>

View File

@ -14,7 +14,7 @@
<meta property="og:url" content="http://0.0.0.0:4000/" />
<meta property="og:site_name" content="Evan Pratten" />
<script type="application/ld+json">
{"headline":"Evan Pratten","@type":"WebSite","url":"http://0.0.0.0:4000/","name":"Evan Pratten","description":"Computer wizard, student, @frc5024 programming team lead, and radio enthusiast.","@context":"https://schema.org"}</script>
{"@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"}</script>
<!-- End Jekyll SEO tag -->
@ -116,7 +116,7 @@
<span class="site-info">
Site design by: <a href="https://retrylife.ca">Evan Pratten</a> |
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
</span>
</div>

View File

@ -14,7 +14,7 @@
<meta property="og:url" content="http://0.0.0.0:4000/projects" />
<meta property="og:site_name" content="Evan Pratten" />
<script type="application/ld+json">
{"headline":"My Projects","@type":"WebPage","url":"http://0.0.0.0:4000/projects","description":"Computer wizard, student, @frc5024 programming team lead, and radio enthusiast.","@context":"https://schema.org"}</script>
{"@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"}</script>
<!-- End Jekyll SEO tag -->
@ -273,7 +273,7 @@
<span class="site-info">
Site design by: <a href="https://retrylife.ca">Evan Pratten</a> |
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
</span>
</div>

View File

@ -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/"}
{"/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/"}

View File

@ -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;
}
}

Binary file not shown.

64
assets/python/rtrbt.py Normal file
View File

@ -0,0 +1,64 @@
# RealTime FRC Robot control helper
# By: Evan Pratten <ewpratten>
# 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)