The elusive $130 robot.py test and development platform

Since the 2020-2021 season is looking to be completely online, with no access to our buildspace, 1076 has decided to experiment this year with sending every member of the team a cheap, Raspberry Pi robot kit to use for training and development. This is the kit we are using: https://www.amazon.com/Freenove-Raspberry-Tracking-Avoidance-Ultrasonic/dp/B07YD2LT9D/. The built in library is in python, but it is written really badly and is fairly unwieldy. Therefore we have started development on a robotpy wpilib-equivalent library for this robot, such that any robot.py files can be used with trivial modifications with either the FRC robot or these robot kits. Currently we have driving fully working with our own barebones driver station program.

Our approach in the development of this wpilib-equivalent library has been to reuse as much robotpy code as possible, then writing a thin API to communicate with the different hardware of this robot, so we can keep as much of the structure of robotpy as possible. We did not want to have to reverse-engineer the driver station protocol, so instead we are using NetworkTables to publish the controller state.

Because we were evaluating whether or not this platform would be suitable, we concentrated on getting something working quickly. This need for haste has driven our efforts so far.

The main elements of our system are 1. Driverstation.py, which interfaces with the joystick on the controller host and sends the controller state to the robot host through networktables. 2. run.py is the robot runner. It takes care of calling the typical robot entry points, handles motor safety and robot enable/disable. 3. Robot.py, which should look familiar to those who has programmed their bot in python. 4. pikitlib - this is our clone of wpilib (just the parts we have needed so far to get things working)

We wanted to put this out there because we think this could be an option for other teams facing the contactless season. At about $130 for the entire setup, it could be a good investment in developing your team’s skills.

We also wanted to inquire with the robotpy experts about just how much of the wpilib pyfrc infrastructure we could pull in and use (things like SendableBase don’t require anything special, so we could make sure to incorporate that into any things that we’d like to display on the dashboard?) But it isn’t completely clear to us how we could make the break in the code so that end up with pure python operating environment (field-runtime, driverstation, robot.py) without having to fully implement HAL, having to replicate driverstation protocol, and all of the other things we don’t know about.

The robot kit itself is about 70$, (you can probably get a discount for your school if you contact the seller), then you will also need a Pi+sd card (we are using the 3B+). Unfortunately these robots need some non household batteries, but they aren’t too expensive. You can get the chargers for them fairly cheap on ebay or amazon. You do have to be more careful with these batteries than your standard double a.
Link to where we got the batteries: Samsung 25R 18650 2500mAh 20A Battery INR18650-25R - 18650 Battery Store

Here’s our code so far: GitHub - FRC1076/RobotKitLib

5 Likes

The current RobotPy stuff requires that you implement a HAL. There’s a websocket HAL implementation which will be available for the 2021 season, it might be a good fit for your use case.

If you borrow from the 2019 implementation instead, it’s all pure python.

1 Like

Thank you for this. It is incredible. We have been looking for this exact thing for quite a while.

We even began creating one using an ESP32, but are a bit stuck with power distribution and safety. We have 2 VMX Pis, which are amazing and we are planning to taech our more advanced students to use them, but they do not run RobotPy (I was going to try to figure it out over the summer, but spent more time learning the intricacies of WPILibj and C++ instead). The big issue for us right now is the difficulty of installing WPILib on students’ machines.

I am wondering about a few things.

  1. With that kit, is it the PCA 9685 that handles the power distribution?
    If so, 25mA does not seem like a lot of headroom even for TT motors, but I may be off a bit. I may be reading their docs wrong. We were gifted a bunch of Vex EDR hardware, and ultimately, we would like students to be able to control that with RobotPy.
  2. How possible do you think it would be to adapt the driver station to a webserver so students could run this with a Chromebook (I know HTML, python, and a bit of Javascript, but I have never combined python with the web protocols)?

Thank you again. We may either buy this kit and use it as is, or adapt it for our hardware.

Do your students use Chromebooks? You can run the development software in Linux if that feature is enabled: Linux apps on Chrome OS: An easy-to-follow guide | Computerworld. My students’ school-issued Chromebooks have that disabled (along with everything else) by IT, so they’re glorified web browsers and basically useless for FRC. We had to repurpose a CAD machine for one student to use instead.

As for “Driver Station in a browser”, DS protocol implementations exist online that you can port from other languages (it’s up to you to find them). It’s just a lot of work. If you use the simulation GUI (more fully featured in 2021), it has Driver Station functionality for the simulated robot at least. A couple vendors are working on their own simulators that hook into the HAL websocket server, and one in particular made a websocket client that runs on a small robot so you can drive it around irl. The nice thing about the HAL approach is they didn’t have to reimplement WPILib from the ground up.

1 Like

Thanks. That is excellent. I will look for the DS protocols. We are in the same boat (Our IT locked down our chronebooks completely). For the esp32, I am figuring out how sockets work. I have a minimal proof-of-concept that is controlling own with a slider. I am also able to get a joystick interface working, but I got stuck linking the two.

It is sloppy, but here is the code I have currently. The Ds Protocol mat help with this too.

You might consider yet another approach, and that is to use Eli’s kitlib, and use the Pi on the robot as the robot brain, the development platform, and as the driver station. The driver station (for receiving controler input) could run on the Pi (running NetworkTables on the loopback), so the entire system is running on the robot. A wireless X-box controller can connect to the Pi and provide the controls. Then you could export selective parts of the driver station state via a web interface that could be browsed by the neutered chrome books if you want some additional visibility. You’ll still need HDMI cable/monitor to bootstrap things, and I’m not sure what options you might have for an SSH that runs in the browser, or a VNC that runs if the browser, but those would provide sufficient connectivity to get things done.

1 Like

I think the PCA 9685 just generates the PWM signals and there are some other onboard motor drivers that are doing the actual work. This thing runs pretty quickly, and I can’t see how that would be possible without drivers. (I can’t say for certain because I’ve already covered up the board, but I can take a closer look at another when the other kits arrive.)

1 Like

You might consider yet another approach, and that is to use Eli’s kitlib, and use the Pi on the robot as the robot brain, the development platform, and as the driver station. The driver station (for receiving controler input) could run on the Pi (running NetworkTables on the loopback), so the entire system is running on the robot.

This is exactly what I was thinking. I realized yesterday that we have a Picar-s that uses the same board as a driver. My first step is going to see if I can get this library running effectively on it. Then, I can start working on the DS options. I forgot about the possibility of interfacing the controller directly with the pi. This could be done easily. The piCar-S uses a separate H bridge motor controller but does use the PCA9865 to generate the PWM just as you suggested. I have read that raspberry pis are notoriously bad at PWM timing.

If I make any headway, I will post results. Thank you regardless. This is quite cool.

Just a warning. One of the pwm channels on our kit is reversed to the motor driver, so we patched that up in the SpeedController, rather than desoldering connectors and reversing them on one of the TT motors. You’ll likely have to hack on that a little bit.

1 Like

I thought we were going to need to rewrite a whole lot of code because we are using a Sunfounder kit, but the piKitLib does a beautiful job on its own. It seems all we will need to add is the direction (for the H bridge). I do have a quick question though, What do you all use for the network tables setup on the pi side? Do you install the FRC Vision Software, and then import the network tables from that, or something else?

We just install networktables from here: pynetworktables · PyPI

1 Like

So, I am making a bit of progress. I have been able to get pynetwork tables installed, and a ping works from my host machine to 127.0.0.1 (the pi is on my home network). When I try to run run.py, I get the following text…

INFO:nt:NetworkTables initialized in server mode
DEBUG:nt.th:Started thread nt-dispatch-thread-0
DEBUG:nt.th:Started thread nt-server-thread-0
DEBUG:nt.th:Started thread connection-notifier-0
DEBUG:nt:Listening on  1735

When I run driverstation.py on my computer, it does not error out, but it still does not seem like it is connecting. Shuffleboard is not connecting either. Run.py is running robot.py. Other than adding a few print statements and an sd object, I have no modified the linked code at all.

Does anyone have any ideas where I may be having connection difficulties? I have been running the typical picar software with no issues.

Edit: I forgot to mention that the driver station launches a black box with no info, but the key commands work on the computer side, yet without a good connection, they do not trigger anything on the robot.

Right now the driverstation is very bare bones with little documentation-- we are currently working on developing this more–, as of now you use the keys E and D to enable and disable the robot, and T and A to switch between autonomous and teleoperated modes. (pressing these keys while having the black window selected). This is a temporary thing while we develop a full GUI for the driverstation.

1 Like

Thank you. That is what I had thought, but I was not certain. The print statements helped a lot. As I enter each mode, it prints in the command prompt. TBH, this is an incredible interface. We could add more pieces if we need, but for now, it is perfect.

My main issue is communication from the robot to the computer.

Are you all connecting to 127.0.0.1? Or are you using something else? I am unable to send any signal in PiKitlib to the computer and vice versa. I am probably doing something wrong though.

My flow is…
Turn on the robot. Then, in Putty…

$cd pikitlib
$sudo python3 run.py

(I used sudo because sometimes motor drivers need superuser permissions)
Then on the computer (Windows with python 3 as the default version)…

C:\ ...\pikitlib\py driverstation.py 127.0.0.1

Then I start shuffleboard (which I also have changed to connect to 127.0.0.1 in preferences).
I can get print statements in robot init to work on the robot, so robot.py is running, but the driver station and shuffleboard do not see it.

My pi is headless hence the need for Putty.

I must be missing something basic, but I cannot figure it out.

The IP address in the driverstation argument is the IP address of the raspberry pi on the local network. 127.0.0.1 (Localhost would have the driverstation attempt to connect to itself.

Ah. Okay. Thank you. That is my problem. I will keep poking.
Edit: I do not know how I did not see that before, but I have communication working. :slight_smile:

After a bit of playing around, I am making progress. I am having a few issues with the timer shower.
When I put a loop in robot.init(), everything works fine. However, the second I remove the loop, I run into timing errors. With the code as is, I get the following on the raspberry pi…

DEBUG:nt.th:Started thread nt-net-write-0
DEBUG:nt.th:Started thread nt-net-read-0
INFO:nt:CONNECTED ***.***.***.** port ***** ()
ConnectionInfo(remote_id='', remote_ip='192.***.*.**', remote_port=*****, last_update=0, protocol_version=768) ; Connected=True
DEBUG:nt.th:Started thread entry-notifier-0
Traceback (most recent call last):
  File "run.py", line 144, in <module>
    m.mainLoopThread()
  File "run.py", line 97, in mainLoopThread
    self.rl._stop()
AttributeError: 'main' object has no attribute 'rl'

…And the code crashes and all motors (regardless of pin setup in robot.py) run.
If I attempt to instantiate the thread in the main loop like so…

def __init__(self):
        """
        Construct robot disconnect, and powered on
        """
        self.r = robot.MyRobot()
        self.current_mode = ""
        self.disabled = True
        

        self.timer = pikitlib.Timer()
        self.rl = threading.Thread(target=self.robotLoop)

I make a bit more progress, but I get the following error…

DEBUG:nt.th:Started thread entry-notifier-0
valueChanged: key: 'Disabled'; value: True; isNew: True
valueChanged: key: 'Mode'; value: ; isNew: True
robotdisabled
Traceback (most recent call last):
  File "run.py", line 149, in <module>
    m.mainLoopThread()
  File "run.py", line 100, in mainLoopThread
    self.rl._stop()
  File "/usr/lib/python3.7/threading.py", line 987, in _stop
    assert not lock.locked()
AssertionError

Any thoughts about what I am doing wrong currently?

I think I recognize those errors, I think we fixed both of those issues just yesterday, so you’ll have to do a git pull on the raspberry pi and the driver station end to get the updates.

1 Like

Hello,
I am making a bit more progress. It seems that the newer repo did not work any better, however, I tried what seems to be your branch, and it is working a bit better. It still crashes with one of the two errors above. However, if I keep toggling enable/ disable, it begins to work (when I click enable after a few rounds of going back and forth). Then, if I disable it again, it crashes with one of the two errors.

Also oddly of note, it seems there is also a memory leak because when I go from auto to teleop, it still prints the a button logic. In addition, eventually, it crashes because either auto or teleop keeps slipping.
Any other thoughts about what I may be doing wrong?

It looks to me like you are doing fine. You are helping Eli find the bugs. :wink: We will accept pull requests if you’d like to help with that. We are hoping to be able to use this software to help our returning students improve their software development skills.