{
    "componentChunkName": "component---src-components-page-template-jsx",
    "path": "/guides/main/camera-calibration",
    "result": {"data":{"mdx":{"id":"4ba52cf7-d354-5fe1-ad84-2007eef14f53","body":"var _excluded = [\"components\"];\n\nfunction _extends() { _extends = Object.assign ? Object.assign.bind() : function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }\n\nfunction _objectWithoutProperties(source, excluded) { if (source == null) return {}; var target = _objectWithoutPropertiesLoose(source, excluded); var key, i; if (Object.getOwnPropertySymbols) { var sourceSymbolKeys = Object.getOwnPropertySymbols(source); for (i = 0; i < sourceSymbolKeys.length; i++) { key = sourceSymbolKeys[i]; if (excluded.indexOf(key) >= 0) continue; if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue; target[key] = source[key]; } } return target; }\n\nfunction _objectWithoutPropertiesLoose(source, excluded) { if (source == null) return {}; var target = {}; var sourceKeys = Object.keys(source); var key, i; for (i = 0; i < sourceKeys.length; i++) { key = sourceKeys[i]; if (excluded.indexOf(key) >= 0) continue; target[key] = source[key]; } return target; }\n\n/* @jsxRuntime classic */\n\n/* @jsx mdx */\nvar _frontmatter = {\n  \"section\": \"Guides\",\n  \"chapter\": \"Main Codebase\",\n  \"title\": \"Camera Calibration\",\n  \"description\": \"Learn how to calibrate cameras.\",\n  \"slug\": \"/guides/main/camera-calibration\",\n  \"authors\": [\"Ysobel Sims (@ysims)\"]\n};\n\nvar makeShortcode = function makeShortcode(name) {\n  return function MDXDefaultShortcode(props) {\n    console.warn(\"Component \" + name + \" was not imported, exported, or provided by MDXProvider as global scope\");\n    return mdx(\"div\", props);\n  };\n};\n\nvar Grid = makeShortcode(\"Grid\");\nvar layoutProps = {\n  _frontmatter: _frontmatter\n};\nvar MDXLayout = \"wrapper\";\nreturn function MDXContent(_ref) {\n  var components = _ref.components,\n      props = _objectWithoutProperties(_ref, _excluded);\n\n  return mdx(MDXLayout, _extends({}, layoutProps, props, {\n    components: components,\n    mdxType: \"MDXLayout\"\n  }), mdx(\"p\", null, \"Camera calibration determines optimal parameters for the cameras. These parameters include the focal length and the transform from one camera to the other. More on the parameters being optimised for camera calibration can be found on \", mdx(\"a\", {\n    parentName: \"p\",\n    \"href\": \"/system/subsystems/input#cameras\"\n  }, \"the input page\"), \".\"), mdx(\"p\", null, \"The calibration requires two steps, creating the \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"nbs\"), \" recording and using it to find the camera parameters.\"), mdx(\"h2\", {\n    \"id\": \"get-the-data\",\n    \"style\": {\n      \"position\": \"relative\"\n    }\n  }, mdx(\"a\", {\n    parentName: \"h2\",\n    \"href\": \"#get-the-data\",\n    \"aria-label\": \"get the data permalink\",\n    \"className\": \"anchor before\"\n  }, mdx(\"svg\", {\n    parentName: \"a\",\n    \"aria-hidden\": \"true\",\n    \"focusable\": \"false\",\n    \"height\": \"16\",\n    \"version\": \"1.1\",\n    \"viewBox\": \"0 0 16 16\",\n    \"width\": \"16\"\n  }, mdx(\"path\", {\n    parentName: \"svg\",\n    \"fillRule\": \"evenodd\",\n    \"d\": \"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"\n  }))), \"Get the Data\"), mdx(\"ol\", null, mdx(\"li\", {\n    parentName: \"ol\"\n  }, mdx(\"p\", {\n    parentName: \"li\"\n  }, \"Change \", mdx(\"a\", {\n    parentName: \"p\",\n    \"href\": \"https://github.com/NUbots/NUbots/blob/main/roles/test/camera.role\"\n  }, mdx(\"inlineCode\", {\n    parentName: \"a\"\n  }, \"test/camera.role\")), \" to include \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"support::logging::DataLogging\"))), mdx(\"li\", {\n    parentName: \"ol\"\n  }, mdx(\"p\", {\n    parentName: \"li\"\n  }, \"Build using \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"./b build\"), \" and then install onto a robot using \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"./b install n<number>\"), \". More on building can be found on the \", mdx(\"a\", {\n    parentName: \"p\",\n    \"href\": \"/guides/main/getting-started\"\n  }, \"Getting Started page\"), \" or the \", mdx(\"a\", {\n    parentName: \"p\",\n    \"href\": \"/system/foundations/build-system\"\n  }, \"Build System page\"), \".\")), mdx(\"li\", {\n    parentName: \"ol\"\n  }, mdx(\"p\", {\n    parentName: \"li\"\n  }, \"On the robot, enable compressed image recording in \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"config/DataLogging.yaml\"), \". To edit the file, run \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"nano config/DataLogging.yaml\"), \". Make sure \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"message.output.CompressedImage\"), \" is \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"true\"), \" (it should be by default).\")), mdx(\"li\", {\n    parentName: \"ol\"\n  }, mdx(\"p\", {\n    parentName: \"li\"\n  }, \"Ensure the Left and Right camera serial numbers are correct in their respective configuration files (\", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"Left.yaml\"), \" and \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"Right.yaml\"), \"). The configuration files are found in the \", mdx(\"a\", {\n    parentName: \"p\",\n    \"href\": \"https://github.com/NUbots/NUbots/tree/main/module/input/Camera/data/config\"\n  }, \"Camera module folder\"), \", with separate directories for each robot.\"), mdx(\"p\", {\n    parentName: \"li\"\n  }, \"The serial numbers can be retrieved by first running \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"lsusb\"), \" and finding the bus and device numbers for the FLIR/Point Grey cameras. Then run \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"lsusb -s <bus number>:<device number> -v\"), \" to find the serial numbers.\"), mdx(\"p\", {\n    parentName: \"li\"\n  }, \"Next you need to figure out which serial number is left and which is right. Change the serial number for one camera to an incorrect number (this ensures it's not found when running test/camera). Enable \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"message.output.CompressedImage\"), \" in \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"NetworkForwarder.yaml\"), \". Run \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"./test/camera\"), \" and test which camera is working by covering one camera and seeing the resulting image in the NUsight vision tab. Alternatively, you could unplug one camera rather than change the serial number. If the serial number is on the wrong camera configuration file, switch them.\")), mdx(\"li\", {\n    parentName: \"ol\"\n  }, mdx(\"p\", {\n    parentName: \"li\"\n  }, \"Check the focus of the lenses using the NUsight vision tab. If it is not sharp, focus the camera. This involves pulling the camera out from the head, still plugged in, and loosening the three grub screws. Twist until the camera is focused.\")), mdx(\"li\", {\n    parentName: \"ol\"\n  }, mdx(\"p\", {\n    parentName: \"li\"\n  }, \"Verify that the extrinsics look correct in NUsight. The extrinsics are the transform from the last neck motor to the camera. This is retrieved from the robot's URDF model, but differences in the real robots may result in required offsets. Offset values for both pitch and roll are in the camera configuration files. The offsets are in radians.\"), mdx(\"ol\", {\n    parentName: \"li\"\n  }, mdx(\"li\", {\n    parentName: \"ol\"\n  }, \"Ensure \", mdx(\"inlineCode\", {\n    parentName: \"li\"\n  }, \"NetworkForwarder.yaml\"), \" has a \", mdx(\"inlineCode\", {\n    parentName: \"li\"\n  }, \"message.output.CompressedImage\"), \" value greater than 0.\"), mdx(\"li\", {\n    parentName: \"ol\"\n  }, \"Stand the robot up with \", mdx(\"inlineCode\", {\n    parentName: \"li\"\n  }, \"./scriptrunner Stand.yaml\")), mdx(\"li\", {\n    parentName: \"ol\"\n  }, \"Face the robot towards a straight horizontal line, such as a line of bricks on a brick wall.\"), mdx(\"li\", {\n    parentName: \"ol\"\n  }, \"Run \", mdx(\"inlineCode\", {\n    parentName: \"li\"\n  }, \"./test/visualmesh\"), \" and switch to the vision tab in NUsight\")), mdx(\"p\", {\n    parentName: \"li\"\n  }, \"NUsight should show a blue horizontal line. Adjust the offsets until the line is drawn at a constant height (the height of the cameras) along the wall.\")), mdx(\"li\", {\n    parentName: \"ol\"\n  }, mdx(\"p\", {\n    parentName: \"li\"\n  }, \"Run \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"./test/camera\"), \" on the robot and hold up a board as shown in the below image. There is an appropriate board in the NUbots laboratory. Move the board around to cover the robot's view over time, taking into account that the lenses have a \", mdx(\"span\", {\n    parentName: \"p\",\n    \"className\": \"math math-inline\"\n  }, mdx(\"span\", {\n    parentName: \"span\",\n    \"className\": \"katex\"\n  }, mdx(\"span\", {\n    parentName: \"span\",\n    \"className\": \"katex-mathml\"\n  }, mdx(\"math\", {\n    parentName: \"span\",\n    \"xmlns\": \"http://www.w3.org/1998/Math/MathML\"\n  }, mdx(\"semantics\", {\n    parentName: \"math\"\n  }, mdx(\"mrow\", {\n    parentName: \"semantics\"\n  }, mdx(\"mn\", {\n    parentName: \"mrow\"\n  }, \"18\"), mdx(\"msup\", {\n    parentName: \"mrow\"\n  }, mdx(\"mn\", {\n    parentName: \"msup\"\n  }, \"0\"), mdx(\"mo\", {\n    parentName: \"msup\",\n    \"lspace\": \"0em\",\n    \"rspace\": \"0em\"\n  }, \"\\u2218\"))), mdx(\"annotation\", {\n    parentName: \"semantics\",\n    \"encoding\": \"application/x-tex\"\n  }, \"180^{\\\\circ}\")))), mdx(\"span\", {\n    parentName: \"span\",\n    \"className\": \"katex-html\",\n    \"aria-hidden\": \"true\"\n  }, mdx(\"span\", {\n    parentName: \"span\",\n    \"className\": \"base\"\n  }, mdx(\"span\", {\n    parentName: \"span\",\n    \"className\": \"strut\",\n    \"style\": {\n      \"height\": \"0.6741em\"\n    }\n  }), mdx(\"span\", {\n    parentName: \"span\",\n    \"className\": \"mord\"\n  }, \"18\"), mdx(\"span\", {\n    parentName: \"span\",\n    \"className\": \"mord\"\n  }, mdx(\"span\", {\n    parentName: \"span\",\n    \"className\": \"mord\"\n  }, \"0\"), mdx(\"span\", {\n    parentName: \"span\",\n    \"className\": \"msupsub\"\n  }, mdx(\"span\", {\n    parentName: \"span\",\n    \"className\": \"vlist-t\"\n  }, mdx(\"span\", {\n    parentName: \"span\",\n    \"className\": \"vlist-r\"\n  }, mdx(\"span\", {\n    parentName: \"span\",\n    \"className\": \"vlist\",\n    \"style\": {\n      \"height\": \"0.6741em\"\n    }\n  }, mdx(\"span\", {\n    parentName: \"span\",\n    \"style\": {\n      \"top\": \"-3.063em\",\n      \"marginRight\": \"0.05em\"\n    }\n  }, mdx(\"span\", {\n    parentName: \"span\",\n    \"className\": \"pstrut\",\n    \"style\": {\n      \"height\": \"2.7em\"\n    }\n  }), mdx(\"span\", {\n    parentName: \"span\",\n    \"className\": \"sizing reset-size6 size3 mtight\"\n  }, mdx(\"span\", {\n    parentName: \"span\",\n    \"className\": \"mord mtight\"\n  }, mdx(\"span\", {\n    parentName: \"span\",\n    \"className\": \"mord mtight\"\n  }, \"\\u2218\"))))))))))))), \" field of view. Move the board around at different distances and angles.\"), mdx(\"img\", {\n    parentName: \"li\",\n    \"src\": \"/cbec4d4e22b4b216daa08e795aa57276/asymmetric-circle-grid.svg\",\n    \"alt\": \"A white board with black circles in rows.\",\n    \"title\": \"Asymmetric circles grid used for calibration.\"\n  }), mdx(Grid, {\n    columns: \"1fr 1fr\",\n    caption: \"Photos from the robot's cameras of a person moving around a board for camera calibration.\",\n    mdxType: \"Grid\"\n  }, mdx(\"img\", {\n    parentName: \"li\",\n    \"src\": \"/opt/build/repo/src/book/03-guides/01-main-codebase/images/calibration/board-middle.jpg\",\n    \"alt\": \"A person holding a board in the middle of the photo\"\n  }), mdx(\"img\", {\n    parentName: \"li\",\n    \"src\": \"/opt/build/repo/src/book/03-guides/01-main-codebase/images/calibration/board-below.jpg\",\n    \"alt\": \"A person holding a board at the bottom of the photo\"\n  }), mdx(\"img\", {\n    parentName: \"li\",\n    \"src\": \"/opt/build/repo/src/book/03-guides/01-main-codebase/images/calibration/board-left.jpg\",\n    \"alt\": \"A person holding a board to the left\"\n  }), mdx(\"img\", {\n    parentName: \"li\",\n    \"src\": \"/opt/build/repo/src/book/03-guides/01-main-codebase/images/calibration/board-right.jpg\",\n    \"alt\": \"A person holding a board to the right\"\n  }))), mdx(\"li\", {\n    parentName: \"ol\"\n  }, mdx(\"p\", {\n    parentName: \"li\"\n  }, \"Stop the binary and copy the \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"nbs\"), \" file created into the NUbots directory on your computer.\"), mdx(\"ol\", {\n    parentName: \"li\"\n  }, mdx(\"li\", {\n    parentName: \"ol\"\n  }, mdx(\"p\", {\n    parentName: \"li\"\n  }, \"To stop the program running, hit \", mdx(\"kbd\", null, \"Ctrl\"), \" + \", mdx(\"kbd\", null, \"c\"), \".\")), mdx(\"li\", {\n    parentName: \"ol\"\n  }, mdx(\"p\", {\n    parentName: \"li\"\n  }, \"Discover the name of the log file created. The file is in the \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"recordings/test/camera/\"), \" folder on the robot. The name corresponds to the date and time it was created, according to the robot. Run \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"ls recordings/test/camera/\"), \" to list all logs.\")), mdx(\"li\", {\n    parentName: \"ol\"\n  }, mdx(\"p\", {\n    parentName: \"li\"\n  }, \"(optional) Rename the log file, making it easier to copy across to the computer. Change the name with the command \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"mv <old path> <new path>\"), \".\")), mdx(\"li\", {\n    parentName: \"ol\"\n  }, mdx(\"p\", {\n    parentName: \"li\"\n  }, \"Run the command \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"scp <robot address>:<file path> .\"), \" from the NUbots directory on your computer, not on the robot.\")), mdx(\"li\", {\n    parentName: \"ol\"\n  }, mdx(\"p\", {\n    parentName: \"li\"\n  }, \"The robot can be turned off at this point. The recording you just made should be on your computer in the NUbots directory. Check that it is before continuing to the next section.\"))))), mdx(\"h2\", {\n    \"id\": \"run-the-optimisation\",\n    \"style\": {\n      \"position\": \"relative\"\n    }\n  }, mdx(\"a\", {\n    parentName: \"h2\",\n    \"href\": \"#run-the-optimisation\",\n    \"aria-label\": \"run the optimisation permalink\",\n    \"className\": \"anchor before\"\n  }, mdx(\"svg\", {\n    parentName: \"a\",\n    \"aria-hidden\": \"true\",\n    \"focusable\": \"false\",\n    \"height\": \"16\",\n    \"version\": \"1.1\",\n    \"viewBox\": \"0 0 16 16\",\n    \"width\": \"16\"\n  }, mdx(\"path\", {\n    parentName: \"svg\",\n    \"fillRule\": \"evenodd\",\n    \"d\": \"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"\n  }))), \"Run the Optimisation\"), mdx(\"ol\", null, mdx(\"li\", {\n    parentName: \"ol\"\n  }, mdx(\"p\", {\n    parentName: \"li\"\n  }, \"Run the following commands to install the dependencies of the camera calibration tool if you have not done this before\"), mdx(\"pre\", {\n    parentName: \"li\"\n  }, mdx(\"code\", {\n    parentName: \"pre\",\n    \"className\": \"language-bash\"\n  }, \"sudo apt update\\nsudo apt install protobuf-compiler libprotobuf-dev\\nsudo -H pip3 install --upgrade pip\\nsudo -H pip3 install tensorflow opencv-contrib-python ruamel.yaml\\n\"))), mdx(\"li\", {\n    parentName: \"ol\"\n  }, mdx(\"p\", {\n    parentName: \"li\"\n  }, \"Calibrate the cameras by running\"), mdx(\"pre\", {\n    parentName: \"li\"\n  }, mdx(\"code\", {\n    parentName: \"pre\",\n    \"className\": \"language-bash\"\n  }, \"./b nbs calibrate_cameras <nbs file name> -c <camera config folder>\\n\")), mdx(\"p\", {\n    parentName: \"li\"\n  }, mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"<nbs file name>\"), \" is the name of the \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"nbs\"), \" file you just created. \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"<camera config folder>\"), \" is the path to the folder with the two camera config files \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"Left.yaml\"), \" and \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"Right.yaml\"), \". These exist in \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"./module/input/Camera/data/config/<robot name>/Cameras/\"), \".\"), mdx(\"p\", {\n    parentName: \"li\"\n  }, \"The calibration routine changes the values in the camera configuration files.\")), mdx(\"li\", {\n    parentName: \"ol\"\n  }, mdx(\"p\", {\n    parentName: \"li\"\n  }, \"Verify these values by running vision and checking the output in NUsight.\"), mdx(\"p\", {\n    parentName: \"li\"\n  }, \"You should see the same blue line as before, correctly aligned with the wall. If the line is not aligned, you will need to adjust the camera offsets.\"), mdx(\"p\", {\n    parentName: \"li\"\n  }, \"Run the \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"test/localisation\"), \" role and check that the field lines in the localisation view are parallel or perpendicular to each other. If the perspective does not look right, then the cameras are not calibrated correctly.\")), mdx(\"li\", {\n    parentName: \"ol\"\n  }, mdx(\"p\", {\n    parentName: \"li\"\n  }, \"Repeat this process with other robots if needed.\")), mdx(\"li\", {\n    parentName: \"ol\"\n  }, mdx(\"p\", {\n    parentName: \"li\"\n  }, \"Commit these changes in a new branch on GitHub and make a Pull Request. Read the \", mdx(\"a\", {\n    parentName: \"p\",\n    \"href\": \"/guides/general/git\"\n  }, \"Git guide\"), \" if you are unsure about this step.\"))));\n}\n;\nMDXContent.isMDXComponent = true;","tableOfContents":{"items":[{"url":"#get-the-data","title":"Get the Data"},{"url":"#run-the-optimisation","title":"Run the Optimisation"}]},"frontmatter":{"section":"Guides","chapter":"Main Codebase","title":"Camera Calibration","description":"Learn how to calibrate cameras.","keywords":null,"slug":"/guides/main/camera-calibration","hidden":null},"childNUbookContributions":{"authors":[{"name":"Ysobel Sims","username":"ysims"}],"lastCommit":{"date":"2023-11-28T09:47:06.000Z","hash":"59078076843a88daa2a26c25bccfc46de77dfe7f"}}}},"pageContext":{"mdxPath":"src/book/03-guides/01-main-codebase/06-camera-calibration.mdx","id":"4ba52cf7-d354-5fe1-ad84-2007eef14f53","next":{"chapter":"Main Codebase","title":"Onboarding Workshop","description":"Build a simple NUClear program to get comfortable with Git and the NUbots codebase.","slug":"/guides/main/onboarding","hidden":null},"previous":{"chapter":"Main Codebase","title":"Data Recording and Playback","description":"How to record data from a running system and play it back.","slug":"/guides/main/data-recording-playback","hidden":null},"menu":[{"title":"Team","slug":"/team/introduction","chapters":[{"title":"Introduction","slug":"/team/introduction","pages":[{"title":"Introduction to NUbots","slug":"/team/introduction","hidden":null},{"title":"Areas of Research","slug":"/team/areas-of-research","hidden":null},{"title":"Current Team","slug":"/team/current-members","hidden":null}],"hidden":false},{"title":"Joining the Team","slug":"/team/how-we-work","pages":[{"title":"How We Work","slug":"/team/how-we-work","hidden":null},{"title":"How to Join NUbots","slug":"/team/how-to-join","hidden":null},{"title":"Lab Induction","slug":"/team/induction","hidden":null}],"hidden":false},{"title":"Community","slug":"/team/sponsors","pages":[{"title":"Sponsors","slug":"/team/sponsors","hidden":null},{"title":"Connect","slug":"/team/connect","hidden":null}],"hidden":false},{"title":"History","slug":"/team/history","pages":[{"title":"Team History","slug":"/team/history","hidden":null},{"title":"Past Members","slug":"/team/past-members","hidden":null},{"title":"Publications","slug":"/team/publications","hidden":null}],"hidden":false},{"title":"RoboCup","slug":"/team/robocup","pages":[{"title":"RoboCup","slug":"/team/robocup","hidden":null},{"title":"Resources","slug":"/team/robocup/resources","hidden":null},{"title":"Debriefs","slug":"/team/robocup/debriefs","hidden":null}],"hidden":false}],"hidden":false},{"title":"System","slug":"/system/foundations/overview","chapters":[{"title":"Foundations","slug":"/system/foundations/overview","pages":[{"title":"Overview","slug":"/system/foundations/overview","hidden":null},{"title":"Build System","slug":"/system/foundations/build-system","hidden":null},{"title":"Continuous Integration","slug":"/system/foundations/ci-system","hidden":null},{"title":"NUClear","slug":"/system/foundations/nuclear","hidden":null},{"title":"Mathematics","slug":"/system/foundations/mathematics","hidden":null},{"title":"Configuration and Script System","slug":"/system/foundations/config-script","hidden":null},{"title":"Director","slug":"/system/foundations/director","hidden":null}],"hidden":false},{"title":"Subsystems","slug":"/system/subsystems/input","pages":[{"title":"Input","slug":"/system/subsystems/input","hidden":null},{"title":"Odometry","slug":"/system/subsystems/odometry","hidden":null},{"title":"Localisation","slug":"/system/subsystems/localisation","hidden":null},{"title":"Motion","slug":"/system/subsystems/motion","hidden":null},{"title":"Vision","slug":"/system/subsystems/vision","hidden":null},{"title":"Behaviour","slug":"/system/subsystems/behaviour","hidden":null},{"title":"Logging","slug":"/system/subsystems/logging","hidden":null}],"hidden":false},{"title":"Tools","slug":"/system/tools/nusight","pages":[{"title":"NUsight","slug":"/system/tools/nusight","hidden":null},{"title":"NUbook","slug":"/system/tools/nubook","hidden":null},{"title":"NUpbr","slug":"/system/tools/nupbr","hidden":null},{"title":"NUgan","slug":"/system/tools/nugan","hidden":null},{"title":"System Configuration","slug":"/system/tools/system_configuration","hidden":null},{"title":"NatNet SDK","slug":"/system/tools/natnet_sdk","hidden":null}],"hidden":false},{"title":"Hardware","slug":"/system/hardware/overview","pages":[{"title":"Overview and Specifications","slug":"/system/hardware/overview","hidden":null}],"hidden":false},{"title":"Modules","slug":"/system/modules/actuation/","pages":[{"title":"Actuation","slug":"/system/modules/actuation/","hidden":null},{"title":"Extension","slug":"/system/modules/extension/","hidden":null},{"title":"Input","slug":"/system/modules/input/","hidden":null},{"title":"Localisation","slug":"/system/modules/localisation/","hidden":null},{"title":"Nbs","slug":"/system/modules/nbs/","hidden":null},{"title":"Network","slug":"/system/modules/network/","hidden":null},{"title":"Output","slug":"/system/modules/output/","hidden":null},{"title":"Planning","slug":"/system/modules/planning/","hidden":null},{"title":"Platform","slug":"/system/modules/platform/","hidden":null},{"title":"Purpose","slug":"/system/modules/purpose/","hidden":null},{"title":"Skill","slug":"/system/modules/skill/","hidden":null},{"title":"Strategy","slug":"/system/modules/strategy/","hidden":null},{"title":"Support","slug":"/system/modules/support/","hidden":null},{"title":"Tools","slug":"/system/modules/tools/","hidden":null},{"title":"Vision","slug":"/system/modules/vision/","hidden":null}],"hidden":false}],"hidden":false},{"title":"Guides","slug":"/guides/main/getting-started","chapters":[{"title":"Main Codebase","slug":"/guides/main/getting-started","pages":[{"title":"Getting Started","slug":"/guides/main/getting-started","hidden":null},{"title":"NUClear","slug":"/guides/main/nuclear-tutorial","hidden":null},{"title":"Running and Tuning Scripts","slug":"/guides/main/tuning-and-running-scripts","hidden":null},{"title":"Maintaining Subsystems","slug":"/guides/main/maintaining-subsystems","hidden":null},{"title":"Data Recording and Playback","slug":"/guides/main/data-recording-playback","hidden":null},{"title":"Camera Calibration","slug":"/guides/main/camera-calibration","hidden":null},{"title":"Onboarding Workshop","slug":"/guides/main/onboarding","hidden":null}],"hidden":false},{"title":"Tools","slug":"/guides/tools/nusight-contribution","pages":[{"title":"Contributing to NUsight","slug":"/guides/tools/nusight-contribution","hidden":null},{"title":"Setting Up Webots","slug":"/guides/tools/webots-setup","hidden":null},{"title":"Visual Mesh Getting Started","slug":"/guides/tools/visualmesh","hidden":null},{"title":"Using NUpbr","slug":"/guides/tools/nupbr-guide","hidden":null},{"title":"GameController Setup","slug":"/guides/tools/gamecontroller","hidden":null}],"hidden":false},{"title":"Hardware","slug":"/guides/hardware/working-with-robots","pages":[{"title":"Working with Robots","slug":"/guides/hardware/working-with-robots","hidden":null},{"title":"Flashing a Robot","slug":"/guides/hardware/flashing","hidden":null},{"title":"Servo Setup and Calibration","slug":"/guides/hardware/servo-calibration","hidden":null},{"title":"Batteries","slug":"/guides/hardware/batteries","hidden":null},{"title":"DARwIn Op2 Robot Restoration and Calibration Guide","slug":"/guides/hardware/darwin-op2-guide","hidden":null}],"hidden":false},{"title":"General","slug":"/guides/general/learning-resources","pages":[{"title":"Learning Resources","slug":"/guides/general/learning-resources","hidden":null},{"title":"Contribution Workflow","slug":"/guides/general/contribute","hidden":null},{"title":"RoboCup Setup","slug":"/guides/general/robocup-setup","hidden":null},{"title":"Troubleshooting","slug":"/guides/general/troubleshooting","hidden":null},{"title":"Code Conventions","slug":"/guides/general/code-conventions","hidden":null},{"title":"Glossary","slug":"/guides/general/glossary","hidden":null}],"hidden":false}],"hidden":false},{"title":"Kitchen Sink","slug":"/kitchen-sink/headers","chapters":[{"title":"Markdown","slug":"/kitchen-sink/headers","pages":[{"title":"Headers","slug":"/kitchen-sink/headers","hidden":true},{"title":"Formatting and Paragraphs","slug":"/kitchen-sink/formatting-and-paragraphs","hidden":true},{"title":"Blockquotes","slug":"/kitchen-sink/blockquotes","hidden":true},{"title":"Alerts","slug":"/kitchen-sink/alerts","hidden":true},{"title":"Images","slug":"/kitchen-sink/images","hidden":true},{"title":"Lists","slug":"/kitchen-sink/lists","hidden":true},{"title":"Code","slug":"/kitchen-sink/code","hidden":true},{"title":"Math","slug":"/kitchen-sink/math","hidden":true},{"title":"Table of Contents","slug":"/kitchen-sink/table-of-contents","hidden":true},{"title":"Tables","slug":"/kitchen-sink/tables","hidden":true},{"title":"Collapsible Content","slug":"/kitchen-sink/collapsible","hidden":true},{"title":"GraphViz Diagrams","slug":"/kitchen-sink/graphviz-diagrams","hidden":true},{"title":"Referencing","slug":"/kitchen-sink/referencing","hidden":true}],"hidden":true}],"hidden":true}],"references":null,"hidden":null}},
    "staticQueryHashes": ["3715292327","445096115","466146812"]}