Copyright 2018 - Capnetix, LLC
Charlie Peppler

Charlie Peppler

Well, all went well with soldering up the MotorHAT.  In fact, we downloaded the software from Adafruit, fired it up in Python, and went through a sequence of first moving a single motor, then moving two motors just using SSH and Python locally on the Pi, with the device on the bench.

 


What I needed to do next was find a python program that would initialize a networktables server, and listen for a connection from a client, and print out the values, so I could see what was happening at the driverstation.

 

I started with just a listener, but here is what I'm running now.  This code listens to any changes in network tables, and then filters out anything that has to do with the forward/backward axes on the two joysticks.

This is NOT production code BTW.   It's a hack to get things to work.

#!/usr/bin/env python3
#
# This is a NetworkTables client (eg, the DriverStation/coprocessor side).
# You need to tell it the IP address of the NetworkTables server (the
# robot or simulator).
#
# This shows how to use a listener to listen for changes in NetworkTables
# values. This will print out any changes detected on the SmartDashboard
# table.
#

# Make this a server/listener
'''

import time
from networktables import NetworkTables

# To see messages from networktables, you must setup logging
import logging

logging.basicConfig(level=logging.DEBUG)

NetworkTables.initialize()
sd = NetworkTables.getTable("SmartDashboard")

i = 0
while True:
    print('dsTime:', sd.getNumber('dsTime', 'N/A'))

    sd.putNumber('robotTime', i)
    time.sleep(1)
    i += 1

'''


import sys
import time
import atexit

from networktables import NetworkTables
from Adafruit_MotorHAT import Adafruit_MotorHAT, Adafruit_DCMotor

# To see messages from networktables, you must setup logging
import logging
logging.basicConfig(level=logging.DEBUG)

'''if len(sys.argv) != 2:
    print("Error: specify an IP to connect to!")
    exit(0)

ip = sys.argv[1]

NetworkTables.initialize(server=ip)

'''
# create a default object, no changes to I2C address or frequency
mh = Adafruit_MotorHAT(addr=0x60)

# recommended for auto-disabling motors on shutdown!


def turnOffMotors():
    mh.getMotor(1).run(Adafruit_MotorHAT.RELEASE)
    mh.getMotor(2).run(Adafruit_MotorHAT.RELEASE)
    mh.getMotor(3).run(Adafruit_MotorHAT.RELEASE)
    mh.getMotor(4).run(Adafruit_MotorHAT.RELEASE)


atexit.register(turnOffMotors)

motorLeft = mh.getMotor(3)
motorRight = mh.getMotor(4)

motorLeftSpeed = 0                           # should be from 0-255
motorLeftDirection = Adafruit_MotorHAT.RELEASE   # Start in a forward direction

motorGain = .5				# 1.0 is full speed, needed to turn them down


def getSpeedFromAxisValue(axisvalue: float) -> int:
    if abs(axisvalue) < .001:
        axisvalue = 0.0
    return abs(int(axisvalue*motorGain*255.0))


def getDirectionFromAxisValue(axisvalue: float, reverse: bool) -> int:
    if abs(axisvalue) < .001:
        direction = Adafruit_MotorHAT.RELEASE
    elif axisvalue < 0.0:
        direction = Adafruit_MotorHAT.FORWARD
        if reverse:
            direction = Adafruit_MotorHAT.BACKWARD
    else:
        direction = Adafruit_MotorHAT.BACKWARD
        if reverse:
            direction = Adafruit_MotorHAT.FORWARD
    return direction


nt = "driver_station//joystick-0"

print("Listening to table:"+nt)
NetworkTables.initialize()
sd = NetworkTables.getTable(nt)


def valueChanged(table, key, value, isNew):
    print("valueChanged: key: '%s'; value: %s; isNew: %s" % (key, value, isNew))
    if key == "axis-3":
        print("Axis 3 changed to %f" % value)
        motorLeft.run(getDirectionFromAxisValue(value, True))
        motorLeft.setSpeed(getSpeedFromAxisValue(value))
    elif key == "axis-1":
        print("Axis 1 changed to %f" % value)
        motorRight.run(getDirectionFromAxisValue(value, True))
        motorRight.setSpeed(getSpeedFromAxisValue(value))


def connectionListener(connected, info):
    print(info, '; Connected=%s' % connected)


NetworkTables.addConnectionListener(connectionListener, immediateNotify=True)

sd = NetworkTables.getTable(nt)
sd.addEntryListener(valueChanged)

# set the speed to start, from 0 (off) to 255 (max speed)
motorLeft.setSpeed(150)
motorLeft.run(Adafruit_MotorHAT.FORWARD);
# turn off motor
motorLeft.run(Adafruit_MotorHAT.RELEASE);

motorRight.setSpeed(150)
motorRight.run(Adafruit_MotorHAT.FORWARD);
# turn off motor
motorRight.run(Adafruit_MotorHAT.RELEASE);

while True:
    time.sleep(1)
 

 

Now, I can connect the player console to the Windows laptop, and startup the pydriver station.  Run the code above on the pi, and Voila!  You can move the motors with the joysticks.  Teleoperation!

 

 

 

My MotorHAT came in the mail from Adafruit.  Always a happy moment when parts come in the mail.



First thing I did was open it up, and solder on the headers, just like it says in the docs. (That's a picture of their pretty soldering, not mine).

It's pretty easy to do, once you get the hang of it.

 

Once all the soldering iwas done, I needed to wire in one of the motors I had from my old Lego set.

Peeking ahead, I wired one of them to the M3 (Motor 3) leads.  As you can see from the picture, the Lego connectors are not very convenient for wiring if you're not using the old RCX 1.0, so I started by putting wires into the M3 connectors on the MotorHAT, and then using alligator clips to connect those wires to the leads on one of the motors.

Not exactly production worthy, but I wanted to make sure I could get a motor to turn.

I had an old variable voltage power supply that I hooked up to the power terminals on the MotorHAT.  

Note!  I would highly recommend having a multimeter.  To test the polarity of the leads on the powers supply before plugging it in to the power on the MotorHAT.  Use it to make sure you connect the right wire to the right terminal.  Positive (+) is the red wire.   Negative (-) is the black wire.  Make sure to connect these in the right way and not flipped!

 

 

Next, I downloaded the Adafruit library that goes with the board, and found a nice place for it on the Pi.

Follow these instructions carefully, they've done a good job documenting the process.

I ran the example program, and there went the motor spinning.  First in one direction, and then the other.   

I was psyched!

 

I wanted to include "teleoperation" in the PiBot.  That meant that I had to setup a driver station.  I needed some type of joystick or gaming console.  So, I found a local Game Stop, and bought a refurbished one for about $15.  This "Rock Candy" job should do the trick. 

I know that at some point, I'm going to need to map at least the axes of the joysticks to drive the left and right motors, so I found an open source Python program, called "Joystick Analyzer" (based on PyGame library), that let me plug the console in the laptop, push buttons, and see what axis or button was being pushed.  From that, I'm sure later, I'll see it someplace in the robot software and do something with it.

My thanks Mike Doty for his contribution of Joystick Analyzer that helped me map this console.

 

 

Now that we have a physical console and a map, we need to figure out how to hook this up to the bot.  Scratching my head, I wondered if someone else had the same idea of using Pi based robots in the FRC off-season, and thought, well, let's pull up DuckDuckGo (a competitor to Google search engine, can you believe it?) and search around.

Well, lo and behold FRC team 2733 "The Pigmice" had developed and released

# Pigmice Python DriverStation
This is a project to create a Python-based driver station for our Raspberry Pi minibots. 

Here is the repo I downloaded

With a little setup of the Python environment, it came right up.

Thanks to the Pigmice!  You made our off season a lot more productive!

 

 

There was only one problem.  The py_driverstation program came up, but what was it doing?  I scratched my head, and thought about the software/networking architecture used during FRC competition...and knew there was this thing called "NetworkTables".

I had used Publish/Subscribe (pub sub) systems before, and I kind of figured out this was a table based PubSub kind of interprocess communications over the wireless network to the robot program.

I didn't really have any documentation to figure out what that structure was, because I was going to need to pickout the axis values of the two joysticks in order to drive the motors.

Hmmm, I bet someone has built an easy to use, open source NetworkTables analyzer out there.  Handy web search, and Bingo!  There it was:


# NetworkTablesMonitor
A tool for monitoring and debugging NetworkTables traffic on the robot.

 

This one was a Java app, developed by Team FRC 2706, Merge Robotics hailing from Ottowa, Canada.

The git repo is here.

 

Thank you Merge Robotics for this useful tool.

 

But wait.  This isn't working yet.

 

 

Question #1:  Where to start?

Well, if we're going to get something to move, we might as well start at the bottom of the "stack".  Given that FRC uses all DC motors (steppers and servos are for more precise motion control), we should start there as well. 

Since we are working with the RasPI, motors need to be smaller.  12VDC motors (without proper power protection) would fry the Pi. 

Fortunately, I happened to have an old Lego Mindstorm set I bought my kids when they were little (all the way back to the RSX...).  I found two Lego motors that should do well.

Of course the RasPi has lots of low power I/O capability (Digital Inputs/Outputs, UART, SPI, I2C, PWM), but not enough to drive multiple motors.  So, we're going to need a motor controller board.  We want something small that works well with the RasPi, but enough to drive motors at between roughly 3-6 VDC.  I chose this one from Adafruit

While I was at it, I ordered another Pi (I wanted to dedicate one to the robot and I'm using my first one).  I also ordered some standoffs (to keep the RasPi and the MotorHAT separate but well supported), a power supply and an SD card for the RasPi.  Between these new pieces and the left over parts I should have enough hardware to get started.

 

Just a note about power supplies...I'm going to start with all the pieces on a prototyping board, connected with two separate plug in power supplies, one for the RasPi, and one for the motors.  We need to keep in mind that eventually we need to be mobile. 

For the RasPi, I plan on using one of those tube like rechargable batteries that generates 5V (used frequenlty for cell phones), and a separate battery pack for the motors.  Probably a holder for 4 AA batteries.  That should give 6V for the motors, and separate 5V for the Pi.

OK, so parts on order, some parts on hand, time to think about software and how we're going to drive this thing around....

 

 

My name is Charlie Peppler.  I have always had a passion for using computers to move things and make things.  I've spent most of my career in connecting computers, devices, databases, and of course people.  More on my background and why I started doing this later, but the first question is:  What the heck is a "Mentor on a Mission"?

 I volunteered as a mentor for First Robotics Competition (Team 5459 - Ipswich MA).  I enjoyed the experience, but after the dust settled on build season, I realized that there is a big gap between students who might be interested, and the technical skills necessary to be fully involved as a functioning team member during the intense 6 week build season.

 
I enjoy connecting hardware and software to do interesting things and wanted to learn more about FRC and building robots (along with students) during the off season.  I started thinking about what would be necessary to create a minimal working testbed in my home to work with and learn all the various components.  
I quickly realized it was cost prohibitive to recreate the Kit of Parts (RoboRio, Power Distribution Panel, Player station, motors etc.) used in real competition.  I didn't want to spend the money, and for more kids to get kids "hands on", there is a real need for a cheaper "on ramp" platform to work on basic skills (mechanical, electrical, software), that would prepare for having fun, and being productive and successful through the build season leading to FRC competition.  
Turning around in my office chair, I looked at my trusty Raspberry Pi.  I bought it over a year ago, connected it to my home network, and ever since have been experimenting with various software projects, connecting hardware and open source software.  I've wired up an RFID board to the Raspi, written a driver based on libnfc and connected it to MQTT (future blog post?), hooked up LEDs and switches, and driven them with a variety of programming languages (C, Node-Red, Javascript, Java, Python, MySQL).  This thing is extremely capable, has lots of available development tools and open source repos, it's expensive, and has proliferated widely.  Some advanced FRC teams are already using the Pi3 as a vision co-processor.  
My mission became clear.  I wanted to recreate a stripped down version of the FRC competition environment (player station, robot comms, robot software, mechanical and electrical) that would allow me and students to learn, work and play in that gap between Lego Mindstorm and full blown FRC competition...at an affordable price!  

If we could get that all running, there's plenty of headroom to learn more.  Thus ...Mentor on a Mission.

PS, I'm recruiting presently recruiting like minded mentors to help make this platform a reality.  If you're interested contact me.

 

 

 

 

 

 

f t g m