Add some tutorial articles
Documentation can build built into html for example using
`bazel build //documentation/...`
To build a specific file run `bazel build
//documentation/tutorials:make-a-drivebase-move`
Change-Id: Ie8c09cfeb60593e18349c8889f0c19e2c6a178e2
diff --git a/debian/pandoc.BUILD b/debian/pandoc.BUILD
index 7e3084e..238c786 100644
--- a/debian/pandoc.BUILD
+++ b/debian/pandoc.BUILD
@@ -1,6 +1,6 @@
genrule(
name = "gen_wrapper",
- outs = ["pandoc_wrapper"],
+ outs = ["pandoc_wrapper.sh"],
cmd = "\n".join([
"cat > $@ <<END",
"#!/bin/bash",
@@ -11,10 +11,16 @@
executable = True,
)
+sh_binary(
+ name = "pandoc_wrapper",
+ srcs = [":pandoc_wrapper.sh"],
+ data = glob(["**"]),
+ visibility = ["//visibility:public"],
+)
+
filegroup(
name = "pandoc",
- srcs = ["pandoc_wrapper"],
- data = glob(["**"]),
+ srcs = ["pandoc_wrapper.sh"],
visibility = ["//visibility:public"],
)
diff --git a/documentation/BUILD b/documentation/BUILD
new file mode 100644
index 0000000..569ce64
--- /dev/null
+++ b/documentation/BUILD
@@ -0,0 +1,6 @@
+load("//tools/build_rules:pandoc.bzl", "pandoc_html")
+
+pandoc_html(
+ name = "index",
+ src = "README.md",
+)
diff --git a/documentation/README.md b/documentation/README.md
new file mode 100644
index 0000000..4dfff4d
--- /dev/null
+++ b/documentation/README.md
@@ -0,0 +1,15 @@
+# Robot Code Documentation
+This folder contains reference material for how to write robot code, organized
+as a set of markdown files.
+
+
+# Tutorials Index
+* [Create a new robot folder](tutorials/create-a-new-robot.html)
+* [Writing a program that runs a motor](tutorials/create-a-simple-program-for-running-a-motor.html)
+* [Download code to the robot](tutorials/download-code-to-the-robot.html)
+* [Make a drivebase move](tutorials/make-a-drivebase-move.html)
+* [Send and receive messages on a queue](tutorials/send-and-receive-messages-on-queues.html)
+* [Submitting code for review](tutorials/submitting-code-for-a-review.html)
+* [Create a new autonomous routine](tutorials/create-a-new-autonomous.html)
+* [Tune an autonomous](tutorials/tune-an-autonomous.html)
+* [Generated queue code](tutorials/generated-queue-code.html)
diff --git a/documentation/tutorials/BUILD b/documentation/tutorials/BUILD
new file mode 100644
index 0000000..13516c1
--- /dev/null
+++ b/documentation/tutorials/BUILD
@@ -0,0 +1,19 @@
+load("//tools/build_rules:pandoc.bzl", "pandoc_html")
+
+articles = [
+ "create-a-new-autonomous",
+ "create-a-new-robot",
+ "create-a-simple-program-for-running-a-motor",
+ "download-code-to-the-robot",
+ "make-a-drivebase-move",
+ "send-and-receive-messages-on-queues",
+ "submitting-code-for-a-review",
+ "tune-an-autonomous",
+ "generated-queue-code",
+ "using-bazel",
+]
+
+[pandoc_html(
+ name = article_name,
+ src = article_name + ".md",
+) for article_name in articles]
diff --git a/documentation/tutorials/create-a-new-autonomous.md b/documentation/tutorials/create-a-new-autonomous.md
new file mode 100644
index 0000000..68ddb60
--- /dev/null
+++ b/documentation/tutorials/create-a-new-autonomous.md
@@ -0,0 +1,2 @@
+# How to create a new autonomous
+TODO
diff --git a/documentation/tutorials/create-a-new-robot.md b/documentation/tutorials/create-a-new-robot.md
new file mode 100644
index 0000000..e746975
--- /dev/null
+++ b/documentation/tutorials/create-a-new-robot.md
@@ -0,0 +1,2 @@
+# How to create a new robot folder
+TODO
diff --git a/documentation/tutorials/create-a-simple-program-for-running-a-motor.md b/documentation/tutorials/create-a-simple-program-for-running-a-motor.md
new file mode 100644
index 0000000..f19d85c
--- /dev/null
+++ b/documentation/tutorials/create-a-simple-program-for-running-a-motor.md
@@ -0,0 +1,2 @@
+# How to create a simple program for running a motor
+TODO
diff --git a/documentation/tutorials/download-code-to-the-robot.md b/documentation/tutorials/download-code-to-the-robot.md
new file mode 100644
index 0000000..4f667cc
--- /dev/null
+++ b/documentation/tutorials/download-code-to-the-robot.md
@@ -0,0 +1,30 @@
+# How to download the code to a robot if you have a working code computer
+
+## Prerequisites
+1. Have a computer that has already built the code. See //:README.md for
+ directions on how to do this.
+
+2. TODO: Physical setup instructions (ethernet cables, router, driver station).
+
+3. TODO: Networking instructions (static ip address on ethernet without losing
+ wireless networking, mDNS information).
+
+
+
+## Downloading the code
+
+1. Make sure that you can connect to the roboRIO.
+```console
+ssh admin@roboRIO-971-frc.local /bin/true
+```
+
+2. Download the code
+```console
+bazel run --cpu=roborio --compilation_mode=opt //y2018:download -- admin@roboRIO-971-frc.local
+```
+
+3. TODO: How to run the code using the driver station.
+
+## Troubleshooting
+* If step 1 fails, you probably are not connected properly to the roboRIO.
+ Double check prerequisites 1 and 2.
diff --git a/documentation/tutorials/generated-queue-code.md b/documentation/tutorials/generated-queue-code.md
new file mode 100644
index 0000000..8f00a31
--- /dev/null
+++ b/documentation/tutorials/generated-queue-code.md
@@ -0,0 +1,246 @@
+# Generated queue code
+
+This tutorial covers what the code that is generated from a .q file looks like.
+
+### The basics
+Each `.q` file generates a `.cc` and `.h` pair that can be #include'd in your c++
+code.
+
+We're going to use `//frc971/queues:gyro.q` as our example.
+
+## Package declaration
+`.q` files usually start with a `package` declaration. The `package` declaration
+directly converts to a set of namespace declarations. So
+
+```cpp
+package frc971.sensors;
+```
+
+generates the namespace definitions
+
+```cpp
+namespace frc971 {
+namespace sensors {
+
+// All of the code for the queue
+
+} // namespace sensors
+} // namespace frc971
+```
+
+## Message declarations
+Each message declared in the queue generates a class that can be instantiated in
+your code easily.
+
+For a simple example, lets use the `Uid` message in `//frc971/queues:gyro.q`:
+
+```cpp
+message Uid {
+ uint32_t uid;
+};
+```
+
+Let's take a look at the actual class definition that is created. If you ever
+want to inspect the code that is generated from a .q file, you can take a look
+in `bazel-genfiles` after you build your code. So after running `bazel build
+//frc971/queues:gyro` there will be a `bazel-genfiles/frc971/queues/gyro.q.h`
+and `bazel-genfiles/frc971/queues/gyro.q.cc`.
+
+Here's the definition of the `Uid` class from
+`bazel-genfiles/frc971/queues/gyro.q.h` (comments mine):
+
+```cpp
+struct Uid : public ::aos::Message {
+ // Used to identify queues uniquely even if they have the same name.
+ enum { kQueueLength = 100, kHash = 0x0837c541 };
+
+ // The actual data that we requested be part of the message.
+ uint32_t uid;
+
+ // Writes the message to a byte buffer.
+ size_t Serialize(char *buffer) const;
+ // Reads the message from a byte buffer.
+ size_t Deserialize(const char *buffer);
+ // Zeroes all of the fields in the message.
+ void Zero();
+ // Returns the size of message. Not used
+ static size_t Size() { return 4 + ::aos::Message::Size(); }
+ // Prints the contents of the message to a string that is human readable.
+ size_t Print(char *buffer, size_t length) const;
+
+ // Gets information about this message's type.
+ static const ::aos::MessageType *GetType();
+ static const ::aos::MessageType *DoGetType();
+
+ // Default constructor, zeroes the struct.
+ Uid();
+ // Value constructor, sets the data at construction.
+ Uid(uint32_t uid_in);
+ bool EqualsNoTime(const Uid &other) const;
+};
+```
+
+## Queue declarations
+Every `queue` declaration in the `.q` file creates an `aos::Queue` variable that
+uses the message type given. So the declaration
+
+```cpp
+queue Uid gyro_part_id;
+```
+
+will generate a variable in `gyro.q.h`
+
+```cpp
+static UNUSED_VARIABLE::aos::Queue<Uid> &gyro_part_id;
+```
+
+which can then be used in any file that includes the header file.
+
+
+## QueueGroup declarations
+
+`queue_group` declares a set of queues and some associated helpers for them.
+There are two kinds of `queue_groups`, declarations and aliases. Here's an
+example of a `queue_group` definition:
+
+```cpp
+queue_group SuperstructureQueue {
+ implements aos.control_loops.ControlLoop;
+
+ message Goal {
+ IntakeGoal intake;
+
+ // Used to identify a position in the planned set of positions on the arm.
+ uint32_t arm_goal_position;
+ // If true, start the grab box sequence.
+ bool grab_box;
+
+ bool open_claw;
+ bool close_claw;
+
+ bool deploy_fork;
+
+ bool hook_release;
+
+ double voltage_winch;
+
+ double open_threshold;
+
+ bool disable_box_correct;
+
+ bool trajectory_override;
+ };
+
+ message Status {
+ // Are all the subsystems zeroed?
+ bool zeroed;
+
+ // If true, any of the subsystems have aborted.
+ bool estopped;
+
+ // Status of both intake sides.
+ IntakeSideStatus left_intake;
+ IntakeSideStatus right_intake;
+
+ ArmStatus arm;
+
+ double filtered_box_velocity;
+ uint32_t rotation_state;
+ };
+
+ message Position {
+ // Values of the series elastic encoders on the left side of the robot from
+ // the rear perspective in radians.
+ IntakeElasticSensors left_intake;
+
+ // Values of the series elastic encoders on the right side of the robot from
+ // the rear perspective in radians.
+ IntakeElasticSensors right_intake;
+
+ ArmPosition arm;
+
+ // Value of the beam breaker sensor. This value is true if the beam is
+ // broken, false if the beam isn't broken.
+ bool claw_beambreak_triggered;
+ // Value of the beambreak sensor detecting when the box has hit the frame
+ // cutout.
+ bool box_back_beambreak_triggered;
+
+ // Distance to the box in meters.
+ double box_distance;
+ };
+
+ message Output {
+ // Voltage sent to the parts on the left side of the intake.
+ IntakeVoltage left_intake;
+
+ // Voltage sent to the parts on the right side of the intake.
+ IntakeVoltage right_intake;
+
+ // Voltage sent to the motors on the proximal joint of the arm.
+ double voltage_proximal;
+
+ // Voltage sent to the motors on the distal joint of the arm.
+ double voltage_distal;
+
+ // Voltage sent to the hanger. Positive pulls the robot up.
+ double voltage_winch;
+
+ // Clamped (when true) or unclamped (when false) status sent to the
+ // pneumatic claw on the arm.
+ bool claw_grabbed;
+
+ // If true, release the arm brakes.
+ bool release_arm_brake;
+ // If true, release the hook
+ bool hook_release;
+ // If true, release the forks
+ bool forks_release;
+ };
+
+ queue Goal goal;
+ queue Output output;
+ queue Status status;
+ queue Position position;
+};
+```
+
+and aliases look like:
+
+```cpp
+queue_group SuperstructureQueue superstructure_queue;
+```
+
+The declaration type creates the definition of the queue group and what messages
+and queues it contains. The alias type creates a variable with the given name.
+
+This queue group results in the following code in
+`bazel-genfiles/y2018/control_loops/superstructure/superstructure.q.h`
+
+```cpp
+
+struct SuperstructureQueue_Goal : public ::aos::Message { /* ... */ }
+struct SuperstructureQueue_Output : public ::aos::Message { /* ... */ }
+struct SuperstructureQueue_Status : public ::aos::Message { /* ... */ }
+struct SuperstructureQueue_Position : public ::aos::Message { /* ... */ }
+class SuperstructureQueue : public ::aos::QueueGroup {
+ public:
+ typedef SuperstructureQueue_Goal Goal;
+ ::aos::Queue<SuperstructureQueue_Goal> goal;
+ typedef SuperstructureQueue_Output Output;
+ ::aos::Queue<SuperstructureQueue_Output> output;
+ typedef SuperstructureQueue_Status Status;
+ ::aos::Queue<SuperstructureQueue_Status> status;
+ typedef SuperstructureQueue_Position Position;
+ ::aos::Queue<SuperstructureQueue_Position> position;
+ SuperstructureQueue(const char *name, uint32_t hash, const char *goal_name,
+ const char *output_name, const char *status_name,
+ const char *position_name);
+};
+```
+
+and a definition of a variable:
+
+```cpp
+static UNUSED_VARIABLE SuperstructureQueue &superstructure_queue;
+```
diff --git a/documentation/tutorials/make-a-drivebase-move.md b/documentation/tutorials/make-a-drivebase-move.md
new file mode 100644
index 0000000..716a12b
--- /dev/null
+++ b/documentation/tutorials/make-a-drivebase-move.md
@@ -0,0 +1,2 @@
+# How to make a drivebase move
+TODO
diff --git a/documentation/tutorials/send-and-receive-messages-on-queues.md b/documentation/tutorials/send-and-receive-messages-on-queues.md
new file mode 100644
index 0000000..bcdaac1
--- /dev/null
+++ b/documentation/tutorials/send-and-receive-messages-on-queues.md
@@ -0,0 +1,74 @@
+# How to send and receive messages on a Queue
+
+Let's say we have a `//y2018:basic_queue.q` file that has the following
+contents:
+
+```cpp
+package y2018;
+
+message BasicMessage {
+ float value;
+};
+
+queue BasicMessage basic_queue;
+```
+
+and the corresponding entry in `//y2018/BUILD`
+
+```python
+queue_library(
+ name = "basic_queue",
+ srcs = [
+ "basic_queue.q",
+ ],
+ visibility = ["//visibility:public"],
+)
+```
+
+The following examples assume that you've declared a dependency on
+`//y2018:basic_queue` in the relevant `BUILD` file.
+
+## Sending a message
+First, include the queue definition that is created from the `.q` file. This
+will make the `basic_queue` variable available.
+
+```cpp
+#include "y2018/basic_queue.q.h"
+```
+
+```cpp
+
+// Allocate a new message pointer to use. basic_queue is from the include
+// statement.
+auto new_basic_message = basic_queue.MakeMessage();
+new_goal.value = 0.5;
+
+// Send the message on the queue
+if (!new_basic_message.Send()) {
+ LOG(ERROR, "Failed to send.\n");
+}
+```
+
+## Receiving a message
+
+Once again, we must include the queue header file to get access to the queue.
+
+
+```cpp
+#include "y2018/basic_queue.q.h"
+```
+
+Then we can receive a message.
+
+
+```cpp
+basic_queue.FetchLatest();
+if (basic_queue.get()) {
+ // We have a valid message ready to be used
+ LOG(INFO, "Got a BasicMessage from basic_queue with value %f\n",
+ basic_queue->value);
+} else {
+ // No new message was available
+ LOG(ERROR, "No message was received\n");
+}
+```
diff --git a/documentation/tutorials/submitting-code-for-a-review.md b/documentation/tutorials/submitting-code-for-a-review.md
new file mode 100644
index 0000000..414345c
--- /dev/null
+++ b/documentation/tutorials/submitting-code-for-a-review.md
@@ -0,0 +1,91 @@
+# How to submit code to gerrit for review
+
+## Prerequisites
+1. Generate an ssh key and add it to Gerrit.
+
+First, run `ssh-keygen` in your terminal, and accept all of the default
+parameters by hitting enter. Then go to Gerrit, click on your name in the top
+right corner and click settings. Choose `SSH Public Keys` on the side bar and
+click `Add Key`. Copy paste the contents of `~/.ssh/id_rsa.pub` into the box and
+hit okay.
+
+2. Add the gerrit change-id git hook to your local repository
+
+If you used the `clone with commit-msg hook` command when you first
+cloned the code, you can skip this step. If you did not, run the following
+commands from the 971-Robot-Code directory, replacing `<username>` with your
+gerrit username.
+
+```console
+scp -p -P 29418 <username>@robotics.mvla.net:hooks/commit-msg .git/hooks/
+```
+
+## Submitting code for review
+
+1. Choose what changes you want to commit
+ - You can see what files you've changed using `git status`
+ - You can use `git diff` to see exactly what you changed. Note that this will
+ not show you new files that you've created locally.
+
+2. Once you know what you want to commit, use `git add <file>` to "stage" them
+ for the commit. You should only add the changes that you want, so if your
+ files contain things you don't want to commit, you'll have to cut out the
+ stuff you don't want before using `git add`.
+
+3. After you've used `git add` to add all the changes you want to commit, run
+ `git commit` and write an informative commit message in the editor that pops
+ up. Save and quit in the editor that opens to actually commit your changes.
+ If you change your mind about committing, you can quit without saving to
+ cancel the commit.
+ - You can use `git commit -v` to see what changes `git` thinks you want to
+ commit in the commit message editor.
+ - If your commit message is short, you can use `git commit -m "<message>"` to
+ specify it on the command line.
+
+4. Send your changes to Gerrit by running
+ `git push origin HEAD:refs/for/master`.
+ - A link to the Gerrit web interface will be printed for you to copy paste
+ into your browser.
+
+5. Add reviewers to your change request so that your code can be reviewed and
+ approved after feedback.
+
+## Editing your submitted change
+
+Gerrit allows you to edit your change and resubmit it.
+
+1. Make sure that the commit you want to edit is the latest in your commit
+ history by running `git show` and making sure that the commit is the one you
+ want to edit.
+
+2. Make the changes you want to make.
+
+3. Add the changes using `git add <file1> <file2> ...`.
+
+4. Add the changes you made to the previous commit by running
+ `git commit --amend`. This will allow you to edit the previous commit
+ message. MAKE SURE YOU DON'T EDIT THE GERRIT Change-Id. This is what Gerrit
+ uses to know that you're updating an existing change instead of pushing a new
+ one.
+
+## Troubleshooting
+* If your commit is missing a Change-Id, you'll get a reasonably understandable
+ error that looks like the following:
+```console
+Counting objects: 5, done.
+Delta compression using up to 4 threads.
+Compressing objects: 100% (5/5), done.
+Writing objects: 100% (5/5), 2.83 KiB | 0 bytes/s, done.
+Total 5 (delta 1), reused 0 (delta 0)
+remote: Resolving deltas: 100% (1/1)
+remote: Processing changes: refs: 1, done
+remote: ERROR: [bf965b4] missing Change-Id in commit message footer
+remote:
+remote: Hint: To automatically insert Change-Id, install the hook:
+remote: gitdir=$(git rev-parse --git-dir); scp -p -P 29418 adrian@robotics.mvla.net:hooks/commit-msg ${gitdir}/hooks/
+remote: And then amend the commit:
+remote: git commit --amend
+remote:
+```
+ If you see this, run the commands that they suggest in the error message and
+ push it again
diff --git a/documentation/tutorials/tune-an-autonomous.md b/documentation/tutorials/tune-an-autonomous.md
new file mode 100644
index 0000000..751cfff
--- /dev/null
+++ b/documentation/tutorials/tune-an-autonomous.md
@@ -0,0 +1,2 @@
+# How to tune an existing autonomous
+TODO
diff --git a/documentation/tutorials/using-bazel.md b/documentation/tutorials/using-bazel.md
new file mode 100644
index 0000000..28e7eb9
--- /dev/null
+++ b/documentation/tutorials/using-bazel.md
@@ -0,0 +1,2 @@
+# Using bazel
+TODO
diff --git a/tools/build_rules/pandoc.bzl b/tools/build_rules/pandoc.bzl
new file mode 100644
index 0000000..bc63bac
--- /dev/null
+++ b/tools/build_rules/pandoc.bzl
@@ -0,0 +1,18 @@
+"""Converts a markdown file to an html file.
+
+Given the src "xyz.md", produces "xyz.html".
+
+Attrs:
+ src: Markdown file to convert. Only one file can be specified.
+"""
+
+def pandoc_html(name, src):
+ output = name + ".html"
+ native.genrule(
+ name = name,
+ srcs = [src],
+ outs = [output],
+ cmd = "$(location @pandoc//:pandoc_wrapper) -s $< -o $@",
+ tools = ["@pandoc//:all_files", "@pandoc//:pandoc_wrapper"],
+ executable = True,
+ )