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
- Failure to adhere to certain guidelines may result in receiving no credit, even for a working solution.
- These guidelines apply to every homework assignment but may be overridden by instructions in an individual assignment.
- If you are unsure about how these guidelines apply or any assignment instructions please ask on the forum.
Homework Layout
- Each assignment consists of a list of tasks labeled as
X.Y, whereXis the task group andYis the subtask. - All tasks with the same group are related
- Read over all the tasks in a group prior to attempting to complete any of them.
- 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.
- 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.
- 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.mdmay result in not receiving credit.
Submission Instructions
- All homework will be completed in a single git repository
- I will send everyone an individual link for creating this repository
- I will grade whatever commit is at the
HEADof themainbranch when I clone your repository. - You should generally work on a development branch
- Commit and push to the remote Github repository frequently
- Only push to
mainwhen you are ready to submit.
- 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
- 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, orlogspace - The
.vscodedirectory
- Your name/email address should be set properly in git, so that it shows up next to your commits
- 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
- Are labeled in the commit message with
DOES NOT COMPILE - Never at the
HEADofmain
- Are labeled in the commit message with
- You may use as many branches as you like, but I will only look at the
mainbranch.
ROS
- Your code must pass
colcon test - Layout your code as
git_repository/package - Within a package:
(Note: if you have no files that fit in a given category, do not include the corresponding directory)
config/Contains.yamland.rvizfileslaunch/Contains.launch.{xml,py}filesurdf/Contains.xacro,.urdf, and.gazebofiles (but not if they are generated at runtime).src/Contains the source code for your ROS nodes and librariesmsg/Contains message filessrv/Contains service filesinclude/pkgnamePublic headers, if you are treating your package as a librarytests/Unit tests and test scripts
- Launchfiles should not result in errors or warnings due to code in one of your packages.
- Launchfile arguments must have a
descriptionattribute to explain their use - Launchfile arguments that take a small number of specific values must have their
choicesattribute set. - Any
package.xmlfiles should be kept up-to-date with the proper dependencies, a description, and author information - 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.
- Use
C++
General
- The code at the
HEADof themainbranch 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
mainbranch if it is at theHEADor not labeled as such
- Commit messages for intermediate commits with errors should be labeled as
- There should be no compiler warnings.
- Take compiler warnings seriously as they often can indicate a bug in your code.
- If your program ever segfaults, it has some type of memory corruption that should be fixed immediately.
- All C++ code should be compiled with
c++23and-Wall -Wextra -Wpedantic - Put braces after control-flow expressions even if they are one line (see goto fail)
Comments
- 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
/*
- 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.
All
.cppfiles 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
All functions/methods should be commented using
doxygenstyle 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);
Classes should have a
doxygencomment 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; }
- Lack of
doxygenstyle comments before functions, classes, or ROS nodes may result in me deleting the uncommented code and trying to compile your project.
Include Files
#pragma onceis not standard C++ and should not be used.- Use include guards in all header files
- All include files that you write should be included with
#include "package/headerfile.hpp". - Minimize the number of header files you include in each header file by using forward declarations where possible
Namespaces
- Do not put
usingstatements at file scope in header files.- These
usingstatements 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
- These
- In most cases it is preferable to explicitly do a
usingfor each function that you need rather than polluting the namespace by doingusing namespace std- One exception to this rule is when using literal suffixes (e.g., the units from
std::chrono), thenusing namespaceis preferred (but still not in headers!)
- One exception to this rule is when using literal suffixes (e.g., the units from
Math
- Double precision literals should always include the decimal point (e.g.,
1.0rather than1)- This enables you to avoid ever thinking about integer/double conversion rules
- Complicated math expressions should be commented, referencing the derivation or source of the equation.
- Break up long math expressions. It is okay to store intermediate values as
constorconstexprvariables - Use
doublenotfloatto minimize numerical issues as potential sources of error.
Classes
- Constructors should use initializer lists to initialize member variables.
- Member variables must be initialized in the constructor initailizer list in the same order in which they are declared
- Usually, single-argument constructors should be declared
explicit(so there will not be an implicit conversion) - Do not use
this->unnecessarily.- In C++
thisis implied when working within a member function.
- In C++
Variables
- Use
constexprandconsteverywhere you can- Do not use
constin headers for pass-by-value, however, the arguments in the implementation file can beconst
- Do not use
- Place variables in the scope closest to where they are needed
- If you use a global variable, make it
staticor put it in an anonymous namespace so it can't bee seen by other modules- There are rare cases where using an
externglobal variable might make sense, but not in this class, so don't useextern
- There are rare cases where using an
- Use
autoa lot (see almost always auto, Question 3). - Do not inherit from a class unless it has a
virtualorprotecteddestructor.
Pointers
- Resource Acquisition is Initialization
- This means you probably don't want to be using
newexcept in a constructor ordeleteexcept in a destructor - There are very few reasons (such as writing your own custom data structure) to use
newordeletein Modern C++ - There are no reasons to use
newordeletein this class- Alternatives are smart pointers (with
make_sharedandmake_uniqueinstead ofnew, or more likelystd::vector
- Alternatives are smart pointers (with
- This means you probably don't want to be using
- Prefer pass by (
constreference) to pass by pointer.- There are very few reasons (such as interfacing with C code) to pass by raw pointer in modern C++
- There are effectively zero reasons to use raw pointers anywhere for the code written for this class.
Data-structures
- Don't use raw arrays (e.g.,
int myarra[20]). - The default data structure of choice is
std::vector- Other data structures have their place, but usually
std::vectoris a good first choice
- Other data structures have their place, but usually
- Use algorithms in
std::algorithmandstd::ranges - 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.
- Do not use
- When using C++20 or beyond, use
std::rangesIntroductory Tutorial
Citations
- Follow the Citation Rules
- The following sources are exempt from the citation requirement:
- Me/anything said by me in office hours or class.
- My notes (on any website authored by me).
- Anything under https://docs.ros.org/en/jazzy/Tutorials.html.
- 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).
- 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.comthese should be cited and cross-referenced appropriately.
- However, if you use code examples from
- You are highly discouraged from using former solutions. Such use must be cited properly (including filenames and line numbers).