Merge "Checking in blob routines."
diff --git a/aos/testing/gtest_main.cc b/aos/testing/gtest_main.cc
index ef63293..e2ba564 100644
--- a/aos/testing/gtest_main.cc
+++ b/aos/testing/gtest_main.cc
@@ -40,7 +40,8 @@
" -p, --print-logs\n"
" Print the log messages as they are being generated.\n"
" -o, --log-file=FILE\n"
- " Print all log messages to FILE instead of standard output\n"
+ " Print all log messages to FILE instead of standard output.\n"
+ " This implies -p.\n"
);
break;
@@ -51,6 +52,9 @@
break;
case 'o':
+ if (::aos::testing::ForcePrintLogsDuringTests) {
+ ::aos::testing::ForcePrintLogsDuringTests();
+ }
if (::aos::testing::SetLogFileName) {
::aos::testing::SetLogFileName(optarg);
}
diff --git a/tools/cpp/arm-frc-linux-gnueabi/libs/libc.so b/tools/cpp/arm-frc-linux-gnueabi/libs/libc.so
new file mode 100644
index 0000000..714bcfe
--- /dev/null
+++ b/tools/cpp/arm-frc-linux-gnueabi/libs/libc.so
@@ -0,0 +1,5 @@
+/* GNU ld script
+ Use the shared library, but some functions are only in
+ the static library, so try that secondarily. */
+OUTPUT_FORMAT(elf32-littlearm)
+GROUP ( libc.so.6 libc_nonshared.a AS_NEEDED ( ld-linux.so.3 ) )
diff --git a/tools/cpp/arm-frc-linux-gnueabi/libs/libpthread.so b/tools/cpp/arm-frc-linux-gnueabi/libs/libpthread.so
new file mode 100644
index 0000000..71f034f
--- /dev/null
+++ b/tools/cpp/arm-frc-linux-gnueabi/libs/libpthread.so
@@ -0,0 +1,5 @@
+/* GNU ld script
+ Use the shared library, but some functions are only in
+ the static library, so try that secondarily. */
+OUTPUT_FORMAT(elf32-littlearm)
+GROUP ( libpthread.so.0 libpthread_nonshared.a )
diff --git a/vm/README.md b/vm/README.md
new file mode 100644
index 0000000..03e8965
--- /dev/null
+++ b/vm/README.md
@@ -0,0 +1,64 @@
+Requirements
+--------------------------------------------------------------------------------
+1. Install Vagrant <https://www.vagrantup.com/downloads.html>
+
+1. Install VirtualBox <https://www.virtualbox.org/wiki/Downloads>
+
+1. Add `vagrant` and `VBoxManage` to your PATH.
+ - This is most likely already done by the installation binaries.
+ It's added to the system path.
+ - To test this, type these commands in a terminal:
+
+ ~$ vagrant --version
+ Vagrant 1.8.1
+ ~$ VBoxManage --version
+ 5.0.14r105127
+
+ - You may need to log out and back in for the path modifications to take
+ effect.
+
+1. On my Jessie installation I had to apply the following patch before I could
+ successfully shut down and reboot the VM.
+
+ --- /opt/vagrant/embedded/gems/gems/vagrant-1.7.4/plugins/guests/debian8/cap/halt.rb 2015-07-17 13:15:13.000000000 -0700
+ +++ new_halt.rb 2015-11-18 20:11:29.003055639 -0800
+ @@ -4,7 +4,7 @@
+ class Halt
+ def self.halt(machine)
+ begin
+ - machine.communicate.sudo("shutdown -h -H")
+ + machine.communicate.sudo("systemctl poweroff")
+ rescue IOError
+ # Do nothing, because it probably means the machine shut down
+ # and SSH connection was lost.
+
+Usage
+--------------------------------------------------------------------------------
+1. Check this folder out on your computer somewhere.
+
+ svn co https://robotics.mvla.net/svn/frc971/2016/trunk/src/vagrant_dev_vm
+
+1. Go into the directory and build the VM.
+
+ vagrant up
+
+1. Some errors during the `vagrant up` process can be addressed by
+ re-provisioning the vagrant box. This is useful if, for example, an
+ `apt-get` invocation timed out and caused the provisioning process to abort.
+
+ vagrant provision
+
+1. Once build, reboot the VM so it starts the GUI properly.
+
+ vagrant reload
+
+1. You can then log in and open a terminal. The username and password are both
+ `user`.
+
+1. Download the code and build it.
+
+ git clone https://USERNAME@robotics.mvla.net/gerrit/971-Robot-Code
+ cd 971-Robot-Code
+ bazel build //y2016/... -- $(cat NO_BUILD_AMD64)
+
+ where USERNAME is the same username you use to log into SVN.
diff --git a/vm/Vagrantfile b/vm/Vagrantfile
new file mode 100644
index 0000000..c802a5a
--- /dev/null
+++ b/vm/Vagrantfile
@@ -0,0 +1,57 @@
+# Vagrantfile API/syntax version. Don't touch unless you know what you're
+# doing!
+VAGRANTFILE_API_VERSION = "2"
+
+# Install the necessary plugins.
+required_plugins = %w( vagrant-persistent-storage )
+required_plugins.each do |plugin|
+ unless Vagrant.has_plugin? plugin || ARGV[0] == 'plugin' then
+ exec "vagrant plugin install #{plugin};vagrant #{ARGV.join(" ")}"
+ end
+end
+
+Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
+ # All Vagrant configuration is done here. The most common configuration
+ # options are documented and commented below. For a complete reference,
+ # please see the online documentation at vagrantup.com.
+
+ # Every Vagrant virtual environment requires a box to build off of.
+ config.vm.box = "debian/jessie64"
+
+ config.vm.provider "virtualbox" do |vb|
+ # Don't boot with headless mode
+ vb.gui = true
+ vb.name = "FRC971-Development-2016"
+
+ # There are two shortcuts for modifying number of CPUs and amount of
+ # memory. Modify them to your liking.
+ vb.cpus = 2
+ vb.memory = 1024 * 2
+ end
+
+ # Use rsync to sync the /vagrant folder.
+ # NOTE: If you change these settings they will not take effect until you
+ # reboot the VM -- i.e. run a "vagrant reload".
+ config.vm.synced_folder ".", "/vagrant", type: "rsync",
+ rsync__exclude: [".git/", ".svn/", "workspace.vdi"], rsync__verbose: true
+
+ # Set up apt and install packages necessary for building the code.
+ config.vm.provision :shell, inline: "/vagrant/setup_apt.sh"
+ config.vm.provision :shell, inline: "/vagrant/setup_extra_storage.sh"
+ config.vm.provision :shell, inline: "/vagrant/setup_code_building.sh"
+ config.vm.provision :shell, inline: "/vagrant/setup_scouting.sh"
+ config.vm.provision :shell, inline: "/vagrant/setup_desktop.sh"
+ config.vm.provision :shell, inline: "/vagrant/setup_misc_packages.sh"
+ config.vm.provision :shell, inline: "/vagrant/setup_vbox_guest_additions.sh"
+
+ # Add a second disk so we have plenty of space to compile the code.
+ config.persistent_storage.enabled = true
+ config.persistent_storage.location = "workspace.vdi"
+ config.persistent_storage.size = 40000 # MiB
+ config.persistent_storage.use_lvm = false
+ config.persistent_storage.filesystem = 'ext4'
+ config.persistent_storage.mountpoint = '/home/user'
+
+ # Forward the scouting app's port.
+ config.vm.network :forwarded_port, guest: 5000, host: 5000, auto_correct: true
+end
diff --git a/vm/setup_apt.sh b/vm/setup_apt.sh
new file mode 100755
index 0000000..d31a372
--- /dev/null
+++ b/vm/setup_apt.sh
@@ -0,0 +1,15 @@
+#!/usr/bin/env bash
+
+set -e
+set -u
+
+export DEBIAN_FRONTEND=noninteractive
+
+# Set up contrib and non-free so we can install some more interesting programs.
+cat > /etc/apt/sources.list.d/contrib.list <<EOT
+deb http://ftp.us.debian.org/debian/ jessie contrib non-free
+deb-src http://ftp.us.debian.org/debian/ jessie contrib non-free
+EOT
+
+# Get a list of the latest packages.
+apt-get update
diff --git a/vm/setup_code_building.sh b/vm/setup_code_building.sh
new file mode 100755
index 0000000..a27b60e
--- /dev/null
+++ b/vm/setup_code_building.sh
@@ -0,0 +1,56 @@
+#!/usr/bin/env bash
+
+set -e
+set -u
+
+export DEBIAN_FRONTEND=noninteractive
+
+readonly PKGS=(
+ bazel
+ clang-3.6
+ clang-format-3.5
+ gfortran
+ git
+ libblas-dev
+ liblapack-dev
+ libpython3-dev
+ libpython-dev
+ python3
+ python3-matplotlib
+ python3-numpy
+ python3-scipy
+ python-matplotlib
+ python-scipy
+ resolvconf
+ ruby
+)
+
+# Set up the backports repo.
+cat > /etc/apt/sources.list.d/backports.list <<EOT
+deb http://http.debian.net/debian jessie-backports main
+EOT
+
+# Set up the LLVM repo.
+cat > /etc/apt/sources.list.d/llvm-3.6.list <<EOT
+deb http://llvm.org/apt/jessie/ llvm-toolchain-jessie-3.6 main
+deb-src http://llvm.org/apt/jessie/ llvm-toolchain-jessie-3.6 main
+EOT
+
+# Set up the 971-managed bazel repo.
+cat > /etc/apt/sources.list.d/bazel-971.list <<EOT
+deb http://robotics.mvla.net/files/frc971/packages jessie main
+EOT
+
+# Enable user namespace for sandboxing.
+cat > /etc/sysctl.d/99-enable-user-namespaces.conf <<EOT
+kernel.unprivileged_userns_clone = 1
+EOT
+
+# Accept the LLVM GPG key so we can install their packages.
+wget -O - http://llvm.org/apt/llvm-snapshot.gpg.key | apt-key add -
+
+# Install all the packages that we need/want.
+apt-get update
+for pkg in "${PKGS[@]}"; do
+ apt-get install -y -f --force-yes "$pkg"
+done
diff --git a/vm/setup_desktop.sh b/vm/setup_desktop.sh
new file mode 100755
index 0000000..d713856
--- /dev/null
+++ b/vm/setup_desktop.sh
@@ -0,0 +1,19 @@
+#!/usr/bin/env bash
+
+set -e
+set -u
+
+export DEBIAN_FRONTEND=noninteractive
+
+readonly PKGS=(
+ iceweasel
+ lightdm
+ mousepad
+ xfce4
+ xfce4-terminal
+)
+
+# Install all the packages that we need/want.
+for pkg in "${PKGS[@]}"; do
+ apt-get install -y -f "$pkg"
+done
diff --git a/vm/setup_extra_storage.sh b/vm/setup_extra_storage.sh
new file mode 100755
index 0000000..5fcf4cb
--- /dev/null
+++ b/vm/setup_extra_storage.sh
@@ -0,0 +1,19 @@
+#!/usr/bin/env bash
+
+set -e
+set -u
+
+readonly EXTRA_USER=user
+readonly EXTRA_STORAGE=/home/"${EXTRA_USER}"
+
+if ! grep -q "$EXTRA_STORAGE" /etc/passwd; then
+ PASSWORD="$(echo "$EXTRA_USER" | mkpasswd -s)"
+ useradd \
+ --home="$EXTRA_STORAGE" -M \
+ --password="$PASSWORD" \
+ --shell=/bin/bash \
+ "$EXTRA_USER"
+ chown "$EXTRA_USER:$EXTRA_USER" "$EXTRA_STORAGE"
+fi
+
+usermod -a -G sudo "$EXTRA_USER"
diff --git a/vm/setup_misc_packages.sh b/vm/setup_misc_packages.sh
new file mode 100755
index 0000000..691b2be
--- /dev/null
+++ b/vm/setup_misc_packages.sh
@@ -0,0 +1,17 @@
+#!/usr/bin/env bash
+
+set -e
+set -u
+
+export DEBIAN_FRONTEND=noninteractive
+
+readonly PKGS=(
+ colordiff
+ tmux
+ vim
+)
+
+# Install all the packages that we want.
+for pkg in "${PKGS[@]}"; do
+ apt-get install -y -f "$pkg"
+done
diff --git a/vm/setup_scouting.sh b/vm/setup_scouting.sh
new file mode 100755
index 0000000..3360ff5
--- /dev/null
+++ b/vm/setup_scouting.sh
@@ -0,0 +1,17 @@
+#!/usr/bin/env bash
+
+set -e
+set -u
+
+export DEBIAN_FRONTEND=noninteractive
+
+readonly PKGS=(
+ python3
+ python3-flask
+)
+
+# Install all the packages that we need/want.
+apt-get update
+for pkg in "${PKGS[@]}"; do
+ apt-get install -y -f --force-yes "$pkg"
+done
diff --git a/vm/setup_vbox_guest_additions.sh b/vm/setup_vbox_guest_additions.sh
new file mode 100755
index 0000000..c9f4b09
--- /dev/null
+++ b/vm/setup_vbox_guest_additions.sh
@@ -0,0 +1,15 @@
+#!/usr/bin/env bash
+
+set -e
+set -u
+
+export DEBIAN_FRONTEND=noninteractive
+
+# Install the kernel sources before the guest additions to guarantee that
+# we can compile the kernel module.
+apt-get install -q -y linux-headers-amd64
+
+# Now we can install the guest additions.
+apt-get install -q -y \
+ virtualbox-guest-dkms \
+ virtualbox-guest-x11
diff --git a/y2017/BUILD b/y2017/BUILD
new file mode 100644
index 0000000..aa423a8
--- /dev/null
+++ b/y2017/BUILD
@@ -0,0 +1,17 @@
+cc_library(
+ name = 'constants',
+ visibility = ['//visibility:public'],
+ srcs = [
+ 'constants.cc',
+ ],
+ hdrs = [
+ 'constants.h',
+ ],
+ deps = [
+ '//aos/common/logging',
+ '//aos/common:once',
+ '//aos/common/network:team_number',
+ '//aos/common:mutex',
+ '//frc971:constants',
+ ],
+)
diff --git a/y2017/actors/BUILD b/y2017/actors/BUILD
new file mode 100644
index 0000000..6766422
--- /dev/null
+++ b/y2017/actors/BUILD
@@ -0,0 +1,50 @@
+package(default_visibility = ['//visibility:public'])
+
+load('/aos/build/queues', 'queue_library')
+
+filegroup(
+ name = 'binaries',
+ srcs = [
+ ':autonomous_action',
+ ],
+)
+
+queue_library(
+ name = 'autonomous_action_queue',
+ srcs = [
+ 'autonomous_action.q',
+ ],
+ deps = [
+ '//aos/common/actions:action_queue',
+ ],
+)
+
+cc_library(
+ name = 'autonomous_action_lib',
+ srcs = [
+ 'autonomous_actor.cc',
+ ],
+ hdrs = [
+ 'autonomous_actor.h',
+ ],
+ deps = [
+ ':autonomous_action_queue',
+ '//aos/common/util:phased_loop',
+ '//aos/common/logging',
+ '//aos/common/actions:action_lib',
+ '//frc971/control_loops/drivetrain:drivetrain_queue',
+ '//frc971/control_loops/drivetrain:drivetrain_config',
+ ],
+)
+
+cc_binary(
+ name = 'autonomous_action',
+ srcs = [
+ 'autonomous_actor_main.cc',
+ ],
+ deps = [
+ ':autonomous_action_lib',
+ ':autonomous_action_queue',
+ '//aos/linux_code:init',
+ ],
+)
\ No newline at end of file
diff --git a/y2017/actors/autonomous_action.q b/y2017/actors/autonomous_action.q
new file mode 100644
index 0000000..52873ca
--- /dev/null
+++ b/y2017/actors/autonomous_action.q
@@ -0,0 +1,29 @@
+package y2017.actors;
+
+import "aos/common/actions/actions.q";
+
+message AutonomousMode {
+ // Mode read from the mode setting sensors.
+ int32_t mode;
+};
+
+queue AutonomousMode auto_mode;
+
+struct AutonomousActionParams {
+ // The mode from the sensors when auto starts.
+ int32_t mode;
+};
+
+queue_group AutonomousActionQueueGroup {
+ implements aos.common.actions.ActionQueueGroup;
+
+ message Goal {
+ uint32_t run;
+ AutonomousActionParams params;
+ };
+
+ queue Goal goal;
+ queue aos.common.actions.Status status;
+};
+
+queue_group AutonomousActionQueueGroup autonomous_action;
diff --git a/y2017/actors/autonomous_actor.cc b/y2017/actors/autonomous_actor.cc
new file mode 100644
index 0000000..ad4b87c
--- /dev/null
+++ b/y2017/actors/autonomous_actor.cc
@@ -0,0 +1,82 @@
+#include "y2017/actors/autonomous_actor.h"
+
+#include <inttypes.h>
+
+#include <chrono>
+#include <cmath>
+
+#include "aos/common/util/phased_loop.h"
+#include "aos/common/logging/logging.h"
+
+#include "frc971/control_loops/drivetrain/drivetrain.q.h"
+#include "y2017/actors/autonomous_action.q.h"
+
+namespace y2017 {
+namespace actors {
+using ::frc971::control_loops::drivetrain_queue;
+using ::aos::monotonic_clock;
+namespace chrono = ::std::chrono;
+namespace this_thread = ::std::this_thread;
+
+namespace {
+double DoubleSeconds(monotonic_clock::duration duration) {
+ return ::std::chrono::duration_cast<::std::chrono::duration<double>>(duration)
+ .count();
+}
+} // namespace
+
+AutonomousActor::AutonomousActor(actors::AutonomousActionQueueGroup *s)
+ : aos::common::actions::ActorBase<actors::AutonomousActionQueueGroup>(s) {}
+
+void AutonomousActor::WaitUntilDoneOrCanceled(
+ ::std::unique_ptr<aos::common::actions::Action> action) {
+ if (!action) {
+ LOG(ERROR, "No action, not waiting\n");
+ return;
+ }
+
+ ::aos::time::PhasedLoop phased_loop(::std::chrono::milliseconds(5),
+ ::std::chrono::milliseconds(5) / 2);
+ while (true) {
+ // Poll the running bit and see if we should cancel.
+ phased_loop.SleepUntilNext();
+ if (!action->Running() || ShouldCancel()) {
+ return;
+ }
+ }
+}
+
+bool AutonomousActor::RunAction(const actors::AutonomousActionParams ¶ms) {
+ monotonic_clock::time_point start_time = monotonic_clock::now();
+ LOG(INFO, "Starting autonomous action with mode %" PRId32 "\n", params.mode);
+
+ switch (params.mode) {
+ case 0:
+ break;
+
+ default:
+ LOG(ERROR, "Invalid auto mode %d\n", params.mode);
+ return true;
+ }
+
+ LOG(INFO, "Done %f\n", DoubleSeconds(monotonic_clock::now() - start_time));
+
+ ::aos::time::PhasedLoop phased_loop(::std::chrono::milliseconds(5),
+ ::std::chrono::milliseconds(5) / 2);
+
+ while (!ShouldCancel()) {
+ phased_loop.SleepUntilNext();
+ }
+ LOG(DEBUG, "Done running\n");
+
+ return true;
+}
+
+::std::unique_ptr<AutonomousAction> MakeAutonomousAction(
+ const ::y2017::actors::AutonomousActionParams ¶ms) {
+ return ::std::unique_ptr<AutonomousAction>(
+ new AutonomousAction(&::y2017::actors::autonomous_action, params));
+}
+
+} // namespace actors
+} // namespace y2017
diff --git a/y2017/actors/autonomous_actor.h b/y2017/actors/autonomous_actor.h
new file mode 100644
index 0000000..ef63b8e
--- /dev/null
+++ b/y2017/actors/autonomous_actor.h
@@ -0,0 +1,38 @@
+#ifndef Y2017_ACTORS_AUTONOMOUS_ACTOR_H_
+#define Y2017_ACTORS_AUTONOMOUS_ACTOR_H_
+
+#include <chrono>
+#include <memory>
+
+#include "aos/common/actions/actions.h"
+#include "aos/common/actions/actor.h"
+#include "frc971/control_loops/drivetrain/drivetrain.q.h"
+#include "frc971/control_loops/drivetrain/drivetrain_config.h"
+#include "y2017/actors/autonomous_action.q.h"
+
+namespace y2017 {
+namespace actors {
+using ::frc971::ProfileParameters;
+
+class AutonomousActor
+ : public ::aos::common::actions::ActorBase<AutonomousActionQueueGroup> {
+ public:
+ explicit AutonomousActor(AutonomousActionQueueGroup *s);
+
+ bool RunAction(const actors::AutonomousActionParams ¶ms) override;
+ private:
+ void WaitUntilDoneOrCanceled(::std::unique_ptr<aos::common::actions::Action>
+ action);
+};
+
+typedef ::aos::common::actions::TypedAction<AutonomousActionQueueGroup>
+ AutonomousAction;
+
+// Makes a new AutonomousActor action.
+::std::unique_ptr<AutonomousAction> MakeAutonomousAction(
+ const ::y2017::actors::AutonomousActionParams ¶ms);
+
+} // namespace actors
+} // namespace y2017
+
+#endif // Y2017_ACTORS_AUTONOMOUS_ACTOR_H_
diff --git a/y2017/actors/autonomous_actor_main.cc b/y2017/actors/autonomous_actor_main.cc
new file mode 100644
index 0000000..21c7e7a
--- /dev/null
+++ b/y2017/actors/autonomous_actor_main.cc
@@ -0,0 +1,16 @@
+#include <stdio.h>
+
+#include "aos/linux_code/init.h"
+#include "y2017/actors/autonomous_action.q.h"
+#include "y2017/actors/autonomous_actor.h"
+
+int main(int /*argc*/, char * /*argv*/ []) {
+ ::aos::Init(-1);
+
+ ::y2017::actors::AutonomousActor autonomous(
+ &::y2017::actors::autonomous_action);
+ autonomous.Run();
+
+ ::aos::Cleanup();
+ return 0;
+}
diff --git a/y2017/constants.cc b/y2017/constants.cc
new file mode 100644
index 0000000..33deee3
--- /dev/null
+++ b/y2017/constants.cc
@@ -0,0 +1,92 @@
+#include "y2017/constants.h"
+
+#include <math.h>
+#include <stdint.h>
+#include <inttypes.h>
+
+#include <map>
+
+#if __has_feature(address_sanitizer)
+#include "sanitizer/lsan_interface.h"
+#endif
+
+#include "aos/common/logging/logging.h"
+#include "aos/common/once.h"
+#include "aos/common/network/team_number.h"
+#include "aos/common/mutex.h"
+
+#ifndef M_PI
+#define M_PI 3.14159265358979323846
+#endif
+
+namespace y2017 {
+namespace constants {
+
+// ///// Mutual constants between robots. /////
+const int Values::kZeroingSampleSize;
+
+constexpr double Values::kDrivetrainEncoderRatio;
+
+namespace {
+const uint16_t kCompTeamNumber = 971;
+const uint16_t kPracticeTeamNumber = 9971;
+
+// ///// Dynamic constants. /////
+
+const Values *DoGetValuesForTeam(uint16_t team) {
+ switch (team) {
+ case 1: // for tests
+ return new Values{
+ 5.0, // drivetrain max speed
+ };
+ break;
+
+ case kCompTeamNumber:
+ return new Values{
+ 5.0, // drivetrain max speed
+ };
+ break;
+
+ case kPracticeTeamNumber:
+ return new Values{
+ 5.0, // drivetrain max speed
+ };
+ break;
+
+ default:
+ LOG(FATAL, "unknown team #%" PRIu16 "\n", team);
+ }
+}
+
+const Values *DoGetValues() {
+ uint16_t team = ::aos::network::GetTeamNumber();
+ LOG(INFO, "creating a Constants for team %" PRIu16 "\n", team);
+ return DoGetValuesForTeam(team);
+}
+
+} // namespace
+
+const Values &GetValues() {
+ static ::aos::Once<const Values> once(DoGetValues);
+ return *once.Get();
+}
+
+const Values &GetValuesForTeam(uint16_t team_number) {
+ static ::aos::Mutex mutex;
+ ::aos::MutexLocker locker(&mutex);
+
+ // IMPORTANT: This declaration has to stay after the mutex is locked to avoid
+ // race conditions.
+ static ::std::map<uint16_t, const Values *> values;
+
+ if (values.count(team_number) == 0) {
+ values[team_number] = DoGetValuesForTeam(team_number);
+#if __has_feature(address_sanitizer)
+ __lsan_ignore_object(values[team_number]);
+#endif
+ }
+ return *values[team_number];
+}
+
+} // namespace constants
+} // namespace y2017
diff --git a/y2017/constants.h b/y2017/constants.h
new file mode 100644
index 0000000..be29a2a
--- /dev/null
+++ b/y2017/constants.h
@@ -0,0 +1,41 @@
+#ifndef Y2017_CONSTANTS_H_
+#define Y2017_CONSTANTS_H_
+
+#include <stdint.h>
+
+namespace y2017 {
+namespace constants {
+
+// Has all of the numbers that change for both robots and makes it easy to
+// retrieve the values for the current one.
+
+// Everything is in SI units (volts, radians, meters, seconds, etc).
+// Some of these values are related to the conversion between raw values
+// (encoder counts, voltage, etc) to scaled units (radians, meters, etc).
+
+// This structure contains current values for all of the things that change.
+struct Values {
+ // ///// Mutual constants between robots. /////
+ // TODO(constants): Update/check these with what we're using this year.
+ static const int kZeroingSampleSize = 200;
+
+ // The ratio from the encoder shaft to the drivetrain wheels.
+ static constexpr double kDrivetrainEncoderRatio =
+ (18.0 / 36.0) /*output reduction*/ * (44.0 / 30.0) /*encoder gears*/;
+
+ // ///// Dynamic constants. /////
+ double drivetrain_max_speed;
+};
+
+// Creates (once) a Values instance for ::aos::network::GetTeamNumber() and
+// returns a reference to it.
+const Values &GetValues();
+
+// Creates Values instances for each team number it is called with and returns
+// them.
+const Values &GetValuesForTeam(uint16_t team_number);
+
+} // namespace constants
+} // namespace y2017
+
+#endif // Y2017_CONSTANTS_H_