UP | HOME

Homework Guidelines

Overview

These guidelines apply to all homework assignments in ME495 Sensing, Navigation, and Machine Learing for Robotics. This document also serves central location for collecting coding standards for the course.

Important Notice

  1. Failure to adhere to certain guidelines may result in receiving no credit, even for a working solution.
  2. These guidelines apply to every homework assignment but may be overridden by instructions in an individual assignment.
  3. If you are unsure about how these guidelines apply or any assignment instructions please ask on the forum.

Homework Layout

  1. Each assignment consists of a list of tasks labeled as X.Y, where X is the task group and Y is the subtask.
  2. All tasks with the same group are related
    • Read over all the tasks in a group prior to attempting to complete any of them.
  3. Tasks within a group are not necessarily meant to be done in the order they are presented.
    • It will often make debugging easier to implement simpler versions of several of the tasks simultaneously and slowly build up functionality.
  4. Most of the assignments should be viewed as pieces of a single larger project.
    • Therefore, you may need to correct issues on previous assignments prior to moving forward.
  5. When nodes/topics/files/etc are specified directly in an assignment, it is your responsibility to make sure that the nodes/topics/files/etc exactly match the specified names. Even being one or two letters off (e.g., README.MD vs README.md may result in not receiving credit.

Submission Instructions

  1. All homework will be completed in a single git repository
    • I will send everyone an individual link for creating this repository
  2. I will grade whatever commit is at the HEAD of the main branch when I clone your repository.
  3. You should generally work on a development branch
    • Commit and push to the remote Github repository frequently
    • Only push to main when you are ready to submit.
  4. Maintain a file called Tasks.md.
    • Whenever a task is complete, list it on its own line in this file.

Coding Standards

The following list contains the standards that our code should strive to adhere to.

The list may grow as the quarter progresses so check back for each assignment.

Git

  1. Do not include files that do not belong in git. For example:
    • Generated executables, libraries, object files of any kind
    • URDF files generated from xacro
    • Files generated by the build system
    • The build, install, or log space
    • The .vscode directory
  2. Your name/email address should be set properly in git, so that it shows up next to your commits
  3. Each homework assignment should consist of many small git commits.
    • You should include a meaningful commit message with each commit
    • It is okay to commit code with compiler errors to your own development branch, as long as they
      1. Are labeled in the commit message with DOES NOT COMPILE
      2. Never at the HEAD of main
  4. You may use as many branches as you like, but I will only look at the main branch.

ROS

  1. Your code must pass colcon test
  2. Layout your code as git_repository/package
  3. Within a package: (Note: if you have no files that fit in a given category, do not include the corresponding directory)
    • config/ Contains .yaml and .rviz files
    • launch/ Contains .launch.{xml,py} files
    • urdf/ Contains .xacro, .urdf, and .gazebo files (but not if they are generated at runtime).
    • src/ Contains the source code for your ROS nodes and libraries
    • msg/ Contains message files
    • srv/ Contains service files
    • include/pkgname Public headers, if you are treating your package as a library
    • tests/ Unit tests and test scripts
  4. Launchfiles should not result in errors or warnings due to code in one of your packages.
  5. Launchfile arguments must have a description attribute to explain their use
  6. Launchfile arguments that take a small number of specific values must have their choices attribute set.
  7. Any package.xml files should be kept up-to-date with the proper dependencies, a description, and author information
  8. No hardcoded/absolute directories in launchfiles or code.
    • Use $(find-pkg-share) and other tools as appropriate, so that the code can be run on computers other than your own.

C++

General

  1. The code at the HEAD of the main branch should be free from compiler errors (Automatic Zero)
    • Commit messages for intermediate commits with errors should be labeled as DOES NOT COMPILE
    • You will automatically receive a zero for code that does not compile on the main branch if it is at the HEAD or not labeled as such
  2. There should be no compiler warnings.
    • Take compiler warnings seriously as they often can indicate a bug in your code.
  3. If your program ever segfaults, it has some type of memory corruption that should be fixed immediately.
  4. All C++ code should be compiled with c++23 and -Wall -Wextra -Wpedantic
  5. Put braces after control-flow expressions even if they are one line (see goto fail)

Comments

  1. Prefer C++ style comments (//) to C style comments /*
    • There are some subtle "gotchas" with C style comments
    • Adhering to this rule makes it easier to temporarily comment out large blocks of code when debugging using /*
  2. Submitted versions of assignments should not have any commented out code unless the commented-out code also includes a descriptive reason as to why it is commented out. And it's generally better to have it completely removed.
  3. All .cpp files that are ROS nodes should start with the following comment block:

    /// \file
    /// \brief A brief description of what the file does
    ///
    /// PARAMETERS:
    ///     parameter_name (parameter_type): description of the parameter
    /// PUBLISHES:
    ///     topic_name (topic_type): description of topic
    /// SUBSCRIBES:
    ///     topic_name (topic_type): description of the topic
    /// SERVERS:
    ///     service_name (service_type): description of the service
    /// CLIENTS:
    ///     service_name (service_type): description of the service
    
  4. All functions/methods should be commented using doxygen style comments

    /// \brief Computes the factorial
    ///
    /// \tparam T - An integral type
    /// \param F - the factorial to compute
    /// \returns F! (F Factorial)
    /// <template typename T>
    /// T factorial (T F);
    
  5. Classes should have a doxygen comment block describing what the class does and all public members should have descriptions.

    /// \brief A class to model a Classroom
    class Classroom
    {
    public:
        /// \brief Create an empty classroom
        Classroom();
    
        /// \brief Give a lecture
        /// \param topic Description of the lecture's subject
        void lecture(const std::string & topic);
    private:
        // Comment is okay but private members are implementation
        // details and not part of the public API so should not get
        // doxygen comments
        int num_students;
    }
    
  6. Lack of doxygen style comments before functions, classes, or ROS nodes may result in me deleting the uncommented code and trying to compile your project.

Include Files

  1. #pragma once is not standard C++ and should not be used.
  2. Use include guards in all header files
  3. All include files that you write should be included with #include "package/headerfile.hpp".
  4. Minimize the number of header files you include in each header file by using forward declarations where possible

Namespaces

  1. Do not put using statements at file scope in header files.
    • These using statements change the behavior of all code that includes the header, including other headers that are below this one
    • Thus, you can introduce include-order dependencies and mess up the functioning of other people's code when they include your header
  2. In most cases it is preferable to explicitly do a using for each function that you need rather than polluting the namespace by doing using namespace std
    • One exception to this rule is when using literal suffixes (e.g., the units from std::chrono), then using namespace is preferred (but still not in headers!)

Math

  1. Double precision literals should always include the decimal point (e.g., 1.0 rather than 1)
    • This enables you to avoid ever thinking about integer/double conversion rules
  2. Complicated math expressions should be commented, referencing the derivation or source of the equation.
  3. Break up long math expressions. It is okay to store intermediate values as const or constexpr variables
  4. Use double not float to minimize numerical issues as potential sources of error.

Classes

  1. Constructors should use initializer lists to initialize member variables.
  2. Member variables must be initialized in the constructor initailizer list in the same order in which they are declared
  3. Usually, single-argument constructors should be declared explicit (so there will not be an implicit conversion)
  4. Do not use this-> unnecessarily.
    • In C++ this is implied when working within a member function.

Variables

  1. Use constexpr and const everywhere you can
    • Do not use const in headers for pass-by-value, however, the arguments in the implementation file can be const
  2. Place variables in the scope closest to where they are needed
  3. If you use a global variable, make it static or put it in an anonymous namespace so it can't bee seen by other modules
    • There are rare cases where using an extern global variable might make sense, but not in this class, so don't use extern
  4. Use auto a lot (see almost always auto, Question 3).
  5. Do not inherit from a class unless it has a virtual or protected destructor.

Pointers

  1. Resource Acquisition is Initialization
    • This means you probably don't want to be using new except in a constructor or delete except in a destructor
    • There are very few reasons (such as writing your own custom data structure) to use new or delete in Modern C++
    • There are no reasons to use new or delete in this class
      • Alternatives are smart pointers (with make_shared and make_unique instead of new, or more likely std::vector
  2. Prefer pass by (const reference) to pass by pointer.
    • There are very few reasons (such as interfacing with C code) to pass by raw pointer in modern C++
  3. There are effectively zero reasons to use raw pointers anywhere for the code written for this class.

Data-structures

  1. Don't use raw arrays (e.g., int myarra[20]).
  2. The default data structure of choice is std::vector
    • Other data structures have their place, but usually std::vector is a good first choice
  3. Use algorithms in std::algorithm and std::ranges
  4. When indexing, use .at() to get runtime bounds checking (at the expense of performance)
    • Do not use [] to index in a C++ program.
    • At some point you may want to use [] for efficiency reasons, but that point is very far down the road and not likely to be needed in this class.
  5. When using C++20 or beyond, use std::ranges Introductory Tutorial

Citations

  1. Follow the Citation Rules
  2. The following sources are exempt from the citation requirement:
    1. Me/anything said by me in office hours or class.
    2. My notes (on any website authored by me).
    3. Anything under https://docs.ros.org/en/jazzy/Tutorials.html.
    4. Any ROS 2 or package-related "boilerplate" code (i.e., code that is provided as an example for how to use a package/feature that would not vary significantly between different uses).
    5. C++ reference material (e.g., from cppreference.com) that is used in a generic manner (e.g., to help you understand how a standard part of C++ works) need not be cited.
      • However, if you use code examples from cppreference.com these should be cited and cross-referenced appropriately.
  3. You are highly discouraged from using former solutions. Such use must be cited properly (including filenames and line numbers).

Author: Matthew Elwin.