Merge "Added damper for series elastic."
diff --git a/.bazelrc b/.bazelrc
index 7f7a2ac..c80339f 100644
--- a/.bazelrc
+++ b/.bazelrc
@@ -77,3 +77,5 @@
# https://github.com/bazelbuild/bazel/issues/6341 for ongoing discussion with
# upstream about this.
build --javabase=@openjdk_linux_archive//:jdk --host_javabase=@openjdk_linux_archive//:jdk
+
+build --noexperimental_separate_genfiles_directory
diff --git a/frc971/control_loops/drivetrain/wheel_nonlinearity_plot.py b/frc971/control_loops/drivetrain/wheel_nonlinearity_plot.py
new file mode 100755
index 0000000..57831c5
--- /dev/null
+++ b/frc971/control_loops/drivetrain/wheel_nonlinearity_plot.py
@@ -0,0 +1,20 @@
+#!/usr/bin/python
+#
+# This is a quick script to show the effect of the wheel nonlinearity term on
+# turning rate
+
+from matplotlib import pylab
+import numpy
+
+if __name__ == '__main__':
+ x = numpy.arange(-1, 1, 0.01)
+
+ for nonlin in numpy.arange(0.2, 1.0, 0.1):
+ angular_range = numpy.pi * nonlin / 2.0
+ newx1 = numpy.sin(x * angular_range) / numpy.sin(angular_range)
+ newx2 = numpy.sin(newx1 * angular_range) / numpy.sin(angular_range)
+
+ pylab.plot(x, newx2, label="nonlin %f" % nonlin)
+
+ pylab.legend()
+ pylab.show()
diff --git a/frc971/control_loops/python/BUILD b/frc971/control_loops/python/BUILD
index fb3e971..09945ba 100644
--- a/frc971/control_loops/python/BUILD
+++ b/frc971/control_loops/python/BUILD
@@ -96,3 +96,18 @@
visibility = ["//visibility:public"],
deps = ["//frc971/control_loops:python_init"],
)
+
+py_binary(
+ name = "spline",
+ srcs = [
+ "spline.py",
+ ],
+ legacy_create_init = False,
+ restricted_to = ["//tools:k8"],
+ deps = [
+ "//external:python-gflags",
+ "//external:python-glog",
+ "//frc971/control_loops/python:controls",
+ "@matplotlib",
+ ],
+)
diff --git a/frc971/control_loops/python/drivetrain.py b/frc971/control_loops/python/drivetrain.py
index 4c89fdc..b1244f3 100644
--- a/frc971/control_loops/python/drivetrain.py
+++ b/frc971/control_loops/python/drivetrain.py
@@ -27,7 +27,8 @@
num_motors=2,
dt=0.00505,
controller_poles=[0.90, 0.90],
- observer_poles=[0.02, 0.02]):
+ observer_poles=[0.02, 0.02],
+ robot_cg_offset=0.0):
"""Defines all constants of a drivetrain.
Args:
@@ -51,11 +52,13 @@
num_motors: int, number of motors on one side of drivetrain.
controller_poles: array, An array of poles. (See control_loop.py)
observer_poles: array, An array of poles. (See control_loop.py)
+ robot_cg_offset: offset in meters of CG from robot center to left side
"""
self.J = J
self.mass = mass
self.robot_radius = robot_radius
+ self.robot_cg_offset = robot_cg_offset
self.wheel_radius = wheel_radius
self.G_high = G_high
self.G_low = G_low
@@ -99,6 +102,14 @@
# Radius of the wheels, in meters.
self.r = drivetrain_params.wheel_radius
self.has_imu = drivetrain_params.has_imu
+ # Offset in meters of the CG from the center of the robot to the left side
+ # of the robot. Since the arm is on the right side, the offset will
+ # likely be a negative number.
+ self.robot_cg_offset = drivetrain_params.robot_cg_offset
+ # Distance from the left side of the robot to the Center of Gravity
+ self.robot_radius_l = drivetrain_params.robot_radius - self.robot_cg_offset
+ # Distance from the right side of the robot to the Center of Gravity
+ self.robot_radius_r = drivetrain_params.robot_radius + self.robot_cg_offset
# Gear ratios
self.G_low = drivetrain_params.G_low
@@ -157,8 +168,12 @@
# These describe the way that a given side of a robot will be influenced
# by the other side. Units of 1 / kg.
- self.msp = 1.0 / self.mass + self.robot_radius * self.robot_radius / self.J
- self.msn = 1.0 / self.mass - self.robot_radius * self.robot_radius / self.J
+ self.mspl = 1.0 / self.mass + self.robot_radius_l * self.robot_radius_l / self.J
+ self.mspr = 1.0 / self.mass + self.robot_radius_r * self.robot_radius_r / self.J
+ self.msnl = self.robot_radius_r / ( self.robot_radius_l * self.mass ) - \
+ self.robot_radius_l * self.robot_radius_r / self.J
+ self.msnr = self.robot_radius_l / ( self.robot_radius_r * self.mass ) - \
+ self.robot_radius_l * self.robot_radius_r / self.J
# The calculations which we will need for A and B.
self.tcl = self.Kt / self.Kv / (
self.Gl * self.Gl * self.resistance * self.r * self.r)
@@ -171,11 +186,15 @@
# X will be of the format
# [[positionl], [velocityl], [positionr], velocityr]]
self.A_continuous = numpy.matrix(
- [[0, 1, 0, 0], [0, -self.msp * self.tcl, 0, -self.msn * self.tcr],
- [0, 0, 0, 1], [0, -self.msn * self.tcl, 0, -self.msp * self.tcr]])
+ [[0, 1, 0, 0],
+ [0, -self.mspl * self.tcl, 0, -self.msnr * self.tcr],
+ [0, 0, 0, 1],
+ [0, -self.msnl * self.tcl, 0, -self.mspr * self.tcr]])
self.B_continuous = numpy.matrix(
- [[0, 0], [self.msp * self.mpl, self.msn * self.mpr], [0, 0],
- [self.msn * self.mpl, self.msp * self.mpr]])
+ [[0, 0],
+ [self.mspl * self.mpl, self.msnr * self.mpr],
+ [0, 0],
+ [self.msnl * self.mpl, self.mspr * self.mpr]])
self.C = numpy.matrix([[1, 0, 0, 0], [0, 0, 1, 0]])
self.D = numpy.matrix([[0, 0], [0, 0]])
@@ -244,8 +263,8 @@
if self.force:
self.A_continuous[0:4, 4:6] = numpy.matrix(
- [[0.0, 0.0], [self.msp, self.msn], [0.0, 0.0],
- [self.msn, self.msp]])
+ [[0.0, 0.0], [self.mspl, self.msnl], [0.0, 0.0],
+ [self.msnr, self.mspr]])
q_voltage = drivetrain_params.kf_q_voltage * self.mpl
else:
self.A_continuous[0:4, 4:6] = self.unaugmented_B_continuous
diff --git a/frc971/control_loops/python/spline.py b/frc971/control_loops/python/spline.py
new file mode 100644
index 0000000..2f8c836
--- /dev/null
+++ b/frc971/control_loops/python/spline.py
@@ -0,0 +1,320 @@
+#!/usr/bin/python
+
+from __future__ import print_function
+
+import numpy
+import sys
+from matplotlib import pylab
+import glog
+import gflags
+
+"""This file is my playground for implementing spline following."""
+
+FLAGS = gflags.FLAGS
+
+
+def spline(alpha, control_points):
+ """Computes a Bezier curve.
+
+ Args:
+ alpha: scalar or list of spline parameters to calculate the curve at.
+ control_points: n x 4 matrix of control points. n[:, 0] is the
+ starting point, and n[:, 3] is the ending point.
+
+ Returns:
+ n x m matrix of spline points. n is the dimension of the control
+ points, and m is the number of points in 'alpha'.
+ """
+ if numpy.isscalar(alpha):
+ alpha = [alpha]
+ alpha_matrix = [[(1.0 - a)**3.0, 3.0 * (1.0 - a)**2.0 * a,
+ 3.0 * (1.0 - a) * a**2.0, a**3.0] for a in alpha]
+
+ return control_points * numpy.matrix(alpha_matrix).T
+
+
+def dspline(alpha, control_points):
+ """Computes the derivitive of a Bezier curve wrt alpha.
+
+ Args:
+ alpha: scalar or list of spline parameters to calculate the curve at.
+ control_points: n x 4 matrix of control points. n[:, 0] is the
+ starting point, and n[:, 3] is the ending point.
+
+ Returns:
+ n x m matrix of spline point derivatives. n is the dimension of the
+ control points, and m is the number of points in 'alpha'.
+ """
+ if numpy.isscalar(alpha):
+ alpha = [alpha]
+ dalpha_matrix = [[
+ -3.0 * (1.0 - a)**2.0, 3.0 * (1.0 - a)**2.0 + -2.0 * 3.0 *
+ (1.0 - a) * a, -3.0 * a**2.0 + 2.0 * 3.0 * (1.0 - a) * a, 3.0 * a**2.0
+ ] for a in alpha]
+
+ return control_points * numpy.matrix(dalpha_matrix).T
+
+
+def ddspline(alpha, control_points):
+ """Computes the second derivitive of a Bezier curve wrt alpha.
+
+ Args:
+ alpha: scalar or list of spline parameters to calculate the curve at.
+ control_points: n x 4 matrix of control points. n[:, 0] is the
+ starting point, and n[:, 3] is the ending point.
+
+ Returns:
+ n x m matrix of spline point second derivatives. n is the dimension of
+ the control points, and m is the number of points in 'alpha'.
+ """
+ if numpy.isscalar(alpha):
+ alpha = [alpha]
+ ddalpha_matrix = [[
+ 2.0 * 3.0 * (1.0 - a),
+ -2.0 * 3.0 * (1.0 - a) + -2.0 * 3.0 * (1.0 - a) + 2.0 * 3.0 * a,
+ -2.0 * 3.0 * a + 2.0 * 3.0 * (1.0 - a) - 2.0 * 3.0 * a,
+ 2.0 * 3.0 * a
+ ] for a in alpha]
+
+ return control_points * numpy.matrix(ddalpha_matrix).T
+
+
+def dddspline(alpha, control_points):
+ """Computes the third derivitive of a Bezier curve wrt alpha.
+
+ Args:
+ alpha: scalar or list of spline parameters to calculate the curve at.
+ control_points: n x 4 matrix of control points. n[:, 0] is the
+ starting point, and n[:, 3] is the ending point.
+
+ Returns:
+ n x m matrix of spline point second derivatives. n is the dimension of
+ the control points, and m is the number of points in 'alpha'.
+ """
+ if numpy.isscalar(alpha):
+ alpha = [alpha]
+ ddalpha_matrix = [[
+ -2.0 * 3.0,
+ 2.0 * 3.0 + 2.0 * 3.0 + 2.0 * 3.0,
+ -2.0 * 3.0 - 2.0 * 3.0 - 2.0 * 3.0,
+ 2.0 * 3.0
+ ] for a in alpha]
+
+ return control_points * numpy.matrix(ddalpha_matrix).T
+
+
+def spline_theta(alpha, control_points, dspline_points=None):
+ """Computes the heading of a robot following a Bezier curve at alpha.
+
+ Args:
+ alpha: scalar or list of spline parameters to calculate the heading at.
+ control_points: n x 4 matrix of control points. n[:, 0] is the
+ starting point, and n[:, 3] is the ending point.
+
+ Returns:
+ m array of spline point headings. m is the number of points in 'alpha'.
+ """
+ if dspline_points is None:
+ dspline_points = dspline(alphas, control_points)
+
+ return numpy.arctan2(
+ numpy.array(dspline_points)[1, :], numpy.array(dspline_points)[0, :])
+
+
+def dspline_theta(alphas,
+ control_points,
+ dspline_points=None,
+ ddspline_points=None):
+ """Computes the derivitive of the heading at alpha.
+
+ This is the derivitive of spline_theta wrt alpha.
+
+ Args:
+ alpha: scalar or list of spline parameters to calculate the derivative
+ of the heading at.
+ control_points: n x 4 matrix of control points. n[:, 0] is the
+ starting point, and n[:, 3] is the ending point.
+
+ Returns:
+ m array of spline point heading derivatives. m is the number of points
+ in 'alpha'.
+ """
+ if dspline_points is None:
+ dspline_points = dspline(alphas, control_points)
+
+ if ddspline_points is None:
+ ddspline_points = ddspline(alphas, control_points)
+
+ dx = numpy.array(dspline_points)[0, :]
+ dy = numpy.array(dspline_points)[1, :]
+
+ ddx = numpy.array(ddspline_points)[0, :]
+ ddy = numpy.array(ddspline_points)[1, :]
+
+ return 1.0 / (dx**2.0 + dy**2.0) * (dx * ddy - dy * ddx)
+
+
+def ddspline_theta(alphas,
+ control_points,
+ dspline_points=None,
+ ddspline_points=None,
+ dddspline_points=None):
+ """Computes the second derivitive of the heading at alpha.
+
+ This is the second derivitive of spline_theta wrt alpha.
+
+ Args:
+ alpha: scalar or list of spline parameters to calculate the second
+ derivative of the heading at.
+ control_points: n x 4 matrix of control points. n[:, 0] is the
+ starting point, and n[:, 3] is the ending point.
+
+ Returns:
+ m array of spline point heading second derivatives. m is the number of
+ points in 'alpha'.
+ """
+ if dspline_points is None:
+ dspline_points = dspline(alphas, control_points)
+
+ if ddspline_points is None:
+ ddspline_points = ddspline(alphas, control_points)
+
+ if dddspline_points is None:
+ dddspline_points = dddspline(alphas, control_points)
+
+ dddspline_points = dddspline(alphas, control_points)
+
+ dx = numpy.array(dspline_points)[0, :]
+ dy = numpy.array(dspline_points)[1, :]
+
+ ddx = numpy.array(ddspline_points)[0, :]
+ ddy = numpy.array(ddspline_points)[1, :]
+
+ dddx = numpy.array(dddspline_points)[0, :]
+ dddy = numpy.array(dddspline_points)[1, :]
+
+ return -1.0 / ((dx**2.0 + dy**2.0)**2.0) * (dx * ddy - dy * ddx) * 2.0 * (
+ dy * ddy + dx * ddx) + 1.0 / (dx**2.0 + dy**2.0) * (dx * dddy - dy *
+ dddx)
+
+
+def main(argv):
+ # Build up the control point matrix
+ start = numpy.matrix([[0.0, 0.0]]).T
+ c1 = numpy.matrix([[0.5, 0.0]]).T
+ c2 = numpy.matrix([[0.5, 1.0]]).T
+ end = numpy.matrix([[1.0, 1.0]]).T
+ control_points = numpy.hstack((start, c1, c2, end))
+
+ # The alphas to plot
+ alphas = numpy.linspace(0.0, 1.0, 1000)
+
+ # Compute x, y and the 3 derivatives
+ spline_points = spline(alphas, control_points)
+ dspline_points = dspline(alphas, control_points)
+ ddspline_points = ddspline(alphas, control_points)
+ dddspline_points = dddspline(alphas, control_points)
+
+ # Compute theta and the two derivatives
+ theta = spline_theta(alphas, control_points, dspline_points=dspline_points)
+ dtheta = dspline_theta(alphas, control_points, dspline_points=dspline_points)
+ ddtheta = ddspline_theta(
+ alphas,
+ control_points,
+ dspline_points=dspline_points,
+ dddspline_points=dddspline_points)
+
+ # Plot the control points and the spline.
+ pylab.figure()
+ pylab.plot(
+ numpy.array(control_points)[0, :],
+ numpy.array(control_points)[1, :],
+ '-o',
+ label='control')
+ pylab.plot(
+ numpy.array(spline_points)[0, :],
+ numpy.array(spline_points)[1, :],
+ label='spline')
+ pylab.legend()
+
+ # For grins, confirm that the double integral of the acceleration (with
+ # respect to the spline parameter) matches the position. This lets us
+ # confirm that the derivatives are consistent.
+ xint_plot = numpy.matrix(numpy.zeros((2, len(alphas))))
+ dxint_plot = xint_plot.copy()
+ xint = spline_points[:, 0].copy()
+ dxint = dspline_points[:, 0].copy()
+ xint_plot[:, 0] = xint
+ dxint_plot[:, 0] = dxint
+ for i in range(len(alphas) - 1):
+ xint += (alphas[i + 1] - alphas[i]) * dxint
+ dxint += (alphas[i + 1] - alphas[i]) * ddspline_points[:, i]
+ xint_plot[:, i + 1] = xint
+ dxint_plot[:, i + 1] = dxint
+
+ # Integrate up the spline velocity and heading to confirm that given a
+ # velocity (as a function of the spline parameter) and angle, we will move
+ # from the starting point to the ending point.
+ thetaint_plot = numpy.zeros((len(alphas),))
+ thetaint = theta[0]
+ dthetaint_plot = numpy.zeros((len(alphas),))
+ dthetaint = dtheta[0]
+ thetaint_plot[0] = thetaint
+ dthetaint_plot[0] = dthetaint
+
+ txint_plot = numpy.matrix(numpy.zeros((2, len(alphas))))
+ txint = spline_points[:, 0].copy()
+ txint_plot[:, 0] = txint
+ for i in range(len(alphas) - 1):
+ dalpha = alphas[i + 1] - alphas[i]
+ txint += dalpha * numpy.linalg.norm(
+ dspline_points[:, i]) * numpy.matrix(
+ [[numpy.cos(theta[i])], [numpy.sin(theta[i])]])
+ txint_plot[:, i + 1] = txint
+ thetaint += dalpha * dtheta[i]
+ dthetaint += dalpha * ddtheta[i]
+ thetaint_plot[i + 1] = thetaint
+ dthetaint_plot[i + 1] = dthetaint
+
+
+ # Now plot x, dx/dalpha, ddx/ddalpha, dddx/dddalpha, and integrals thereof
+ # to perform consistency checks.
+ pylab.figure()
+ pylab.plot(alphas, numpy.array(spline_points)[0, :], label='x')
+ pylab.plot(alphas, numpy.array(xint_plot)[0, :], label='ix')
+ pylab.plot(alphas, numpy.array(dspline_points)[0, :], label='dx')
+ pylab.plot(alphas, numpy.array(dxint_plot)[0, :], label='idx')
+ pylab.plot(alphas, numpy.array(txint_plot)[0, :], label='tix')
+ pylab.plot(alphas, numpy.array(ddspline_points)[0, :], label='ddx')
+ pylab.plot(alphas, numpy.array(dddspline_points)[0, :], label='dddx')
+ pylab.legend()
+
+ # Now do the same for y.
+ pylab.figure()
+ pylab.plot(alphas, numpy.array(spline_points)[1, :], label='y')
+ pylab.plot(alphas, numpy.array(xint_plot)[1, :], label='iy')
+ pylab.plot(alphas, numpy.array(dspline_points)[1, :], label='dy')
+ pylab.plot(alphas, numpy.array(dxint_plot)[1, :], label='idy')
+ pylab.plot(alphas, numpy.array(txint_plot)[1, :], label='tiy')
+ pylab.plot(alphas, numpy.array(ddspline_points)[1, :], label='ddy')
+ pylab.plot(alphas, numpy.array(dddspline_points)[1, :], label='dddy')
+ pylab.legend()
+
+ # And for theta.
+ pylab.figure()
+ pylab.plot(alphas, theta, label='theta')
+ pylab.plot(alphas, dtheta, label='dtheta')
+ pylab.plot(alphas, ddtheta, label='ddtheta')
+ pylab.plot(alphas, thetaint_plot, label='thetai')
+ pylab.plot(alphas, dthetaint_plot, label='dthetai')
+
+ # TODO(austin): Start creating a velocity plan now that we have all the
+ # derivitives of our spline.
+
+ pylab.legend()
+ pylab.show()
+
+
+if __name__ == '__main__':
+ argv = FLAGS(sys.argv)
+ sys.exit(main(argv))
diff --git a/frc971/downloader.bzl b/frc971/downloader.bzl
new file mode 100644
index 0000000..2967127
--- /dev/null
+++ b/frc971/downloader.bzl
@@ -0,0 +1,37 @@
+load('//aos/downloader:downloader.bzl', 'aos_downloader')
+load('//tools/build_rules:label.bzl', 'expand_label')
+
+def robot_downloader(start_binaries, binaries=[], dirs=None, default_target=None):
+ '''Sets up the standard robot download targets.
+
+ Attrs:
+ start_binaries: A list of cc_binary targets to start on the robot.
+ dirs: Passed through to aos_downloader.
+ default_target: Passed through to aos_downloader.
+ '''
+
+ aos_downloader(
+ name = 'download',
+ start_srcs = [
+ '//aos:prime_start_binaries',
+ ] + start_binaries,
+ srcs = [
+ '//aos:prime_binaries',
+ ] + binaries,
+ dirs = dirs,
+ default_target = default_target,
+ restricted_to = ['//tools:roborio'],
+ )
+
+ aos_downloader(
+ name = 'download_stripped',
+ start_srcs = [
+ '//aos:prime_start_binaries_stripped',
+ ] + [expand_label(binary) + ".stripped" for binary in start_binaries],
+ srcs = [
+ '//aos:prime_binaries_stripped',
+ ] + [expand_label(binary) + ".stripped" for binary in binaries],
+ dirs = dirs,
+ default_target = default_target,
+ restricted_to = ['//tools:roborio'],
+ )
diff --git a/scripts/backup_ODROID_microSD_card.rb b/scripts/backup_ODROID_microSD_card.rb
new file mode 100755
index 0000000..e5fc4ad
--- /dev/null
+++ b/scripts/backup_ODROID_microSD_card.rb
@@ -0,0 +1,262 @@
+#!/usr/bin/env ruby
+
+HELP_MSG_SHORT = <<END
+#
+# Usage: #{__FILE__} [-h]
+#
+# -h Print this help message.
+#
+END
+
+HELP_MSG_LONG = <<END
+
+Summary:
+ Backup an ODROID microSD card.
+#
+# The backup_ODROID_microSD_card.rb and restore_ODRIOD_microSD_card_from_backup.rb
+# scripts are used to backup ODROID microSD cards and create new ones. They use
+# tar, mkfs, and dd. dd is only used for the master boot record. The traditional
+# way of copying a mircoSD card is to use dd to make a copy of the entire disk and then
+# copy that back using dd. This can take a long time - hours - and requires having
+# enough space to save a file that is the size of the microSD card. These scripts
+# run in less than 5 minutes each and use only as much disk space as is require
+# to hold the compressed contents of the microSD card.
+#
+# This https://wiki.odroid.com/odroid-xu4/software/partition_table
+# page has some useful information on how hard disks are put together.
+# It appears that the Ubuntu Partition Table Mainline U-boot (odroidxu4-v2017.05)
+# section near the bottom of the page is how the ODROIDs are set up. The
+# Boot Sequence part at the bottom is also helpful to understand the boot sequence.
+#
+# The scripts prompt the user for the device name to be used for the source
+# of the backup and as the target for the restore. The root filesystem of
+# the computer running these scripts is not allowed as an option.
+#
+# Note: If you have trouble booting the ODROID, make sure the small switch
+# around the corner from the HDMI port is set to microSD and not MMC.
+# If this does not work, try pushing and holding for a few seconds the
+# power button on top of the case. It is located right by the two USB ports.
+# Once it is booted, the blue heartbeat light should slowly flash.
+# https://magazine.odroid.com/wp-content/uploads/odroid-xu4-user-manual.pdf
+# has more information on the ODROID.
+END
+
+HELP_MSG = HELP_MSG_LONG + HELP_MSG_SHORT
+
+require 'json'
+require 'pp'
+
+# Process the command line arguments.
+def parse_args()
+ # If there are any command line arguments, print the help message.
+ # This script will fail otherwise because the command line arguments
+ # are passed to the gets commands below which is not what we want.
+ #
+ # Print the help message if there
+ if ((ARGV[0] == "-h") || (ARGV.length > 0) )
+ puts HELP_MSG
+ exit!()
+ end
+end
+
+# Get the partition label
+def get_label(partition)
+ return(`blkid -o export #{partition} | egrep "^LABEL="`.gsub(/LABEL=/,"").chomp)
+end
+
+# Get the partition uuid
+def get_uuid(partition)
+ return(`blkid -o export #{partition} | egrep "^UUID="`.gsub(/UUID=/,"").chomp)
+end
+
+# Get the two ODROID partition names.
+def get_partitions(device)
+ sfdisk = JSON.parse(`sfdisk --json /dev/#{device}`)
+ partitions = sfdisk['partitiontable']['partitions']
+ partition1 = partition2 = nil # return nil if the partition does not exist
+ partition1 = partitions[0]['node'] if partitions.length > 0
+ partition2 = partitions[1]['node'] if partitions.length > 1
+ [partition1, partition2]
+end
+
+# Check to see if a partition is mounted.
+def is_mounted(partition)
+ `lsblk -no MOUNTPOINT #{partition} | wc -c`.chomp.to_i>1
+end
+
+def umount(partition)
+ #puts `df #{partition}` if is_mounted(partition)
+ echo_and_run("umount #{partition}") if is_mounted(partition)
+end
+
+def mount(partition, dir)
+ # First make sure it is not mounted.
+ umount(partition)
+ echo_and_run("mount #{partition} #{dir}")
+end
+
+# Echo and run a command. Print out the output from the command too.
+def echo_and_run(cmd)
+ puts cmd
+ puts `#{cmd}`
+end
+
+# Convert a float to minutes and seconds.
+def time_to_minutes_and_seconds(time)
+ min = time.to_i/60
+ sec = time.to_i%60
+ sprintf("%d:%02d minutes:seconds",min,sec)
+end
+
+# Get the size of the size of the Master Boot Record (MBR).
+# Also include the 512 bytes for the partition table.
+# The MBR resides in the space before start of the first
+# partition.
+def get_MBR_size(device)
+ # Use Json to parse the sfdisk output.
+ sfdisk = JSON.parse(`sfdisk --json /dev/#{device}`)
+ first_partition_start_in_blocks = sfdisk['partitiontable']['partitions'][0]['start']
+ sector_size_in_bytes = `cat /sys/block/#{device}/queue/hw_sector_size`.chomp.to_i
+ return ([first_partition_start_in_blocks, sector_size_in_bytes])
+end
+
+$start_time = Time.now
+$date=`date "+%Y%m%d.%H%M"`.chomp
+$time = "/usr/bin/time -p"
+
+parse_args()
+
+# First figure out what devices are available. Do not show the root filesystem as an option.
+#
+# lsblk gives a listing (shown below) of the devices and mount points.
+# findmnt -n -o SOURCE / tells which device the root filesystem is mounted on.
+# /dev/nvme0n1p6 for the file systems below.
+#
+# NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT
+# mmcblk0 179:0 0 29.7G 0 disk
+# ├─mmcblk0p1 179:1 0 128M 0 part /media/michael/boot
+# └─mmcblk0p2 179:2 0 14.8G 0 part /media/michael/rootfs
+# nvme0n1 259:0 0 238.5G 0 disk
+# ├─nvme0n1p1 259:1 0 1000M 0 part
+# ├─nvme0n1p2 259:2 0 260M 0 part /boot/efi
+# ├─nvme0n1p3 259:3 0 128M 0 part
+# ├─nvme0n1p4 259:4 0 112.3G 0 part
+# ├─nvme0n1p5 259:5 0 15.6G 0 part
+# ├─nvme0n1p6 259:6 0 93.4G 0 part /
+# └─nvme0n1p7 259:7 0 15.8G 0 part [SWAP]
+
+# Locate the root partition.
+root_partition = `findmnt -n -o SOURCE /`.chomp.gsub('/dev/',"")
+
+# Use Json to parse the lsblk output.
+lsblk = JSON.parse(`lsblk --json`)
+
+# Create a list of devices
+devices = []
+partitions = {}
+
+lsblk['blockdevices'].each { |device|
+ devices.push(device_name = device["name"])
+ # For each partition of this device, create a mapping from the partition to the device name.
+ device['children'].each { |partition|
+ partitions[partition["name"]]=device_name
+ }
+}
+puts HELP_MSG_SHORT
+puts "\n# Backing up ODROID XU4 microSD card.\n"
+puts "\n# The available devices are: #{devices.join(" ")}"
+puts "# The root partition is: #{root_partition}"
+puts "# The root device is #{partitions[root_partition]}. This will not be offered as an option. "
+# Remove the root partition device from the list of devices.
+devices.delete(partitions[root_partition])
+non_root_devices = devices.join(" ")
+
+clone_source_device = ""
+
+puts "# The non root devices are: #{non_root_devices}"
+puts `lsblk #{non_root_devices.gsub(/\w+/){|s|'/dev/'+s}}`
+
+if (non_root_devices.length == 0) then
+ puts "\nERROR: No possible microSD card devices found. Exiting.\n\n"
+ exit -1
+end
+
+# Ask the user for the name of the device to be cloned.
+loop do
+ printf "\n# Enter the name of the device to be cloned [#{non_root_devices}]: "
+ clone_source_device = gets.chomp
+ STDOUT.flush
+ if devices.include?(clone_source_device) then
+ break
+ else
+ puts "ERROR: device name '#{clone_source_device}' not found. Please try again."
+ end
+end
+
+puts "# Using #{clone_source_device} for the device to be cloned."
+
+#
+# Make tar and dd files of the microSD card.
+#
+
+printf("\n# Provide a comment to be included in the filenames. i.e. 971-champs: ")
+comment = gets.chomp.gsub("_","-")
+#comment = "971_champs".gsub("_","-")
+puts "# Using comment: #{comment}"
+
+# List the partitions
+partition1, partition2 = get_partitions(clone_source_device)
+partition1_label = get_label(partition1)
+partition2_label = get_label(partition2)
+partition1_uuid = get_uuid(partition1)
+partition2_uuid = get_uuid(partition2)
+puts "\n# Summary information:"
+puts "# Partition 1 is #{partition1} with label #{partition1_label} and uuid #{partition1_uuid}"
+puts "# Partition 2 is #{partition2} with label #{partition2_label} and uuid #{partition2_uuid}"
+
+base_name = "#{$date}_ODROID_XU4"
+
+tar_file_name_boot = "#{base_name}_p1_#{comment}_#{partition1_label}_#{partition1_uuid}.tgz"
+tar_file_name_root = "#{base_name}_p2_#{comment}_#{partition2_label}_#{partition2_uuid}.tgz"
+dd_file_name_mbr = "#{base_name}_MBR_#{comment}.dd"
+sfdisk_file_name = "#{base_name}_sfdisk_#{comment}.txt"
+puts "# Using disk partition information name: #{sfdisk_file_name}"
+puts "# Using boot partition backup name: #{tar_file_name_boot }"
+puts "# Using root partition backup name: #{tar_file_name_root}"
+puts "# Using disk MBR (master boot record) information name: #{dd_file_name_mbr}"
+
+puts "\n# Backing up the sfdisk partition information."
+echo_and_run("sfdisk -d /dev/#{clone_source_device} > #{sfdisk_file_name}")
+
+puts "\n# Backing up the boot partition."
+`mkdir /new` if ! Dir.exists?("/new")
+puts "# Make sure nothing is mounted on /new before mounting #{partition1} there."
+puts "# Here is df output to check to see if anything is mounted on /new."
+echo_and_run("df /new")
+puts "# Running unmount /new to make sure nothing is mounted there."
+echo_and_run("umount /new")
+mount(partition1,"/new")
+echo_and_run("#{$time} tar -czf #{tar_file_name_boot} -C /new .")
+umount(partition1)
+
+puts "\n# Backing up the root partition."
+mount(partition2,"/new")
+echo_and_run("#{$time} tar -czf #{tar_file_name_root} -C /new .")
+umount(partition2)
+
+puts "\n# Backing up the master boot record using dd"
+mbr_size_in_blocks, sector_size_in_bytes = get_MBR_size(clone_source_device)
+puts "# The block size is #{sector_size_in_bytes} bytes and the master boot record is "
+puts "# #{mbr_size_in_blocks} blocks long for a total size of\
+ #{mbr_size_in_blocks*sector_size_in_bytes} bytes."
+echo_and_run("dd if=/dev/#{clone_source_device} of=#{dd_file_name_mbr} \
+ bs=#{sector_size_in_bytes} count=#{mbr_size_in_blocks}")
+
+$end_time = Time.now
+puts ""
+puts "Start time: #{$start_time}"
+puts " End time: #{$end_time}"
+puts "======================================"
+puts "Total time: #{time_to_minutes_and_seconds($end_time-$start_time)}"
+puts ""
+puts "# Done.\n"
diff --git a/scripts/restore_ODRIOD_microSD_card_from_backup.rb b/scripts/restore_ODRIOD_microSD_card_from_backup.rb
new file mode 100755
index 0000000..3c82b2d
--- /dev/null
+++ b/scripts/restore_ODRIOD_microSD_card_from_backup.rb
@@ -0,0 +1,317 @@
+#!/usr/bin/env ruby
+
+HELP_MSG_SHORT = <<END
+#
+# Usage: #{__FILE__} [-h]
+#
+# -h Print this help message.
+#
+END
+
+HELP_MSG_LONG = <<END
+
+Summary:
+ Restore a backup image to an ODROID microSD card.
+#
+# The backup_ODROID_microSD_card.rb and restore_ODRIOD_microSD_card_from_backup.rb
+# scripts are used to backup ODROID microSD cards and create new ones. They use
+# tar, mkfs, and dd. dd is only used for the master boot record. The traditional
+# way of copying a mircoSD card is to use dd to make a copy of the entire disk and then
+# copy that back using dd. This can take a long time - hours - and requires having
+# enough space to save a file that is the size of the microSD card. These scripts
+# run in less than 5 minutes each and use only as much disk space as is require
+# to hold the compressed contents of the microSD card.
+#
+# This https://wiki.odroid.com/odroid-xu4/software/partition_table
+# page has some useful information on how hard disks are put together.
+# It appears that the Ubuntu Partition Table Mainline U-boot (odroidxu4-v2017.05)
+# section near the bottom of the page is how the ODROIDs are set up. The
+# Boot Sequence part at the bottom is also helpful to understand the boot sequence.
+#
+# The scripts prompt the user for the device name to be used for the source
+# of the backup and as the target for the restore. The root filesystem of
+# the computer running these scripts is not allowed as an option.
+#
+# Note: If you have trouble booting the ODROID, make sure the small switch
+# around the corner from the HDMI port is set to microSD and not MMC.
+# If this does not work, try pushing and holding for a few seconds the
+# power button on top of the case. It is located right by the two USB ports.
+# Once it is booted, the blue heartbeat light should slowly flash.
+# https://magazine.odroid.com/wp-content/uploads/odroid-xu4-user-manual.pdf
+# has more information on the ODROID.
+END
+
+HELP_MSG = HELP_MSG_LONG + HELP_MSG_SHORT
+
+require 'json'
+require 'pp'
+
+# Process the command line arguments.
+def parse_args()
+ # If there are any command line arguments, print the help message.
+ # This script will fail otherwise because the command line arguments
+ # are passed to the gets commands below which is not what we want.
+ #
+ # Print the help message if there
+ if ((ARGV[0] == "-h") || (ARGV.length > 0) )
+ puts HELP_MSG
+ exit!()
+ end
+end
+
+# Get the partition label
+def get_label(partition)
+ return(`blkid -o export #{partition} | egrep "^LABEL="`.gsub(/LABEL=/,"").chomp)
+end
+
+def get_uuid(partition)
+ return(`blkid -o export #{partition} | egrep "^UUID="`.gsub(/UUID=/,"").chomp)
+end
+
+# Get the two ODROID partition names.
+def get_partitions(device)
+ sfdisk = JSON.parse(`sfdisk --json /dev/#{device}`)
+ partitions = sfdisk['partitiontable']['partitions']
+ partition1 = partition2 = nil # return nil if the partition does not exist
+ partition1 = partitions[0]['node'] if partitions.length > 0
+ partition2 = partitions[1]['node'] if partitions.length > 1
+ [partition1, partition2]
+end
+
+def umount_all_partitions(device)
+ sfdisk = JSON.parse(`sfdisk --json /dev/#{device}`)
+ partitions = sfdisk['partitiontable']['partitions']
+ puts "# Unmounting all partitions on device #{device}"
+ partitions.each do |partition_info|
+ partition = partition_info['node']
+ if is_mounted(partition) then
+ echo_and_run("umount #{partition}")
+ else
+ puts "# #{partition} not mounted so no need to unmount it."
+ end
+ end
+end
+
+# Check to see if a partition is mounted.
+def is_mounted(partition)
+ `lsblk -no MOUNTPOINT #{partition} | wc -c`.chomp.to_i>1
+end
+
+def umount(partition)
+ #puts `df #{partition}` if is_mounted(partition)
+ echo_and_run("umount #{partition}") if is_mounted(partition)
+end
+
+def mount(partition, dir)
+ # First make sure it is not mounted.
+ umount(partition)
+ echo_and_run("mount #{partition} #{dir}")
+end
+
+# Echo and run a command. Print out the output from the command too.
+def echo_and_run(cmd)
+ puts cmd
+ puts `#{cmd}`
+end
+
+# Convert a float to minutes and seconds.
+def time_to_minutes_and_seconds(time)
+ min = time.to_i/60
+ sec = time.to_i%60
+ sprintf("%d:%02d minutes:seconds",min,sec)
+end
+
+$start_time = Time.now
+$time = "/usr/bin/time -p"
+
+parse_args()
+
+# First figure out what devices are available. Do not show the root filesystem as an option.
+#
+# lsblk gives a listing (shown below) of the devices and mount points.
+# findmnt -n -o SOURCE / tells which device the root filesystem is mounted on.
+# /dev/nvme0n1p6 for the file systems below.
+#
+# NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT
+# mmcblk0 179:0 0 29.7G 0 disk
+# ├─mmcblk0p1 179:1 0 128M 0 part /media/michael/boot
+# └─mmcblk0p2 179:2 0 14.8G 0 part /media/michael/rootfs
+# nvme0n1 259:0 0 238.5G 0 disk
+# ├─nvme0n1p1 259:1 0 1000M 0 part
+# ├─nvme0n1p2 259:2 0 260M 0 part /boot/efi
+# ├─nvme0n1p3 259:3 0 128M 0 part
+# ├─nvme0n1p4 259:4 0 112.3G 0 part
+# ├─nvme0n1p5 259:5 0 15.6G 0 part
+# ├─nvme0n1p6 259:6 0 93.4G 0 part /
+# └─nvme0n1p7 259:7 0 15.8G 0 part [SWAP]
+
+root_partition = `findmnt -n -o SOURCE /`.chomp.gsub('/dev/',"")
+
+# Use Json to parse the lsblk output.
+lsblk = JSON.parse(`lsblk --json`)
+
+# Create a list of devices
+devices = []
+partitions = {}
+
+lsblk['blockdevices'].each { |device|
+ devices.push(device_name = device["name"])
+ # For each partition of this device, create a mapping from the partition to the device name.
+ device['children'].each { |partition|
+ partitions[partition["name"]]=device_name
+ }
+}
+puts "\n# Restoring ODROID XU4 microSD card from a backup.\n"
+puts "\n# The available devices are: #{devices.join(" ")}"
+puts "# The root partition is: #{root_partition}"
+puts "# The root device is #{partitions[root_partition]}. This will not be offered as an option. "
+# Remove the root partition device from the list of devices.
+devices.delete(partitions[root_partition])
+non_root_devices = devices.join(" ")
+
+clone_source_device = ""
+
+puts "# The non root devices are: #{non_root_devices}"
+puts `lsblk #{non_root_devices.gsub(/\w+/){|s|'/dev/'+s}}`
+
+if (non_root_devices.length == 0) then
+ puts "\nERROR: No possible microSD card devices found. Exiting.\n\n"
+ exit -1
+end
+
+# Ask the user for the name of the device to be used for restoring the backup.
+loop do
+ printf "\n# Enter the name of the device to be overwritten with the backup [#{non_root_devices}]: "
+ clone_source_device = gets.chomp
+ STDOUT.flush
+ if devices.include?(clone_source_device) then
+ break
+ else
+ puts "ERROR: device name '#{clone_source_device}' not found. Please try again."
+ end
+end
+
+puts "# Using \"#{clone_source_device}\" for the device to be overwritten with the backup."
+
+#
+# Make tar and dd files of the microSD card.
+#
+
+
+puts "\n# Here is a list of backups available for the restore:"
+puts `ls -ltr *_ODROID_XU4_MBR_*.dd`
+date = ""
+# Ask the user for the name of the device to be used for restoring the backup.
+loop do
+ printf "\n# Enter the backup date (i.e. 20181103.1111) from the list above for"
+ printf "\n# the restore source: "
+ date = gets.chomp
+ STDOUT.flush
+ if (`ls #{date}_ODROID_XU4_MBR*.dd`.chomp.length > 10) then
+ break
+ else
+ puts "ERROR: Backup with date '#{date}' not found. Please try again."
+ end
+end
+
+puts "\n# Using #{clone_source_device} for the device to be overwritten with the backup."
+puts `lsblk /dev/#{clone_source_device}`
+printf "\n# Enter the backup date (i.e. 181102.2224) for the archive to be overwritten with the backup: "
+response = ""
+loop do
+ printf "\n# Are you sure!! All data will be destroyed [Yes|No]: "
+ response = gets.chomp
+ STDOUT.flush
+ exit if response.match("^[nN]o$")
+ if (response.match("^[yY]es$")) then
+ break
+ else
+ puts "ERROR: Enter 'Yes' or 'no'. Please try again."
+ end
+end
+
+sfdisk_file_name = `ls #{date}_ODROID_XU4_sfdisk_*.txt`.chomp
+tar_file_name_boot = `ls #{date}_ODROID_XU4_p1_*.tgz`.chomp
+tar_file_name_root = `ls #{date}_ODROID_XU4_p2_*.tgz`.chomp
+dd_file_name_mbr = `ls #{date}_ODROID_XU4_MBR_*.dd`.chomp
+puts "\n# Using backup files:"
+puts `ls -l #{sfdisk_file_name} \
+#{tar_file_name_boot} \
+#{tar_file_name_root} \
+#{dd_file_name_mbr}`
+
+# Partition the microSD card
+puts "\n# Partitioning the microSD card with device #{clone_source_device}"
+puts "#"
+puts "# First, make sure the partitions are not mounted."
+umount_all_partitions(clone_source_device)
+puts "#"
+puts "# Partioning the disk using sfdisk #{sfdisk_file_name}"
+echo_and_run("sfdisk /dev/#{clone_source_device} < #{sfdisk_file_name}")
+puts "# Done partioning the disk using sfdisk #{sfdisk_file_name}"
+puts "\n# Run partprobe so that the OS reads the new partition table to deal with above warning."
+puts "partprobe"
+`partprobe`
+
+# Get the names of the two newly created partitions.
+partition1, partition2 = get_partitions(clone_source_device)
+
+puts "\n# Making new files systems"
+a,b,c,d,e,label,uuid = tar_file_name_boot.gsub(/.tgz$/,"").split("_")
+# Set the uuid with the -i flag. i.e. "mkfs.vfat -n boot -i 52AA6867 #{partition1}"
+puts "#\n# Making boot partition with label '#{label}' with:"
+echo_and_run("mkfs.vfat -n #{label} #{partition1}")
+
+a,b,c,d,e,label,uuid = tar_file_name_root.gsub(/.tgz$/,"").split("_")
+puts "#\n# Making root partition with label '#{label}' and uuid '#{uuid}' with"
+puts "# The -F flag enables the force option."
+echo_and_run("mkfs.ext4 -F -L #{label} -U #{uuid} #{partition2}")
+
+puts "\n# Restoring backup to the boot partition."
+`mkdir /new` if ! Dir.exists?("/new")
+puts "# Make sure nothing is mounted on /new before mounting #{partition1} there."
+puts "# Here is df output to check to see if anything is mounted on /new."
+echo_and_run("df /new")
+puts "# Running unmount /new to make sure nothing is mounted there."
+echo_and_run("umount /new")
+mount(partition1,"/new")
+puts "# Using restore command:"
+echo_and_run("#{$time} tar --numeric-owner -xzf #{tar_file_name_boot} -C /new")
+umount(partition1)
+
+puts "\n# Restoring backup to the root partition."
+mount(partition2,"/new")
+puts "# Using restore command:"
+echo_and_run("#{$time} tar --numeric-owner -xzf #{tar_file_name_root} -C /new .")
+puts "# Sync the disks to flush writing the tar file."
+echo_and_run("#{$time} sync")
+umount(partition2)
+
+# On helium, I backed up the Master Boot Record, bootloader, and other
+# header files with:root[533] helium /backups/linux/helium
+# root@helium:# dd if=/dev/mmcblk1 of=/backups/linux/helium/20180902_helium_MBR.dd bs=512 count=8192
+# dd if=${DISK} of=${ODROID_DIR}/20180923_ODROID_XU4_9971_MBR.dd bs=512 count=2048
+
+# http://wiki.linuxquestions.org/wiki/Some_dd_examples
+# shows how to copy one disk to another while skipping the partition table.
+# seek=N skip N obs-sized blocks at start of output
+# skip=N skip N ibs-sized blocks at start of input
+
+
+# I wrote this with
+# root@gold:/tmp# dd if=20180902_helium_MBR.dd of=/dev/mmcblk0 bs=512
+#dd if=${ODROID_DIR}/20180923_ODROID_XU4_9971_MBR.dd skip=1 of=${DISK} seek=1 bs=512
+
+puts "\n# Restoring MBR (master boot record) to the beginning of the device."
+puts `ls -l #{dd_file_name_mbr}`
+puts "# Using restore command:"
+echo_and_run("#{$time} dd if=#{dd_file_name_mbr} skip=1 of=/dev/#{clone_source_device} seek=1 bs=512")
+
+$end_time = Time.now
+puts ""
+puts "Start time: #{$start_time}"
+puts " End time: #{$end_time}"
+puts "======================================"
+puts "Total time: #{time_to_minutes_and_seconds($end_time-$start_time)}"
+puts ""
+puts "# Done.\n"
diff --git a/tools/build_rules/label.bzl b/tools/build_rules/label.bzl
new file mode 100644
index 0000000..ff02327
--- /dev/null
+++ b/tools/build_rules/label.bzl
@@ -0,0 +1,5 @@
+# This file provides any necessary label abstractions since it doesn't seem like
+# Starlark provides them itself
+
+def expand_label(label):
+ return '%s' % label if ':' in label else '%s:%s' % (label, label.split('/')[-1])
diff --git a/y2012/BUILD b/y2012/BUILD
index 68dcc49..fd9119b 100644
--- a/y2012/BUILD
+++ b/y2012/BUILD
@@ -1,4 +1,4 @@
-load("//aos/downloader:downloader.bzl", "aos_downloader")
+load("//frc971:downloader.bzl", "robot_downloader")
cc_binary(
name = "joystick_reader",
@@ -19,18 +19,12 @@
],
)
-aos_downloader(
- name = "download",
- srcs = [
- "//aos:prime_binaries",
- ],
- restricted_to = ["//tools:roborio"],
- start_srcs = [
+robot_downloader(
+ start_binaries = [
":joystick_reader",
":wpilib_interface",
"//y2012/control_loops/drivetrain",
"//y2012/control_loops/accessories",
- "//aos:prime_start_binaries",
],
)
diff --git a/y2014/BUILD b/y2014/BUILD
index 28569d0..dfd2325 100644
--- a/y2014/BUILD
+++ b/y2014/BUILD
@@ -1,4 +1,4 @@
-load("//aos/downloader:downloader.bzl", "aos_downloader")
+load("//frc971:downloader.bzl", "robot_downloader")
cc_library(
name = "constants",
@@ -42,13 +42,8 @@
],
)
-aos_downloader(
- name = "download",
- srcs = [
- "//aos:prime_binaries",
- ],
- restricted_to = ["//tools:roborio"],
- start_srcs = [
+robot_downloader(
+ start_binaries = [
":hot_goal_reader",
":joystick_reader",
":wpilib_interface",
@@ -57,7 +52,6 @@
"//y2014/control_loops/shooter:shooter",
"//y2014/autonomous:auto",
"//y2014/actors:binaries",
- "//aos:prime_start_binaries",
],
)
diff --git a/y2014/actors/BUILD b/y2014/actors/BUILD
index 1b9cf8e..09eb3b0 100644
--- a/y2014/actors/BUILD
+++ b/y2014/actors/BUILD
@@ -10,6 +10,14 @@
],
)
+filegroup(
+ name = 'binaries.stripped',
+ srcs = [
+ ':drivetrain_action.stripped',
+ ':shoot_action.stripped',
+ ],
+)
+
queue_library(
name = 'shoot_action_queue',
srcs = [
diff --git a/y2014_bot3/BUILD b/y2014_bot3/BUILD
index 3654191..ea79dac 100644
--- a/y2014_bot3/BUILD
+++ b/y2014_bot3/BUILD
@@ -1,4 +1,4 @@
-load("//aos/downloader:downloader.bzl", "aos_downloader")
+load("//frc971:downloader.bzl", "robot_downloader")
cc_binary(
name = "joystick_reader",
@@ -19,19 +19,13 @@
],
)
-aos_downloader(
- name = "download_stripped",
- srcs = [
- "//aos:prime_binaries_stripped",
- ],
- restricted_to = ["//tools:roborio"],
- start_srcs = [
- ":joystick_reader.stripped",
- ":wpilib_interface.stripped",
- "//aos:prime_start_binaries_stripped",
- "//y2014_bot3/autonomous:auto.stripped",
- "//y2014_bot3/control_loops/drivetrain:drivetrain.stripped",
- "//y2014_bot3/control_loops/rollers:rollers.stripped",
+robot_downloader(
+ start_binaries = [
+ ":joystick_reader",
+ ":wpilib_interface",
+ "//y2014_bot3/autonomous:auto",
+ "//y2014_bot3/control_loops/drivetrain:drivetrain",
+ "//y2014_bot3/control_loops/rollers:rollers",
],
)
diff --git a/y2014_bot3/control_loops/drivetrain/drivetrain_base.cc b/y2014_bot3/control_loops/drivetrain/drivetrain_base.cc
index e39a99a..2daaf6a 100644
--- a/y2014_bot3/control_loops/drivetrain/drivetrain_base.cc
+++ b/y2014_bot3/control_loops/drivetrain/drivetrain_base.cc
@@ -20,7 +20,7 @@
const DrivetrainConfig<double> &GetDrivetrainConfig() {
static DrivetrainConfig<double> kDrivetrainConfig{
::frc971::control_loops::drivetrain::ShifterType::SIMPLE_SHIFTER,
- ::frc971::control_loops::drivetrain::LoopType::OPEN_LOOP,
+ ::frc971::control_loops::drivetrain::LoopType::CLOSED_LOOP,
::frc971::control_loops::drivetrain::GyroType::SPARTAN_GYRO,
::frc971::control_loops::drivetrain::IMUType::IMU_X,
@@ -36,7 +36,7 @@
// No shifter sensors, so we could put anything for the things below.
kThreeStateDriveShifter, kThreeStateDriveShifter,
false /* default_high_gear */, 0.0, 0.60 /* wheel_non_linearity */,
- 0.60 /* quickturn_wheel_multiplier */, 1.0 /* wheel_multiplier */,
+ 0.60 /* quickturn_wheel_multiplier */, 0.7 /* wheel_multiplier */,
};
return kDrivetrainConfig;
diff --git a/y2014_bot3/control_loops/drivetrain/drivetrain_base.h b/y2014_bot3/control_loops/drivetrain/drivetrain_base.h
index 36f8ddf..d41ff99 100644
--- a/y2014_bot3/control_loops/drivetrain/drivetrain_base.h
+++ b/y2014_bot3/control_loops/drivetrain/drivetrain_base.h
@@ -8,7 +8,7 @@
namespace drivetrain {
const double kDrivetrainEncoderRatio =
- (17.0 / 50.0) /*output reduction*/ * (24.0 / 64.0) /*encoder gears*/;
+ (17.0 / 50.0) /*output reduction*/ * (64.0 / 24.0) /*encoder gears*/;
const ::frc971::control_loops::drivetrain::DrivetrainConfig<double>
&GetDrivetrainConfig();
diff --git a/y2014_bot3/control_loops/python/drivetrain.py b/y2014_bot3/control_loops/python/drivetrain.py
index 93993c3..48510be 100755
--- a/y2014_bot3/control_loops/python/drivetrain.py
+++ b/y2014_bot3/control_loops/python/drivetrain.py
@@ -22,7 +22,7 @@
q_vel_high = 0.95,
has_imu = False,
dt = 0.005,
- controller_poles = [0.67, 0.67])
+ controller_poles = [0.83, 0.83])
def main(argv):
argv = FLAGS(argv)
diff --git a/y2014_bot3/wpilib_interface.cc b/y2014_bot3/wpilib_interface.cc
index 9f991c9..2b0edb5 100644
--- a/y2014_bot3/wpilib_interface.cc
+++ b/y2014_bot3/wpilib_interface.cc
@@ -114,9 +114,9 @@
{
auto drivetrain_message = drivetrain_queue.position.MakeMessage();
drivetrain_message->right_encoder =
- drivetrain_translate(drivetrain_right_encoder_->GetRaw());
+ -drivetrain_translate(drivetrain_right_encoder_->GetRaw());
drivetrain_message->left_encoder =
- -drivetrain_translate(drivetrain_left_encoder_->GetRaw());
+ drivetrain_translate(drivetrain_left_encoder_->GetRaw());
drivetrain_message->left_speed =
drivetrain_velocity_translate(drivetrain_left_encoder_->GetPeriod());
drivetrain_message->right_speed =
diff --git a/y2016/BUILD b/y2016/BUILD
index 3414331..c7622f8 100644
--- a/y2016/BUILD
+++ b/y2016/BUILD
@@ -1,4 +1,4 @@
-load("//aos/downloader:downloader.bzl", "aos_downloader")
+load('//frc971:downloader.bzl', 'robot_downloader')
cc_library(
name = "constants",
@@ -50,52 +50,22 @@
],
)
-aos_downloader(
- name = "download",
- srcs = [
- "//aos:prime_binaries",
- ],
- dirs = [
- "//y2016/dashboard:www_files",
- ],
- restricted_to = ["//tools:roborio"],
- start_srcs = [
- ":joystick_reader",
- ":wpilib_interface",
- "//aos:prime_start_binaries",
- "//y2016/control_loops/drivetrain:drivetrain",
- "//y2016/control_loops/superstructure:superstructure",
- "//y2016/control_loops/shooter:shooter",
- "//y2016/dashboard:dashboard",
- "//y2016/actors:autonomous_action",
- "//y2016/actors:superstructure_action",
- "//y2016/actors:vision_align_action",
- "//y2016/vision:target_receiver",
- ],
-)
-
-aos_downloader(
- name = "download_stripped",
- srcs = [
- "//aos:prime_binaries_stripped",
- ],
- dirs = [
- "//y2016/dashboard:www_files",
- ],
- restricted_to = ["//tools:roborio"],
- start_srcs = [
- ":joystick_reader.stripped",
- ":wpilib_interface.stripped",
- "//aos:prime_start_binaries_stripped",
- "//y2016/control_loops/drivetrain:drivetrain.stripped",
- "//y2016/control_loops/superstructure:superstructure.stripped",
- "//y2016/control_loops/shooter:shooter.stripped",
- "//y2016/dashboard:dashboard.stripped",
- "//y2016/actors:autonomous_action.stripped",
- "//y2016/actors:superstructure_action.stripped",
- "//y2016/actors:vision_align_action.stripped",
- "//y2016/vision:target_receiver.stripped",
- ],
+robot_downloader(
+ start_binaries = [
+ ':joystick_reader',
+ ':wpilib_interface',
+ '//y2016/control_loops/drivetrain:drivetrain',
+ '//y2016/control_loops/superstructure:superstructure',
+ '//y2016/control_loops/shooter:shooter',
+ '//y2016/dashboard:dashboard',
+ '//y2016/actors:autonomous_action',
+ '//y2016/actors:superstructure_action',
+ '//y2016/actors:vision_align_action',
+ '//y2016/vision:target_receiver',
+ ],
+ dirs = [
+ '//y2016/dashboard:www_files',
+ ],
)
cc_binary(
diff --git a/y2017/BUILD b/y2017/BUILD
index aa67a78..e002758 100644
--- a/y2017/BUILD
+++ b/y2017/BUILD
@@ -1,4 +1,4 @@
-load("//aos/downloader:downloader.bzl", "aos_downloader")
+load('//frc971:downloader.bzl', 'robot_downloader')
cc_library(
name = "constants",
@@ -85,38 +85,14 @@
],
)
-aos_downloader(
- name = "download",
- srcs = [
- "//aos:prime_binaries",
- ],
- restricted_to = ["//tools:roborio"],
- start_srcs = [
- ":joystick_reader",
- ":wpilib_interface",
- "//aos:prime_start_binaries",
- "//y2017/actors:autonomous_action",
- "//y2017/control_loops/drivetrain:drivetrain",
- "//y2017/control_loops/superstructure:superstructure",
- "//y2017/vision:target_receiver",
- ],
-)
-
-aos_downloader(
- name = "download_stripped",
- srcs = [
- "//aos:prime_binaries_stripped",
- ],
- restricted_to = ["//tools:roborio"],
- start_srcs = [
- ":joystick_reader.stripped",
- ":wpilib_interface.stripped",
- "//aos:prime_start_binaries_stripped",
- "//y2017/actors:autonomous_action.stripped",
- "//y2017/control_loops/drivetrain:drivetrain.stripped",
- "//y2017/control_loops/superstructure:superstructure.stripped",
- "//y2017/vision:target_receiver.stripped",
- ],
+robot_downloader(
+ start_binaries = [
+ ':joystick_reader',
+ ':wpilib_interface',
+ '//y2017/control_loops/drivetrain:drivetrain',
+ '//y2017/control_loops/superstructure:superstructure',
+ '//y2017/actors:autonomous_action',
+ ],
)
py_library(
diff --git a/y2018/BUILD b/y2018/BUILD
index 09d2bc9..6173702 100644
--- a/y2018/BUILD
+++ b/y2018/BUILD
@@ -1,41 +1,18 @@
-load("//aos/downloader:downloader.bzl", "aos_downloader")
+load("//frc971:downloader.bzl", "robot_downloader")
load("//aos/build:queues.bzl", "queue_library")
load("@com_google_protobuf//:protobuf.bzl", "cc_proto_library")
-aos_downloader(
- name = "download",
- srcs = [
- "//aos:prime_binaries",
- ],
- restricted_to = ["//tools:roborio"],
- start_srcs = [
+robot_downloader(
+ start_binaries = [
":joystick_reader",
":wpilib_interface",
"//y2018/vision:vision_status",
- "//aos:prime_start_binaries",
- "//y2018/control_loops/drivetrain:drivetrain",
"//y2018/actors:autonomous_action",
+ "//y2018/control_loops/drivetrain:drivetrain",
"//y2018/control_loops/superstructure:superstructure",
],
)
-aos_downloader(
- name = "download_stripped",
- srcs = [
- "//aos:prime_binaries_stripped",
- ],
- restricted_to = ["//tools:roborio"],
- start_srcs = [
- ":joystick_reader.stripped",
- ":wpilib_interface.stripped",
- "//y2018/vision:vision_status.stripped",
- "//aos:prime_start_binaries_stripped",
- "//y2018/actors:autonomous_action.stripped",
- "//y2018/control_loops/drivetrain:drivetrain.stripped",
- "//y2018/control_loops/superstructure:superstructure.stripped",
- ],
-)
-
cc_binary(
name = "joystick_reader",
srcs = [
diff --git a/y2018/control_loops/python/BUILD b/y2018/control_loops/python/BUILD
index d445f8a..2d2c4f1 100644
--- a/y2018/control_loops/python/BUILD
+++ b/y2018/control_loops/python/BUILD
@@ -169,9 +169,11 @@
],
default_python_version = "PY3",
legacy_create_init = False,
+ restricted_to = ["//tools:k8"],
srcs_version = "PY3",
deps = [
":python_init",
+ "@python_gtk",
],
)
diff --git a/y2018/control_loops/python/drivetrain.py b/y2018/control_loops/python/drivetrain.py
index 64217a0..6421379 100644
--- a/y2018/control_loops/python/drivetrain.py
+++ b/y2018/control_loops/python/drivetrain.py
@@ -30,6 +30,7 @@
force=True,
kf_q_voltage=13.0,
controller_poles=[0.82, 0.82],
+ robot_cg_offset=0.0,
)