profile
viewpoint
Trent Houliston TrentHouliston University of Newcastle Australia

Fastcode/VisualMesh 10

The VisualMesh detection system

TrentHouliston/FMLP 6

Fast Multi Layer Perceptron

TrentHouliston/Niowire 3

Niowire, The highly scaleable socket server framework

josiahw/LSH 1

simple locality sensitive hashing

RoboCup-Humanoid-TC/RobocupProtocol 1

Protobuf message protocol for the Robocup Humanoid league

TrentHouliston/IMP 1

A OpenCL C++ version of Josiaw's IsomapCuda

JakeFountain/OOGL 0

Object-oriented C++ wrapper for OpenGL.

TrentHouliston/ChromaTagsSim 0

Simulating chromatags to see if they are viable

TrentHouliston/cmake_format 0

Source code formatter for cmake listfiles.

TrentHouliston/EyeDebug 0

This is a simple class made to make debugging easier through the power of the Eyes (O.o) instead of long crazy methods simply to output variables, just use O.o(variable)

push eventFastcode/VisualMesh

Trent Houliston

commit sha f522fdadba3c63d6292c9a2474495364da10ace4

Change lookup in visualmesh.hpp to int to match mesh.hpp

view details

Trent Houliston

commit sha 2a2b4a729d17b2d6017dd6ef11e80d8cd65b6f40

Add missing compile definition when BUILD_OPENCL_ENGINE is manually set off

view details

Trent Houliston

commit sha 4bb4b9e27ffdd945cacce2391b608359fbae2c41

Correct example_net.yaml missing an output layer

view details

Trent Houliston

commit sha cae7d01dc035d334d3c1b710cfbab5dde2a11960

Dump history into yaml rather than pickle as TensorFlow 2.3 history objects can't be pickled

view details

Trent Houliston

commit sha b0c9391b1b458b8d447a3a3444c56192f66f8033

Use training for finding LR as otherwise the batch size is wrong

view details

push time in 17 days

push eventNUbots/NUbots

Trent Houliston

commit sha 467f458c687419056e2487fe468c7f22d19a6965

Fix missing space in clang-format command that prevented formatting (#336)

view details

push time in 21 days

delete branch NUbots/NUbots

delete branch : houliston/format

delete time in 21 days

PR opened NUbots/NUbots

Reviewers
Fix missing space in clang-format command that prevented formatting
+14 -12

0 comment

2 changed files

pr created time in 21 days

create barnchNUbots/NUbots

branch : houliston/format

created branch time in 21 days

delete tag Fastcode/VisualMesh

delete tag : 2.0.0

delete time in 22 days

created tagFastcode/VisualMesh

tagv2.0.0

The VisualMesh detection system

created time in 22 days

created tagFastcode/VisualMesh

tag2.0.0

The VisualMesh detection system

created time in 22 days

release Fastcode/VisualMesh

2.0.0

released time in 22 days

push eventFastcode/VisualMesh

Trent Houliston

commit sha 414d59edf7725c1ce962de653c318531a3733541

Start swapping the math of calculating the mesh over to using n directly

view details

Trent Houliston

commit sha d9640bfa2a0fc0e7efa4b16438960bcd89c21069

Remove unused variable

view details

Trent Houliston

commit sha 57ba7c2dc9fd2a29a8d0d72252f1e7dd21a2dce3

Files missing from commit

view details

Trent Houliston

commit sha e0bee1b625420a392c731b54ccc470c654a9b230

Add code to test the mesh for consistency of sampling

view details

Trent Houliston

commit sha 1434c243380c96d3883ddd58208209e71a0f6d61

Move the projection math out into its own file in preparation for quadtrees

view details

Trent Houliston

commit sha 097631d09752a34b33e3b4eaa526464cb00a6e8a

Split out the generator and write a BSP generator algorithm. Current Issues: Currently the HexaPizza generator still doesn't calculate the neighbours properly. The BSP algorithm is a little slow to generate There currently is no tested code for actually looking up things in the BSP

view details

Trent Houliston

commit sha 80894054f78e040159540d3169243b92390baac9

Remove unused function

view details

Trent Houliston

commit sha 85e80d3528a9893dd0969a3d9983ac6642080e7a

Fix the hexpizzas neighbours so they print correctly

view details

Trent Houliston

commit sha 7847dfd3210c60b5ea48759cde78db106d9447ff

Format the cmake file

view details

Trent Houliston

commit sha 945195893a33070c896e16dcb42c1cdcad810205

Start working on the new method for cutting down bsp trees

view details

Trent Houliston

commit sha 4aca4c8078bfecb5d70f0ae9acbb8313cf756aef

Add a mesh quailty binary that runs the mesh tester and add colours to compile output

view details

Trent Houliston

commit sha 4daae9e9d9b7ddfa628fe6035aade8da3d8fe790

Fix the sorting of the mesh by the BSP

view details

Trent Houliston

commit sha 08a1db49976b072c8cacf1e6da90ec1c1a4c07ce

Make the multi height mesh handle single mesh values better

view details

Trent Houliston

commit sha 88949dc5eb6efc837a3a04a7c62f85c7e0f2d616

Make the ray vectors 3 dimensional rather than 4 to save memory. The vectors are still converted to 4D when uploading to OpenCL, but otherwise it's not needed

view details

Trent Houliston

commit sha c2d7bd98c6d742a60338a967d79a5f25e4ff3c89

Add block select and matrix multiply to the math This is starting to get out of hand here! Perhaps we should move to Eigen

view details

Trent Houliston

commit sha f2160e5bb35c4e4508029831ade69696a0084bdb

Add missing 3d projection code

view details

Trent Houliston

commit sha 6a5c6f5c534c4b504c5e803f78c41f7bf4933c31

Add code for filtering down the BSP using cones

view details

Trent Houliston

commit sha d0c85e54f6577ad63f0cdb0a067f10691548570f

Add the per item check for on screen

view details

Trent Houliston

commit sha d0144c664399edbfbaa6c99bfbaf0195722d9a94

Move the cone math into its own file

view details

Trent Houliston

commit sha 994e6ba0caacd9a01dec971156bb7a24f2b3072a

Remove unused include

view details

push time in 22 days

created tagFastcode/VisualMesh

tagv1.0.0

The VisualMesh detection system

created time in 22 days

release Fastcode/VisualMesh

v1.0.0

released time in 22 days

push eventNUbots/NUbook

Trent Houliston

commit sha 76cd2e8057df872209ead028118b66506b4934c7

Rename support::configuration::NetworkConfiguration to network::NUClearNet (#68) Paired with https://github.com/NUbots/NUbots/pull/334

view details

push time in a month

delete branch NUbots/NUbook

delete branch : houliston/movenuclearnet

delete time in a month

PR merged NUbots/NUbook

Rename NetworkConfiguration to NUClearNet

Paired with https://github.com/NUbots/NUbots/pull/334

+1 -1

0 comment

1 changed file

TrentHouliston

pr closed time in a month

Pull request review commentNUbots/NUbots

Adds Bit-Bots Quintic Walk

+#include "QuinticWalk.h"++#include <fmt/format.h>++#include "extension/Configuration.h"++#include "message/behaviour/FixedWalkCommand.h"+#include "message/motion/GetupCommand.h"+#include "message/motion/KinematicsModel.h"+#include "message/motion/ServoTarget.h"+#include "message/motion/WalkCommand.h"+#include "message/support/SaveConfiguration.h"++#include "utility/math/comparison.h"+#include "utility/math/euler.h"+#include "utility/math/matrix/Transform3D.h"+#include "utility/motion/InverseKinematics.h"+#include "utility/support/eigen_armadillo.h"+#include "utility/support/yaml_expression.h"++namespace module {+namespace motion {++    using extension::Configuration;++    using message::behaviour::ServoCommand;+    using message::input::Sensors;+    using message::motion::DisableWalkEngineCommand;+    using message::motion::EnableWalkEngineCommand;+    using message::motion::ExecuteGetup;+    using message::motion::KillGetup;+    using message::motion::KinematicsModel;+    using message::motion::ServoTarget;+    using message::motion::StopCommand;+    using message::motion::WalkCommand;+    using utility::support::Expression;++    using utility::input::ServoID;+    using utility::math::matrix::Transform3D;+    using utility::motion::kinematics::calculateLegJoints;++    QuinticWalk::QuinticWalk(std::unique_ptr<NUClear::Environment> environment) : Reactor(std::move(environment)) {++        on<Configuration>("QuinticWalk.yaml").then([this](const Configuration& cfg) {+            // Use configuration here from file QuinticWalk.yaml+            params.freq                          = cfg["walk"]["freq"].as<float>();+            params.double_support_ratio          = cfg["walk"]["double_support_ratio"].as<float>();+            params.first_step_swing_factor       = cfg["walk"]["first_step_swing_factor"].as<float>();+            params.foot_distance                 = cfg["walk"]["foot"]["distance"].as<float>();+            params.foot_rise                     = cfg["walk"]["foot"]["rise"].as<float>();+            params.foot_z_pause                  = cfg["walk"]["foot"]["z_pause"].as<float>();+            params.foot_put_down_z_offset        = cfg["walk"]["foot"]["put_down"]["z_offset"].as<float>();+            params.foot_put_down_phase           = cfg["walk"]["foot"]["put_down"]["phase"].as<float>();+            params.foot_put_down_roll_offset     = cfg["walk"]["foot"]["put_down"]["roll_offset"].as<float>();+            params.foot_apex_phase               = cfg["walk"]["foot"]["apex_phase"].as<float>();+            params.foot_overshoot_ratio          = cfg["walk"]["foot"]["overshoot"]["ratio"].as<float>();+            params.foot_overshoot_phase          = cfg["walk"]["foot"]["overshoot"]["phase"].as<float>();+            params.trunk_height                  = cfg["walk"]["trunk"]["height"].as<float>();+            params.trunk_pitch                   = 1.0f + cfg["walk"]["trunk"]["pitch"].as<Expression>();+            params.trunk_phase                   = cfg["walk"]["trunk"]["phase"].as<float>();+            params.trunk_x_offset                = cfg["walk"]["trunk"]["x_offset"].as<float>();+            params.trunk_y_offset                = cfg["walk"]["trunk"]["y_offset"].as<float>();+            params.trunk_swing                   = cfg["walk"]["trunk"]["swing"].as<float>();+            params.trunk_pause                   = cfg["walk"]["trunk"]["pause"].as<float>();+            params.trunk_x_offset_p_coef_forward = cfg["walk"]["trunk"]["x_offset_p_coef"]["forward"].as<float>();+            params.trunk_x_offset_p_coef_turn    = cfg["walk"]["trunk"]["x_offset_p_coef"]["turn"].as<float>();+            params.trunk_pitch_p_coef_forward = 1.0f + cfg["walk"]["trunk"]["pitch_p_coef"]["forward"].as<Expression>();+            params.trunk_pitch_p_coef_turn    = 1.0f + cfg["walk"]["trunk"]["pitch_p_coef"]["turn"].as<Expression>();+            params.kick_length                = cfg["walk"]["kick"]["length"].as<float>();+            params.kick_phase                 = cfg["walk"]["kick"]["phase"].as<float>();+            params.kick_vel                   = cfg["walk"]["kick"]["vel"].as<float>();+            params.pause_duration             = cfg["walk"]["pause"]["duration"].as<float>();++            // Send these parameters to the walk engine+            walk_engine.setParameters(params);++            config.max_step[0] = cfg["max_step"]["x"].as<float>();+            config.max_step[1] = cfg["max_step"]["y"].as<float>();+            config.max_step[2] = cfg["max_step"]["z"].as<float>();+            config.max_step_xy = cfg["max_step"]["xy"].as<float>();++            config.imu_active          = cfg["imu"]["active"].as<bool>();+            config.imu_pitch_threshold = cfg["imu"]["pitch"]["threshold"].as<float>();+            config.imu_roll_threshold  = cfg["imu"]["roll"]["threshold"].as<float>();++            for (int i = 0; i < ServoID::NUMBER_OF_SERVOS; ++i) {+                if ((i >= 6) && (i < 18)) {+                    jointGains[i] = cfg["gains"]["legs"].as<float>();+                }+            }+        });++        on<Startup, Trigger<KinematicsModel>>().then("Update Kinematics Model", [this](const KinematicsModel& model) {+            kinematicsModel = model;+            first_run       = true;+            current_orders.setZero();+            is_left_support  = true;+            falling          = false;+            last_update_time = NUClear::clock::now();+            walk_engine.reset();+        });++        on<Trigger<ExecuteGetup>>().then([this]() { falling = true; });++        on<Trigger<KillGetup>>().then([this]() { falling = false; });++        on<Trigger<StopCommand>>().then([this] { current_orders.setZero(); });++        on<Trigger<WalkCommand>>().then([this](const WalkCommand& walkCommand) {+            // the engine expects orders in [m] not [m/s]. We have to compute by dividing by step frequency which is a+            // double step factor 2 since the order distance is only for a single step, not double step+            const float factor             = (1.0 / (params.freq)) / 2.0;+            const Eigen::Vector3f& command = walkCommand.command.cast<float>() * factor;++            // Clamp velocity command+            Eigen::Vector3f orders =+                command.array().max(-config.max_step.array()).min(config.max_step.array()).matrix();++            // translational orders (x+y) should not exceed combined limit. scale if necessary+            if (config.max_step_xy != 0) {+                float scaling_factor = 1.0f / std::max(1.0f, (orders.x() + orders.y()) / config.max_step_xy);+                orders.cwiseProduct(Eigen::Vector3f(scaling_factor, scaling_factor, 1.0f));+            }++            // warn user that speed was limited+            if (command.x() != orders.x() || command.y() != orders.y() || command.z() != orders.z()) {+                log<NUClear::WARN>(+                    fmt::format("Speed command was x: {} y: {} z: {} xy: {} but maximum is x: {} y: {} z: {} xy: {}",+                                command.x(),+                                command.y(),+                                command.z(),+                                command.x() + command.y(),+                                config.max_step[0] / factor,+                                config.max_step[1] / factor,+                                config.max_step[2] / factor,+                                config.max_step_xy / factor));+            }++            // Update orders+            current_orders = orders;+        });++        on<Trigger<Sensors>>().then([this](const Sensors& sensors) {+            if (config.imu_active) {+                Eigen::Vector3f RPY =+                    utility::math::euler::MatrixToEulerIntrinsic(sensors.Htw.topLeftCorner<3, 3>().cast<float>());++                // compute the pitch offset to the currently wanted pitch of the engine+                float wanted_pitch =+                    params.trunk_pitch + params.trunk_pitch_p_coef_forward * walk_engine.getFootstep().getNext().x()+                    + params.trunk_pitch_p_coef_turn * std::abs(walk_engine.getFootstep().getNext().z());+                RPY.y() += wanted_pitch;++                // threshold pitch and roll+                if (std::abs(RPY[0]) > config.imu_roll_threshold) {+                    log<NUClear::WARN>(fmt::format("Robot roll exceeds threshold - {} > {}",+                                                   std::abs(RPY.x()),+                                                   config.imu_roll_threshold));+                    walk_engine.requestPause();+                }+                else if (std::abs(RPY[1]) > config.imu_pitch_threshold) {+                    log<NUClear::WARN>(fmt::format("Robot pitch exceeds threshold - {} > {}",+                                                   std::abs(RPY.y()),+                                                   config.imu_pitch_threshold));+                    walk_engine.requestPause();+                }+            }+        });++        on<Trigger<EnableWalkEngineCommand>>().then([this](const EnableWalkEngineCommand& command) {+            subsumptionId = command.subsumptionId;+            walk_engine.reset();+            update_handle.enable();+        });++        on<Trigger<DisableWalkEngineCommand>>().then([this] { update_handle.disable(); });++        update_handle = on<Every<UPDATE_FREQUENCY, Per<std::chrono::seconds>>, Single>().then([this]() {+            const float dt = getTimeDelta();++            if (falling) {+                // We are falling, reset walk engine+                walk_engine.reset();+            }+            else {+                // we don't want to walk, even if we have orders, if we are not in the right state+                bool walkableState = true;  // TODO: what is our equivalent here?++                // see if the walk engine has new goals for us+                walkableState = walk_engine.updateState(dt, current_orders, walkableState);++                if ((walk_engine.getState() != engine::WalkEngineState::IDLE) && walkableState) {  // todo+                    calculateJointGoals();+                }+            }+        });+    }  // namespace motion++    float QuinticWalk::getTimeDelta() {+        // compute time delta depended if we are currently in simulation or reality+        float dt;+        auto current_time = NUClear::clock::now();+        // only take real time difference if walking was not stopped before+        // TODO Is this really necessary?+        auto time_diff_ms = std::chrono::duration_cast<std::chrono::milliseconds>(current_time - last_update_time);+        dt                = time_diff_ms.count() / 1000.0f;+        if (dt == 0.0f) {+            // log<NUClear::WARN>(fmt::format("dt was 0 ({})", time_diff_ms.count()));+            dt = 0.001f;+        }+        last_update_time = current_time;+        // time is wrong when we run it for the first time+        if (first_run) {+            first_run = false;+            dt        = 0.0001f;+        }+        return dt;+    }++    void QuinticWalk::calculateJointGoals() {+        /*+        This method computes the next motor goals and publishes them.+        */+        auto setRPY = [&](const float& roll, const float& pitch, const float& yaw) {+            const float halfYaw   = yaw * 0.5f;+            const float halfPitch = pitch * 0.5f;+            const float halfRoll  = roll * 0.5f;+            const float cosYaw    = std::cos(halfYaw);+            const float sinYaw    = std::sin(halfYaw);+            const float cosPitch  = std::cos(halfPitch);+            const float sinPitch  = std::sin(halfPitch);+            const float cosRoll   = std::cos(halfRoll);+            const float sinRoll   = std::sin(halfRoll);+            return Eigen::Quaternionf(cosRoll * cosPitch * cosYaw + sinRoll * sinPitch * sinYaw,  // formerly yzx+                                      sinRoll * cosPitch * cosYaw - cosRoll * sinPitch * sinYaw,  // x+                                      cosRoll * sinPitch * cosYaw + sinRoll * cosPitch * sinYaw,  // y+                                      cosRoll * cosPitch * sinYaw - sinRoll * sinPitch * cosYaw   // z+                                      )+                .normalized()+                .toRotationMatrix();+        };++        // Read the cartesian positions and orientations for trunk and fly foot+        walk_engine.computeCartesianPosition(trunk_pos, trunk_axis, foot_pos, foot_axis, is_left_support);++        // Change goals from support foot based coordinate system to trunk based coordinate system+        Eigen::Affine3f Hst;  // trunk_to_support_foot_goal

If it's only the 0,0,0,1 that's set then if you don't set the translation and linear it would have junk in it besides that final row. That could have been the problem that was occuring

ysims

comment created time in a month

PullRequestReviewEvent

Pull request review commentNUbots/NUbots

Adds Bit-Bots Quintic Walk

+#include "QuinticWalk.h"++#include <fmt/format.h>++#include "extension/Configuration.h"++#include "message/behaviour/FixedWalkCommand.h"+#include "message/motion/GetupCommand.h"+#include "message/motion/KinematicsModel.h"+#include "message/motion/ServoTarget.h"+#include "message/motion/WalkCommand.h"+#include "message/support/SaveConfiguration.h"++#include "utility/math/comparison.h"+#include "utility/math/euler.h"+#include "utility/math/matrix/Transform3D.h"+#include "utility/motion/InverseKinematics.h"+#include "utility/support/eigen_armadillo.h"+#include "utility/support/yaml_expression.h"++namespace module {+namespace motion {++    using extension::Configuration;++    using message::behaviour::ServoCommand;+    using message::input::Sensors;+    using message::motion::DisableWalkEngineCommand;+    using message::motion::EnableWalkEngineCommand;+    using message::motion::ExecuteGetup;+    using message::motion::KillGetup;+    using message::motion::KinematicsModel;+    using message::motion::ServoTarget;+    using message::motion::StopCommand;+    using message::motion::WalkCommand;+    using utility::support::Expression;++    using utility::input::ServoID;+    using utility::math::matrix::Transform3D;+    using utility::motion::kinematics::calculateLegJoints;++    QuinticWalk::QuinticWalk(std::unique_ptr<NUClear::Environment> environment) : Reactor(std::move(environment)) {++        on<Configuration>("QuinticWalk.yaml").then([this](const Configuration& cfg) {+            // Use configuration here from file QuinticWalk.yaml+            params.freq                          = cfg["walk"]["freq"].as<float>();+            params.double_support_ratio          = cfg["walk"]["double_support_ratio"].as<float>();+            params.first_step_swing_factor       = cfg["walk"]["first_step_swing_factor"].as<float>();+            params.foot_distance                 = cfg["walk"]["foot"]["distance"].as<float>();+            params.foot_rise                     = cfg["walk"]["foot"]["rise"].as<float>();+            params.foot_z_pause                  = cfg["walk"]["foot"]["z_pause"].as<float>();+            params.foot_put_down_z_offset        = cfg["walk"]["foot"]["put_down"]["z_offset"].as<float>();+            params.foot_put_down_phase           = cfg["walk"]["foot"]["put_down"]["phase"].as<float>();+            params.foot_put_down_roll_offset     = cfg["walk"]["foot"]["put_down"]["roll_offset"].as<float>();+            params.foot_apex_phase               = cfg["walk"]["foot"]["apex_phase"].as<float>();+            params.foot_overshoot_ratio          = cfg["walk"]["foot"]["overshoot"]["ratio"].as<float>();+            params.foot_overshoot_phase          = cfg["walk"]["foot"]["overshoot"]["phase"].as<float>();+            params.trunk_height                  = cfg["walk"]["trunk"]["height"].as<float>();+            params.trunk_pitch                   = 1.0f + cfg["walk"]["trunk"]["pitch"].as<Expression>();+            params.trunk_phase                   = cfg["walk"]["trunk"]["phase"].as<float>();+            params.trunk_x_offset                = cfg["walk"]["trunk"]["x_offset"].as<float>();+            params.trunk_y_offset                = cfg["walk"]["trunk"]["y_offset"].as<float>();+            params.trunk_swing                   = cfg["walk"]["trunk"]["swing"].as<float>();+            params.trunk_pause                   = cfg["walk"]["trunk"]["pause"].as<float>();+            params.trunk_x_offset_p_coef_forward = cfg["walk"]["trunk"]["x_offset_p_coef"]["forward"].as<float>();+            params.trunk_x_offset_p_coef_turn    = cfg["walk"]["trunk"]["x_offset_p_coef"]["turn"].as<float>();+            params.trunk_pitch_p_coef_forward = 1.0f + cfg["walk"]["trunk"]["pitch_p_coef"]["forward"].as<Expression>();+            params.trunk_pitch_p_coef_turn    = 1.0f + cfg["walk"]["trunk"]["pitch_p_coef"]["turn"].as<Expression>();+            params.kick_length                = cfg["walk"]["kick"]["length"].as<float>();+            params.kick_phase                 = cfg["walk"]["kick"]["phase"].as<float>();+            params.kick_vel                   = cfg["walk"]["kick"]["vel"].as<float>();+            params.pause_duration             = cfg["walk"]["pause"]["duration"].as<float>();++            // Send these parameters to the walk engine+            walk_engine.setParameters(params);++            config.max_step[0] = cfg["max_step"]["x"].as<float>();+            config.max_step[1] = cfg["max_step"]["y"].as<float>();+            config.max_step[2] = cfg["max_step"]["z"].as<float>();+            config.max_step_xy = cfg["max_step"]["xy"].as<float>();++            config.imu_active          = cfg["imu"]["active"].as<bool>();+            config.imu_pitch_threshold = cfg["imu"]["pitch"]["threshold"].as<float>();+            config.imu_roll_threshold  = cfg["imu"]["roll"]["threshold"].as<float>();++            for (int i = 0; i < ServoID::NUMBER_OF_SERVOS; ++i) {+                if ((i >= 6) && (i < 18)) {+                    jointGains[i] = cfg["gains"]["legs"].as<float>();+                }+            }+        });++        on<Startup, Trigger<KinematicsModel>>().then("Update Kinematics Model", [this](const KinematicsModel& model) {+            kinematicsModel = model;+            first_run       = true;+            current_orders.setZero();+            is_left_support  = true;+            falling          = false;+            last_update_time = NUClear::clock::now();+            walk_engine.reset();+        });++        on<Trigger<ExecuteGetup>>().then([this]() { falling = true; });++        on<Trigger<KillGetup>>().then([this]() { falling = false; });++        on<Trigger<StopCommand>>().then([this] { current_orders.setZero(); });++        on<Trigger<WalkCommand>>().then([this](const WalkCommand& walkCommand) {+            // the engine expects orders in [m] not [m/s]. We have to compute by dividing by step frequency which is a+            // double step factor 2 since the order distance is only for a single step, not double step+            const float factor             = (1.0 / (params.freq)) / 2.0;+            const Eigen::Vector3f& command = walkCommand.command.cast<float>() * factor;++            // Clamp velocity command+            Eigen::Vector3f orders =+                command.array().max(-config.max_step.array()).min(config.max_step.array()).matrix();++            // translational orders (x+y) should not exceed combined limit. scale if necessary+            if (config.max_step_xy != 0) {+                float scaling_factor = 1.0f / std::max(1.0f, (orders.x() + orders.y()) / config.max_step_xy);+                orders.cwiseProduct(Eigen::Vector3f(scaling_factor, scaling_factor, 1.0f));+            }++            // warn user that speed was limited+            if (command.x() != orders.x() || command.y() != orders.y() || command.z() != orders.z()) {+                log<NUClear::WARN>(+                    fmt::format("Speed command was x: {} y: {} z: {} xy: {} but maximum is x: {} y: {} z: {} xy: {}",+                                command.x(),+                                command.y(),+                                command.z(),+                                command.x() + command.y(),+                                config.max_step[0] / factor,+                                config.max_step[1] / factor,+                                config.max_step[2] / factor,+                                config.max_step_xy / factor));+            }++            // Update orders+            current_orders = orders;+        });++        on<Trigger<Sensors>>().then([this](const Sensors& sensors) {+            if (config.imu_active) {+                Eigen::Vector3f RPY =+                    utility::math::euler::MatrixToEulerIntrinsic(sensors.Htw.topLeftCorner<3, 3>().cast<float>());++                // compute the pitch offset to the currently wanted pitch of the engine+                float wanted_pitch =+                    params.trunk_pitch + params.trunk_pitch_p_coef_forward * walk_engine.getFootstep().getNext().x()+                    + params.trunk_pitch_p_coef_turn * std::abs(walk_engine.getFootstep().getNext().z());+                RPY.y() += wanted_pitch;++                // threshold pitch and roll+                if (std::abs(RPY[0]) > config.imu_roll_threshold) {+                    log<NUClear::WARN>(fmt::format("Robot roll exceeds threshold - {} > {}",+                                                   std::abs(RPY.x()),+                                                   config.imu_roll_threshold));+                    walk_engine.requestPause();+                }+                else if (std::abs(RPY[1]) > config.imu_pitch_threshold) {+                    log<NUClear::WARN>(fmt::format("Robot pitch exceeds threshold - {} > {}",+                                                   std::abs(RPY.y()),+                                                   config.imu_pitch_threshold));+                    walk_engine.requestPause();+                }+            }+        });++        on<Trigger<EnableWalkEngineCommand>>().then([this](const EnableWalkEngineCommand& command) {+            subsumptionId = command.subsumptionId;+            walk_engine.reset();+            update_handle.enable();+        });++        on<Trigger<DisableWalkEngineCommand>>().then([this] { update_handle.disable(); });++        update_handle = on<Every<UPDATE_FREQUENCY, Per<std::chrono::seconds>>, Single>().then([this]() {+            const float dt = getTimeDelta();++            if (falling) {+                // We are falling, reset walk engine+                walk_engine.reset();+            }+            else {+                // we don't want to walk, even if we have orders, if we are not in the right state+                bool walkableState = true;  // TODO: what is our equivalent here?++                // see if the walk engine has new goals for us+                walkableState = walk_engine.updateState(dt, current_orders, walkableState);++                if ((walk_engine.getState() != engine::WalkEngineState::IDLE) && walkableState) {  // todo+                    calculateJointGoals();+                }+            }+        });+    }  // namespace motion++    float QuinticWalk::getTimeDelta() {+        // compute time delta depended if we are currently in simulation or reality+        float dt;+        auto current_time = NUClear::clock::now();+        // only take real time difference if walking was not stopped before+        // TODO Is this really necessary?+        auto time_diff_ms = std::chrono::duration_cast<std::chrono::milliseconds>(current_time - last_update_time);+        dt                = time_diff_ms.count() / 1000.0f;+        if (dt == 0.0f) {+            // log<NUClear::WARN>(fmt::format("dt was 0 ({})", time_diff_ms.count()));+            dt = 0.001f;+        }+        last_update_time = current_time;+        // time is wrong when we run it for the first time+        if (first_run) {+            first_run = false;+            dt        = 0.0001f;+        }+        return dt;+    }++    void QuinticWalk::calculateJointGoals() {+        /*+        This method computes the next motor goals and publishes them.+        */+        auto setRPY = [&](const float& roll, const float& pitch, const float& yaw) {+            const float halfYaw   = yaw * 0.5f;+            const float halfPitch = pitch * 0.5f;+            const float halfRoll  = roll * 0.5f;+            const float cosYaw    = std::cos(halfYaw);+            const float sinYaw    = std::sin(halfYaw);+            const float cosPitch  = std::cos(halfPitch);+            const float sinPitch  = std::sin(halfPitch);+            const float cosRoll   = std::cos(halfRoll);+            const float sinRoll   = std::sin(halfRoll);+            return Eigen::Quaternionf(cosRoll * cosPitch * cosYaw + sinRoll * sinPitch * sinYaw,  // formerly yzx+                                      sinRoll * cosPitch * cosYaw - cosRoll * sinPitch * sinYaw,  // x+                                      cosRoll * sinPitch * cosYaw + sinRoll * cosPitch * sinYaw,  // y+                                      cosRoll * cosPitch * sinYaw - sinRoll * sinPitch * cosYaw   // z+                                      )+                .normalized()+                .toRotationMatrix();+        };++        // Read the cartesian positions and orientations for trunk and fly foot+        walk_engine.computeCartesianPosition(trunk_pos, trunk_axis, foot_pos, foot_axis, is_left_support);++        // Change goals from support foot based coordinate system to trunk based coordinate system+        Eigen::Affine3f Hst;  // trunk_to_support_foot_goal

I believe that setting the translation sets the right-hand column, and linear is the upper 3x3, but this might have something to do with the 0,0,0,1 at the bottom of the matrix? However, I think that the default constructor of Affine3f is already identity but you would have to confirm.

ysims

comment created time in a month

PullRequestReviewEvent

push eventNUbots/NUbots

Trent Houliston

commit sha 0d2cc7603899e04174b62e321840898d7c4fedec

Add an image decompressor to allow playback of nbs files with compressed images (#335) Co-authored-by: Alex Biddulph <c3124185@uon.edu.au>

view details

push time in a month

delete branch NUbots/NUbots

delete branch : houliston/decompress

delete time in a month

Pull request review commentNUbots/NUbots

Add an image decompressor to allow playback of nbs files with compressed images

+#ifndef MODULE_INPUT_IMAGEDECOMPRESSOR_H+#define MODULE_INPUT_IMAGEDECOMPRESSOR_H++#include <atomic>+#include <cstdint>+#include <memory>+#include <mutex>+#include <nuclear>++#include "decompressor/DecompressorFactory.h"++namespace module {+namespace input {++    class ImageDecompressor : public NUClear::Reactor {+    private:+        struct DecompressorContext {+            struct Decompressor {+                /// This atomic bool gets turned on/off depending on if it is in use+                std::unique_ptr<std::atomic<bool>> active;

It does have to be a unique pointer due to the way atomics work

TrentHouliston

comment created time in a month

push eventNUbots/NUbots

Trent Houliston

commit sha 358be09c57dcd6ac55f4d64fb02fac8b41a3ae99

Update module/input/ImageDecompressor/src/ImageDecompressor.cpp Co-authored-by: Alex Biddulph <c3124185@uon.edu.au>

view details

push time in a month

Pull request review commentNUbots/NUbots

Added comments to motion messages

 message KinematicsModel {         mat3 foot        = 9;     } -    Leg         leg                       = 1;-    Head        head                      = 2;-    Arm         arm                       = 3;-    MassModel   massModel                 = 4;-    TensorModel tensorModel               = 5;-    float       TEAMDARWINCHEST_TO_ORIGIN = 6;+    // Instantiations of the config containers.+    Leg         leg         = 1;+    Head        head        = 2;+    Arm         arm         = 3;+    MassModel   massModel   = 4;+    TensorModel tensorModel = 5;++    float TEAMDARWINCHEST_TO_ORIGIN = 6;

Doubt it would cause problems anymore

KipHamiltons

comment created time in a month

create barnchNUbots/NUbots

branch : houliston/decompress

created branch time in a month

push eventNUbots/NUbots

Trent Houliston

commit sha a965365242a1a1f4ca5f84a4fa864c8cfdac21e6

Move the NetworkConfiguration module to NUClearNet (#334)

view details

push time in a month

delete branch NUbots/NUbots

delete branch : houliston/renamenet

delete time in a month

PR merged NUbots/NUbots

Reviewers
Move the NetworkConfiguration module to NUClearNet

Currently, the name NetworkConfiguration is a little generic given that soon we may have other systems that use the network. Moving this module makes it clearer what it does.

+135 -127

0 comment

26 changed files

TrentHouliston

pr closed time in a month

push eventNUbots/NUbots

Trent Houliston

commit sha b592451ba353f042445411d477989df268c3156a

Update README.md

view details

push time in a month

PR opened NUbots/NUbook

Reviewers
Rename NetworkConfiguration to NUClearNet

Paired with https://github.com/NUbots/NUbots/pull/334

+1 -1

0 comment

1 changed file

pr created time in a month

create barnchNUbots/NUbook

branch : houliston/movenuclearnet

created branch time in a month

push eventNUbots/NUbots

Trent Houliston

commit sha 89638a22d1998432c1044030cff70658e220a7b1

Another one

view details

push time in a month

push eventNUbots/NUbots

Trent Houliston

commit sha b2637de794cdd49047e983f1154ef11c8df0ee27

Missed one

view details

push time in a month

push eventNUbots/NUbots

Trent Houliston

commit sha b3716b38713881acc7cd777c8e9ffc32b3c72cdb

Remove gradient from the cone as as it's duplicate information (#332)

view details

Trent Houliston

commit sha f49ad6c27fbe8afa7cb11b54b7d8c8a3dda5d447

Update some Visual Studio Code settings (#333) Co-authored-by: Alex Biddulph <c3124185@uon.edu.au>

view details

Trent Houliston

commit sha d660d5a1c59bc514b93e894bd8daeefbcf701725

Make the Dockerfile build as root and do the user creation at the end (#331) Co-authored-by: Alex Biddulph <c3124185@uon.edu.au>

view details

Trent Houliston

commit sha 9c20d46bbad3d8ae7e4348822bf049367ebdbbbc

Remove id from servos (#328)

view details

Trent Houliston

commit sha 5d752babefe08bb3e7cbee2e2f542e2a54483cce

Make DataPlayback cleaner and better able to handle multiple files (#323) Co-authored-by: Alex Biddulph <c3124185@uon.edu.au>

view details

Trent Houliston

commit sha ba84375f81528bbdcd4055021e8ff41bea98807c

Merge branch 'master' into houliston/renamenet

view details

push time in a month

PR opened NUbots/NUbots

Reviewers
Move the NetworkConfiguration module to NUClearNet

Currently, the name NetworkConfiguration is a little generic given that soon we may have other systems that use the network. Moving this module makes it clearer what it does.

+110 -115

0 comment

24 changed files

pr created time in a month

create barnchNUbots/NUbots

branch : houliston/renamenet

created branch time in a month

push eventNUbots/NUbots

Trent Houliston

commit sha 5d752babefe08bb3e7cbee2e2f542e2a54483cce

Make DataPlayback cleaner and better able to handle multiple files (#323) Co-authored-by: Alex Biddulph <c3124185@uon.edu.au>

view details

push time in a month

delete branch NUbots/NUbots

delete branch : houliston/cleanerplayback

delete time in a month

PR merged NUbots/NUbots

Reviewers
Make DataPlayback cleaner and better able to handle multiple files

This also makes the configuration no longer generated so it's easier to work with these files in docker

Pairs with NUbook PR

+307 -218

1 comment

12 changed files

TrentHouliston

pr closed time in a month

Pull request review commentNUbots/NUbook

Add information on the DataPlayback module

+---+section: System+chapter: Subsystems+title: Logging+description: Logging and how it works in the NUbots codebase.+slug: /system/subsystems/logging+---++# Data Playback++The DataPlayback module will allow you to play back `.nbs` files as if they were happening in realtime. This can be very useful when you are trying to diagnose a problem for which you have a recording since you can continuously play back the same data.++The module will buffer up packets from the future and emit them at the same rate that they were emitted originally.++## Usage++Add `support::logging::DataPlayback` to your role file and comment out the roles that you want the `nbs` files to replace. For example, if you are playing back `message.input.Sensors` you need to comment out `platform::darwin::SensorFilter` from your role otherwise you will have two different modules emitting conflicting `Sensors` messages. You must recompile your role for these changes to take effect.++In order to play back the messages you need to enable the message types that are the input to the modules that you wish to test by setting them to true in the configuration (e.g. `message.input.sensors: true`). Make sure the `.nbs` file contains the messages you are trying to emit (you can check with `./b nbs stats <nbs-file>`).
In order to play back the messages you need to enable the message types that are the input to the modules that you wish to test by setting them to true in the configuration (e.g. `message.input.Sensors: true`). Make sure the `.nbs` file contains the messages you are trying to emit (you can check with `./b nbs stats <nbs-file>`).
Bidski

comment created time in a month

Pull request review commentNUbots/NUbook

Add information on the DataPlayback module

+---+section: System+chapter: Subsystems+title: Logging+description: Logging and how it works in the NUbots codebase.+slug: /system/subsystems/logging+---++# Data Playback++The DataPlayback module will allow you to play back `.nbs` files as if they were happening in realtime. This can be very useful when you are trying to diagnose a problem for which you have a recording since you can continuously play back the same data.++The module will buffer up packets from the future and emit them at the same rate that they were emitted originally.++## Usage++Add `support::logging::DataPlayback` to your role file and comment out the roles that you want the `nbs` files to replace. For example, if you are playing back `message.input.Sensors` you need to comment out `platform::darwin::SensorFilter` from your role otherwise you will have two different modules emitting conflicting `Sensors` messages. You must recompile your role for these changes to take effect.++In order to play back the messages you need to enable the message types that are the input to the modules that you wish to test by setting them to true in the configuration (e.g. `message.input.sensors: true`). Make sure the `.nbs` file contains the messages you are trying to emit (you can check with `./b nbs stats <nbs-file>`).++`nbs` files can be provided to the module via the configuration file or via the command line. If the configuration file has arguments those are used first. If there are no files provided in the configuration file, the arguments from the command line are used instead. This is so that if you have another module in your role that relies on command line arguments you have an alternate way to provide these files.
`nbs` files can be provided to the module via the configuration file or via the command line. If the configuration file has arguments those are used. If there are no files provided in the configuration file, the arguments from the command line are used instead. This is so that if you have another module in your role that relies on command line arguments you have an alternate way to provide these files.
Bidski

comment created time in a month

push eventNUbots/NUbots

Trent Houliston

commit sha 907ba5870891bb6c7aca89b3a4037ef4b33ac370

Add a tool for filtering out message types from nbs files (#329) Co-authored-by: Alex Biddulph <c3124185@uon.edu.au>

view details

Trent Houliston

commit sha b3716b38713881acc7cd777c8e9ffc32b3c72cdb

Remove gradient from the cone as as it's duplicate information (#332)

view details

Trent Houliston

commit sha f49ad6c27fbe8afa7cb11b54b7d8c8a3dda5d447

Update some Visual Studio Code settings (#333) Co-authored-by: Alex Biddulph <c3124185@uon.edu.au>

view details

Trent Houliston

commit sha d660d5a1c59bc514b93e894bd8daeefbcf701725

Make the Dockerfile build as root and do the user creation at the end (#331) Co-authored-by: Alex Biddulph <c3124185@uon.edu.au>

view details

Trent Houliston

commit sha 9c20d46bbad3d8ae7e4348822bf049367ebdbbbc

Remove id from servos (#328)

view details

Trent Houliston

commit sha 3c372273d61de8c115275a81f2b33fc75aa5f742

Merge branch 'master' into houliston/cleanerplayback

view details

push time in a month

delete branch NUbots/NUbots

delete branch : TrentHouliston-patch-1

delete time in a month

push eventNUbots/NUbots

Trent Houliston

commit sha 9c20d46bbad3d8ae7e4348822bf049367ebdbbbc

Remove id from servos (#328)

view details

push time in a month

PR merged NUbots/NUbots

Remove id from servos

As the servos list is always looked up by id anyway. If this field contained anything other than it's index it would cause bugs. Therefore it shouldn't exist in the first place

+2 -12

3 comments

3 changed files

TrentHouliston

pr closed time in a month

push eventNUbots/NUbots

Josephus Paye II

commit sha f6d0c492962e66a3fc966580fbd4f3ac368a4989

Fix Docker mount error in WSL 2 (#330)

view details

Trent Houliston

commit sha 907ba5870891bb6c7aca89b3a4037ef4b33ac370

Add a tool for filtering out message types from nbs files (#329) Co-authored-by: Alex Biddulph <c3124185@uon.edu.au>

view details

Trent Houliston

commit sha b3716b38713881acc7cd777c8e9ffc32b3c72cdb

Remove gradient from the cone as as it's duplicate information (#332)

view details

Trent Houliston

commit sha f49ad6c27fbe8afa7cb11b54b7d8c8a3dda5d447

Update some Visual Studio Code settings (#333) Co-authored-by: Alex Biddulph <c3124185@uon.edu.au>

view details

Trent Houliston

commit sha d660d5a1c59bc514b93e894bd8daeefbcf701725

Make the Dockerfile build as root and do the user creation at the end (#331) Co-authored-by: Alex Biddulph <c3124185@uon.edu.au>

view details

Trent Houliston

commit sha 40dda4915d2e44c2c2dddca502cfdc58fe467a01

Merge branch 'master' into TrentHouliston-patch-1

view details

push time in a month

push eventNUbots/NUbots

Trent Houliston

commit sha d660d5a1c59bc514b93e894bd8daeefbcf701725

Make the Dockerfile build as root and do the user creation at the end (#331) Co-authored-by: Alex Biddulph <c3124185@uon.edu.au>

view details

push time in a month

delete branch NUbots/NUbots

delete branch : houliston/rootdocker

delete time in a month

PR merged NUbots/NUbots

Make the Dockerfile build as root and do the user creation at the end

This means that cases where the $USERID who is using the dockerfile is not 1000 can build a docker image with their own ID so you don't get conflicts

+51 -57

1 comment

5 changed files

TrentHouliston

pr closed time in a month

push eventNUbots/NUbots

Trent Houliston

commit sha b0189a2047c73d5459ab0efc3299141ac2c8edad

Apply suggestions from code review Co-authored-by: Alex Biddulph <c3124185@uon.edu.au>

view details

push time in a month

Pull request review commentNUbots/NUbots

Make the Dockerfile build as root and do the user creation at the end

 function(ToolchainLibraryFinder)   include(FindPackageHandleStandardArgs)   find_package_handle_standard_args(     ${PACKAGE_NAME}-    FOUND_VAR-    ${PACKAGE_NAME}_FOUND-    REQUIRED_VARS-    ${required_vars}-    VERSION_VAR-    ${PACKAGE_NAME}_VERSION-    # VERSION_VAR "${MAJOR}.${MINOR}.${PATCH}")+    FOUND_VAR ${PACKAGE_NAME}_FOUND+    REQUIRED_VARS ${required_vars}+    VERSION_VAR ${PACKAGE_NAME}_VERSION # VERSION_VAR "${MAJOR}.${MINOR}.${PATCH}")

Because it's what cmake_format demands

TrentHouliston

comment created time in a month

push eventNUbots/NUbots

Trent Houliston

commit sha 0067f450a0637e31504581a85db48537285d21ba

Replace loop with lookup

view details

push time in a month

pull request commentNUbots/NUbots

Remove id from servos

The problem is if we use both methods it just gets confusing. 99% of the time we use the array using the enum. The other time in HeadBehaviour we do an entire loop through every servo just to try and find one we are looking for.

TrentHouliston

comment created time in a month

push eventNUbots/NUbots

Trent Houliston

commit sha b3716b38713881acc7cd777c8e9ffc32b3c72cdb

Remove gradient from the cone as as it's duplicate information (#332)

view details

Trent Houliston

commit sha f49ad6c27fbe8afa7cb11b54b7d8c8a3dda5d447

Update some Visual Studio Code settings (#333) Co-authored-by: Alex Biddulph <c3124185@uon.edu.au>

view details

Trent Houliston

commit sha dc0b80f0a44536c581f144e60c793a60a414149b

Merge branch 'master' into houliston/rootdocker

view details

push time in a month

push eventNUbots/NUbots

Trent Houliston

commit sha f49ad6c27fbe8afa7cb11b54b7d8c8a3dda5d447

Update some Visual Studio Code settings (#333) Co-authored-by: Alex Biddulph <c3124185@uon.edu.au>

view details

push time in a month

delete branch NUbots/NUbots

delete branch : houliston/vscodesettings

delete time in a month

PR merged NUbots/NUbots

Reviewers
Update some Visual Studio Code settings

Make the spell checker use non-american spelling and add some settings to make the editor better display completion/errors

+10 -3

0 comment

2 changed files

TrentHouliston

pr closed time in a month

push eventNUbots/NUbots

Trent Houliston

commit sha 8d94cd44e86cfac6e5969497bac57ab664554c6c

Update .devcontainer.json Co-authored-by: Alex Biddulph <c3124185@uon.edu.au>

view details

push time in a month

Pull request review commentNUbots/NUbots

Update some Visual Studio Code settings

   "image": "nubots:generic",   "workspaceMount": "type=bind,consistency=delegated,src=${localWorkspaceFolder},dst=/home/nubots/NUbots",   "workspaceFolder": "/home/nubots/NUbots",-  "runArgs": [-    "--mount",-    "type=volume,src=nubots_generic_build,dst=/home/nubots/build,consistency=delegated"+  "mounts": [+    "type=volume,src=horus_generic_build,dst=/home/fourtel/build,consistency=delegated"

Oops

TrentHouliston

comment created time in a month

push eventNUbots/NUbots

Trent Houliston

commit sha b3716b38713881acc7cd777c8e9ffc32b3c72cdb

Remove gradient from the cone as as it's duplicate information (#332)

view details

Trent Houliston

commit sha df11330f3664dc3cff3d4f01a7dfa22500a9cc57

Merge branch 'master' into houliston/vscodesettings

view details

push time in a month

push eventNUbots/NUbots

Trent Houliston

commit sha b3716b38713881acc7cd777c8e9ffc32b3c72cdb

Remove gradient from the cone as as it's duplicate information (#332)

view details

push time in a month

delete branch NUbots/NUbots

delete branch : houliston/removegradient

delete time in a month

PR merged NUbots/NUbots

Remove gradient from the cone as as it's duplicate information

Radius and gradient are the same number and having both is terrible

+8 -11

0 comment

3 changed files

TrentHouliston

pr closed time in a month

PR opened NUbots/NUbots

Reviewers
Update some Visual Studio Code settings
+11 -4

0 comment

2 changed files

pr created time in a month

create barnchNUbots/NUbots

branch : houliston/vscodesettings

created branch time in a month

push eventNUbots/NUbots

Trent Houliston

commit sha a477022a4b05592199ab92c53f70b2513a3fe972

Update module/support/logging/DataPlayback/README.md Co-authored-by: Alex Biddulph <c3124185@uon.edu.au>

view details

push time in a month

Pull request review commentNUbots/NUbots

Make DataPlayback cleaner and better able to handle multiple files

     "files.trimFinalNewlines": true,     "files.trimTrailingWhitespace": true,     "files.eol": "\n",+    "cSpell.language": "en-GB",     "editor.rulers": [         120     ],+    "protoc": {+        "options": [+            "-I${workspaceFolder}/nuclear/message/proto"+        ]+    },     "python.formatting.provider": "black",+    "yaml.format.printWidth": 120,

Those are so that the compilation/errors for protobuf works properly in vscode. To do that they need the include path

TrentHouliston

comment created time in a month

Pull request review commentNUbots/NUbots

Remove gradient from the cone as as it's duplicate information

 namespace vision {                         }                          // Ball cam space info-                        b.cone.axis     = horizon.Hcw.topLeftCorner<3, 3>().cast<float>() * axis;-                        float proj      = 1.0f / radius;-                        b.cone.gradient = std::sqrt(proj * proj - 1.0f);-                        b.cone.radius   = radius;+                        b.cone.axis   = horizon.Hcw.topLeftCorner<3, 3>().cast<float>() * axis;+                        float proj    = 1.0f / radius;

Removed

TrentHouliston

comment created time in a month

push eventNUbots/NUbots

Trent Houliston

commit sha bf8bb1effaf94bf947339f2288dc38f703c3b789

proj is now unused variable

view details

push time in a month

push eventNUbots/NUbots

Trent Houliston

commit sha 1fdaf8c312b2c8aa7a24afdac55b93acad490a64

Remove vestigial configuration

view details

Trent Houliston

commit sha 7e98174b036825d66de500c9f803b920acb6ca2b

Make the symlink be a dependent of the module so it doesn't constantly rebuild

view details

push time in a month

Pull request review commentNUbots/NUbots

Remove gradient from the cone as as it's duplicate information

 message Frustum { }  message Cone {-    fvec3 axis     = 1;-    float gradient = 2;-    float radius   = 3;+    fvec3 axis = 1;+    // Cos(theta) of the cone angle+    float radius = 3;

Would mean old NBS files won't play properly... Do we have any we care about?

TrentHouliston

comment created time in a month

push eventNUbots/NUbots

Trent Houliston

commit sha e215ef3fb4061aea75c3e3ff1e2eea87ca339f5d

Formatting

view details

push time in a month

pull request commentNUbots/NUbook

added walk through of foot and shoulder servo

The flow of this page is bugging me :(

I think we need to break it up into a number of separate sections, each section dealing with one specific thing

  • How to repair a servo
  • How to remove the NUC
  • How to install the NUC
  • How to detach the arm from the shoulder
  • How to detach the shoulder from the torso
  • How to attach the arm to the shoulder
  • How to attach the shoulder to the torso
  • etc

Then the section on repairing the shoulder pitch servo can just be

  1. Detach arm from shoulder
  2. Detach shoulder from torso
  3. Remove NUC
  4. Remove shoulder pitch servo
  5. Repair/replace shoulder pitch servo
  6. Install shoulder pitch servo
  7. Install NUC
  8. Attach shoulder to torso
  9. Attach arm to shoulder
  10. Test

And you can then rely on the other sections to provide the details on each of the steps listed in the section on repairing the shoulder pitch servo, and repairing other servos can then follow the same format

Thoughts @tayloryoung6396 @JosephusPaye @ysims @TrentHouliston ?

I think that the best way to go about this would be to copy what sites like ifixit do with their teardown/rebuild instructions. Those are super useful and really easy to follow. Is there a way we can make it behave like that?

Basically you have a bunch of steps that you need to take to do a specific task and present them in order.

abihall

comment created time in a month

Pull request review commentNUbots/NUbook

added walk through of foot and shoulder servo

 title: Working with Robots description: How to safely handle and work with robots. slug: /guides/hardware/working-with-robots ---++## Aligning an Ankle++An alignment of a ankle may need to be done if the foot and the leg of the robot aren't perpendicular when standing. +An ankle alignment may also be necessary when the foot has come loose. ++To align an ankle correctly perform the following instructions:++1. On the inner part of the robots leg, unscrew the screws holding the plastic casing to the the ankle and knee servo. +Remove the plastic casing, as seen in the following image:+![leg cover](./images/ankle_leg/leg_cover.jpg 'leg cover')++2. There should be a silver disk, the following photo is a close up:+![servo close up](./images/ankle_leg/servo_close.jpg 'servo close up')+There are three small indents on the silver disk, two on one side and one on the other. The single dot should be pointing towards the ground when the robot is standing and the other two dots towards the head.+These three dots form an arrow, this arrow should be pointing downwards when the robot is standing.++3. Manually move the disk on the servo so it is in the correct orientation ++4. Place the plastic cover back on and replace all the screws. When replacing the screws, one hole must be left without a screw to allow for the servo to move. The hole left without a screw is the largest hole, which can be seen on the right of the following image:

It might not be like this anymore, but I went the arrow supposed to point away from the hard stop on the servo? So that when it rotates it will always rotate away from the hard stop?

abihall

comment created time in 2 months

push eventNUbots/NUbots

Trent Houliston

commit sha 4aba61e334d75d0aead03f9106e201004f57bfb7

Update Geometry.proto

view details

push time in 2 months

push eventNUbots/NUbots

Trent Houliston

commit sha 90330a7abcf3c4bce7994234f7676721dec1c18d

Remove from virtual ball

view details

push time in 2 months

push eventNUbots/NUbots

Trent Houliston

commit sha 7ce67ce1117c47077236edb80c110e0cfb4b0fcd

Remove from ball detector

view details

push time in 2 months

PR opened NUbots/NUbots

Remove gradient from the cone as as it's duplicate information

Radius and gradient are the same number and having both is terrible

+3 -3

0 comment

1 changed file

pr created time in 2 months

create barnchNUbots/NUbots

branch : houliston/removegradient

created branch time in 2 months

CommitCommentEvent

Pull request review commentNUbots/dashboard

Implement UDP networking layer

 import minimist from 'minimist'; import favicon from 'serve-favicon'; import sio from 'socket.io'; -import { WebSocketProxyUDPServer } from './network/network';-import { WebSocketServer } from './network/web_socket_server';+import { UDPServers } from './network/network'; +// Process command line arguments const args = minimist(process.argv.slice(2));-const teamAAddress = args.team_a || '239.226.152.162';-const teamBAddress = args.team_b || '239.226.152.163';++// Get all of the teams from the command line+// Fall back to our defaults if none were specified+let teams = args._;+if (teams.length === 0) {+  teams = ['Red Team:239.226.152.162:9917', 'Blue Team:239.226.152.163:9917'];+}++// Convert command line data into a more usable format+const teamData = teams.map((team: string) => {+  const nameSplit = team.indexOf(':');

But you would no longer have the confusion between the name, IP and port. Because I imagine you could in theory have colons in the team name too

Bidski

comment created time in 2 months

Pull request review commentNUbots/dashboard

Implement UDP networking layer

 import minimist from 'minimist'; import favicon from 'serve-favicon'; import sio from 'socket.io'; -import { WebSocketProxyUDPServer } from './network/network';-import { WebSocketServer } from './network/web_socket_server';+import { UDPServers } from './network/network'; +// Process command line arguments const args = minimist(process.argv.slice(2));-const teamAAddress = args.team_a || '239.226.152.162';-const teamBAddress = args.team_b || '239.226.152.163';++// Get all of the teams from the command line+// Fall back to our defaults if none were specified+let teams = args._;+if (teams.length === 0) {+  teams = ['Red Team:239.226.152.162:9917', 'Blue Team:239.226.152.163:9917'];+}++// Convert command line data into a more usable format+const teamData = teams.map((team: string) => {+  const nameSplit = team.indexOf(':');

That's what quotes are for

Bidski

comment created time in 2 months

Pull request review commentNUbots/dashboard

Implement UDP networking layer

 import minimist from 'minimist'; import favicon from 'serve-favicon'; import sio from 'socket.io'; -import { WebSocketProxyUDPServer } from './network/network';-import { WebSocketServer } from './network/web_socket_server';+import { UDPServers } from './network/network'; +// Process command line arguments const args = minimist(process.argv.slice(2));-const teamAAddress = args.team_a || '239.226.152.162';-const teamBAddress = args.team_b || '239.226.152.163';++// Get all of the teams from the command line+// Fall back to our defaults if none were specified+let teams = args._;+if (teams.length === 0) {+  teams = ['Red Team:239.226.152.162:9917', 'Blue Team:239.226.152.163:9917'];+}++// Convert command line data into a more usable format+const teamData = teams.map((team: string) => {+  const nameSplit = team.indexOf(':');

The other option is we let the shell separate the tokens and use spaces, every 3 values is a name, IP, port

Bidski

comment created time in 2 months

push eventNUbots/NUbots

Trent Houliston

commit sha 0cb4c9fcdc55388bb033df131a9156e5e20a2954

cmake-format

view details

push time in 2 months

Pull request review commentNUbots/dashboard

Implement UDP networking layer

 import compression from 'compression'; import history from 'connect-history-api-fallback'; import express from 'express'; import http from 'http';+import minimist from 'minimist'; import favicon from 'serve-favicon';+import sio from 'socket.io';++import { WebSocketProxyUDPServer } from './network/network';+import { WebSocketServer } from './network/web_socket_server';++const args = minimist(process.argv.slice(2));+const teamAAddress = args.team_a || '239.226.152.162';+const teamBAddress = args.team_b || '239.226.152.163';  const app = express(); const server = http.createServer(app);+const sioNetwork = sio(server);++// Initialize socket.io namespace immediately to catch reconnections.+WebSocketProxyUDPServer.of(WebSocketServer.of(sioNetwork.of('/dashboard')), {

You fixed dev, but prod is still the old style

Bidski

comment created time in 2 months

Pull request review commentNUbots/dashboard

Implement UDP networking layer

 export class UDPServer {     return () => this.clients.delete(client);   } -  // Set up callbacks for a given team and then bind the team to its multicast address and port-  private initialiseListener = (listener: Listener) => {-    listener.server.on('listening', () => {+  // One of the UDP servers received a new message, send it on to all clients+  private onMessage = (+    team: TeamData,+    packet: Buffer,+    rinfo: dgram.RemoteInfo,+  ) => {+    for (let emit_cb of this.clients.values()) {+      emit_cb('udp_packet', {+        payload: packet,+        team: {+          name: team.name,+          address: team.address,+          port: team.port,+        },+        rinfo: {+          family: rinfo.family,+          address: rinfo.address,+          port: rinfo.port,+        },+      });+    }+  };+}++class UDPServer {+  private socket: dgram.Socket;++  constructor(+    private team: TeamData,+    private msg_cb: MessageCallback,+    ipv6: boolean,+  ) {+    if (ipv6) {+      this.socket = dgram.createSocket({ type: 'udp6', reuseAddr: true });+    } else {+      this.socket = dgram.createSocket({ type: 'udp4', reuseAddr: true });+    }++    this.socket.on('listening', () => {       // Add multicast membership if we are using a multicast address-      if (listener.ipv6) {+      if (ipv6) {

This seems like adding state to the IP just to make this if statement easier. I mean you could literally just do team.address.includes(":")

Bidski

comment created time in 2 months

Pull request review commentNUbots/dashboard

Implement UDP networking layer

 export class UDPServer {     return () => this.clients.delete(client);   } -  // Set up callbacks for a given team and then bind the team to its multicast address and port-  private initialiseListener = (listener: Listener) => {-    listener.server.on('listening', () => {+  // One of the UDP servers received a new message, send it on to all clients+  private onMessage = (+    team: TeamData,+    packet: Buffer,+    rinfo: dgram.RemoteInfo,+  ) => {+    for (let emit_cb of this.clients.values()) {+      emit_cb('udp_packet', {+        payload: packet,+        team: {+          name: team.name,+          address: team.address,+          port: team.port,+        },+        rinfo: {+          family: rinfo.family,+          address: rinfo.address,+          port: rinfo.port,+        },+      });+    }+  };+}++class UDPServer {+  private socket: dgram.Socket;++  constructor(+    private team: TeamData,+    private msg_cb: MessageCallback,+    ipv6: boolean,+  ) {+    if (ipv6) {+      this.socket = dgram.createSocket({ type: 'udp6', reuseAddr: true });+    } else {+      this.socket = dgram.createSocket({ type: 'udp4', reuseAddr: true });+    }++    this.socket.on('listening', () => {       // Add multicast membership if we are using a multicast address-      if (listener.ipv6) {+      if (ipv6) {         // IPv6 multicast addresses start with 0xFF00-        if (listener.team.address.split(':')[0].toUpperCase() === 'FF00') {-          listener.server.addMembership(listener.team.address);+        if (team.address.split(':')[0].toUpperCase() === 'FF00') {+          this.socket.addMembership(team.address);         }       } else {         // IPv4 multicast addresses start with 0xE-        const octet = Number(listener.team.address.split('.')[0])+        const octet = Number(team.address.split('.')[0])           .toString(16)           .toUpperCase();         if (octet.startsWith('E')) {

Why toUpperCase when you can just check it starts with 'e' instead

Bidski

comment created time in 2 months

Pull request review commentNUbots/dashboard

Implement UDP networking layer

 export class UDPServer {     return () => this.clients.delete(client);   } -  // Set up callbacks for a given team and then bind the team to its multicast address and port-  private initialiseListener = (listener: Listener) => {-    listener.server.on('listening', () => {+  // One of the UDP servers received a new message, send it on to all clients+  private onMessage = (+    team: TeamData,+    packet: Buffer,+    rinfo: dgram.RemoteInfo,+  ) => {+    for (let emit_cb of this.clients.values()) {+      emit_cb('udp_packet', {+        payload: packet,+        team: {+          name: team.name,+          address: team.address,+          port: team.port,+        },+        rinfo: {+          family: rinfo.family,+          address: rinfo.address,+          port: rinfo.port,+        },+      });+    }+  };+}++class UDPServer {+  private socket: dgram.Socket;++  constructor(+    private team: TeamData,+    private msg_cb: MessageCallback,+    ipv6: boolean,+  ) {+    if (ipv6) {+      this.socket = dgram.createSocket({ type: 'udp6', reuseAddr: true });+    } else {+      this.socket = dgram.createSocket({ type: 'udp4', reuseAddr: true });+    }++    this.socket.on('listening', () => {       // Add multicast membership if we are using a multicast address-      if (listener.ipv6) {+      if (ipv6) {         // IPv6 multicast addresses start with 0xFF00-        if (listener.team.address.split(':')[0].toUpperCase() === 'FF00') {-          listener.server.addMembership(listener.team.address);+        if (team.address.split(':')[0].toUpperCase() === 'FF00') {

This isn't a valid way to check, IPv6 addresses might look like FF:00::1, or even FF::1 is a valid multicast address

Bidski

comment created time in 2 months

Pull request review commentNUbots/dashboard

Implement UDP networking layer

 import dgram = require('dgram'); import dns = require('dns');  export type ClientListener = (event: string, ...args: any[]) => void;+export type MessageCallback = (+  team: TeamData,+  payload: Buffer,+  rinfo: dgram.RemoteInfo,+) => void;  export type TeamData = {   name: string;   address: string;   port: number; }; -type Listener = {-  server: dgram.Socket;-  ipv6: boolean;-  team: TeamData;-};--export class UDPServer {-  private listeners: Array<Listener>;+export class UDPServers {+  private servers: Array<UDPServer>;   private clients: Map<string, ClientListener>;    constructor(teams: Array<TeamData>) {     this.clients = new Map<string, ClientListener>();-    this.listeners = new Array<Listener>();+    this.servers = new Array<UDPServer>();      teams.forEach((team: TeamData) => {-      // Determine if we are listening on a IPv4 or IPv6 address and resolve any DNS names+      // Determine if we are listening on a IPv4 or IPv6 address and resolve any DNS address+      // If the specified address can be resolved to an IPv4 address prefer that over an IPv6 address       dns.lookup(         team.address,-        { family: 0, all: false },+        { family: 0, all: true },         (           error: NodeJS.ErrnoException | null,-          address: string,-          family: number,+          addresses: dns.LookupAddress[],         ) => {-          if (family === 6) {-            const listener = {-              server: dgram.createSocket({ type: 'udp6', reuseAddr: true }),-              ipv6: true,-              team: {-                name: team.name,-                address: address,-                port: team.port,-              },-            };-            this.initialiseListener(listener);-            this.listeners.push(listener);-          } else if (family === 4) {-            const listener = {-              server: dgram.createSocket({ type: 'udp4', reuseAddr: true }),-              ipv6: false,-              team: {-                name: team.name,-                address: address,-                port: team.port,-              },-            };-            this.initialiseListener(listener);-            this.listeners.push(listener);+          // Find the first IPv4 and IPv6 addresses that were returned+          let ipv4 = '';+          let ipv6 = '';+          addresses.forEach((address: dns.LookupAddress) => {+            if (address.family === 6 && ipv6 === '') {+              ipv6 = address.address;+            }+            if (address.family === 4 && ipv4 === '') {+              ipv4 = address.address;+            }+          });
          let ipv4 = addresses.filter(v => v.family === 4);
          let ipv6 = addresses.filter(v => v.family === 6);
Bidski

comment created time in 2 months

Pull request review commentNUbots/dashboard

Implement UDP networking layer

 import dgram = require('dgram'); import dns = require('dns');  export type ClientListener = (event: string, ...args: any[]) => void;+export type MessageCallback = (+  team: TeamData,+  payload: Buffer,+  rinfo: dgram.RemoteInfo,+) => void;  export type TeamData = {   name: string;   address: string;   port: number; }; -type Listener = {-  server: dgram.Socket;-  ipv6: boolean;-  team: TeamData;-};--export class UDPServer {-  private listeners: Array<Listener>;+export class UDPServers {+  private servers: Array<UDPServer>;   private clients: Map<string, ClientListener>;    constructor(teams: Array<TeamData>) {     this.clients = new Map<string, ClientListener>();-    this.listeners = new Array<Listener>();+    this.servers = new Array<UDPServer>();      teams.forEach((team: TeamData) => {-      // Determine if we are listening on a IPv4 or IPv6 address and resolve any DNS names+      // Determine if we are listening on a IPv4 or IPv6 address and resolve any DNS address+      // If the specified address can be resolved to an IPv4 address prefer that over an IPv6 address       dns.lookup(         team.address,-        { family: 0, all: false },+        { family: 0, all: true },         (           error: NodeJS.ErrnoException | null,-          address: string,-          family: number,+          addresses: dns.LookupAddress[],         ) => {-          if (family === 6) {-            const listener = {-              server: dgram.createSocket({ type: 'udp6', reuseAddr: true }),-              ipv6: true,-              team: {-                name: team.name,-                address: address,-                port: team.port,-              },-            };-            this.initialiseListener(listener);-            this.listeners.push(listener);-          } else if (family === 4) {-            const listener = {-              server: dgram.createSocket({ type: 'udp4', reuseAddr: true }),-              ipv6: false,-              team: {-                name: team.name,-                address: address,-                port: team.port,-              },-            };-            this.initialiseListener(listener);-            this.listeners.push(listener);+          // Find the first IPv4 and IPv6 addresses that were returned+          let ipv4 = '';+          let ipv6 = '';+          addresses.forEach((address: dns.LookupAddress) => {+            if (address.family === 6 && ipv6 === '') {+              ipv6 = address.address;+            }+            if (address.family === 4 && ipv4 === '') {+              ipv4 = address.address;+            }+          });++          // Prefer IPv4 addresses+          if (ipv4 !== '') {+            this.servers.push(+              UDPServer.of(+                { name: team.name, address: ipv4, port: team.port },+                (team: TeamData, payload: Buffer, rinfo: dgram.RemoteInfo) => {+                  this.onMessage(team, payload, rinfo);+                },+                false,+              ),+            );+          } else if (ipv6 !== '') {+            this.servers.push(+              UDPServer.of(+                { name: team.name, address: ipv6, port: team.port },+                (team: TeamData, payload: Buffer, rinfo: dgram.RemoteInfo) => {+                  this.onMessage(team, payload, rinfo);+                },+                true,+              ),+            );
          if (ipv4.length > 0 || ipv6.length > 0) {
            this.servers.push(
              UDPServer.of(
                { name: team.name, address: ipv4.length > 0 ? ipv4[0] : ipv6[0], port: team.port },
                (team: TeamData, payload: Buffer, rinfo: dgram.RemoteInfo) => {
                  this.onMessage(team, payload, rinfo);
                },
                false,
              ),
            );

And don't bother storing ipv4 vs ipv6, just check what the address is later to do the multicast checking

Bidski

comment created time in 2 months

Pull request review commentNUbots/dashboard

Implement UDP networking layer

 export class UDPServer {     return () => this.clients.delete(client);   } -  // Set up callbacks for a given team and then bind the team to its multicast address and port-  private initialiseListener = (listener: Listener) => {-    listener.server.on('listening', () => {+  // One of the UDP servers received a new message, send it on to all clients+  private onMessage = (+    team: TeamData,+    packet: Buffer,+    rinfo: dgram.RemoteInfo,+  ) => {

Is there a reason that you made a variable equal to a function rather than a member function? There are some reasons to do that but I think in this case it should just be a normal function

  private onMessage(
    team: TeamData,
    packet: Buffer,
    rinfo: dgram.RemoteInfo,
  ) {
Bidski

comment created time in 2 months

Pull request review commentNUbots/dashboard

Implement UDP networking layer

 if (teams.length === 0) { // Convert command line data into a more usable format var teamData = new Array<TeamData>(); teams.forEach((team: string) => {-  const data = team.split(':');-  teamData.push({ name: data[0], address: data[1], port: Number(data[2]) });+  const nameSplit = team.indexOf(':');+  const portSplit = team.lastIndexOf(':');+  const teamName = team.substring(0, nameSplit);+  const teamAddress = team.substring(nameSplit + 1, portSplit);+  const teamPort = Number(team.substring(portSplit + 1));+  teamData.push({ name: teamName, address: teamAddress, port: teamPort }); });

This should be a .map operation rather than a forEach (since you're making a list from a list) Also never use var in javascript anymore, use let or in this case const (since you're not assigning anything else to this variable)

Bidski

comment created time in 2 months

Pull request review commentNUbots/dashboard

Implement UDP networking layer

 export class UDPServer {     this.listeners = new Array<Listener>();      teams.forEach((team: TeamData) => {-      this.listeners.push({-        server: dgram.createSocket({ type: 'udp4', reuseAddr: true }),-        team: team,-      });-    });--    this.listeners.forEach((listener: Listener) => {-      this.initialiseListener(listener);+      // Determine if we are listening on a IPv4 or IPv6 address and resolve any DNS names+      dns.lookup(+        team.address,+        { family: 0, all: false },+        (+          error: NodeJS.ErrnoException | null,+          address: string,+          family: number,+        ) => {+          if (family === 6) {+            const listener = {+              server: dgram.createSocket({ type: 'udp6', reuseAddr: true }),+              ipv6: true,+              team: {+                name: team.name,+                address: address,+                port: team.port,+              },+            };+            this.initialiseListener(listener);

This should just be a type with a constructor rather than an initaliseListener function. Any time you have a function that isinitialiseSomething it's an indication that your classes are leaking into eachother

Bidski

comment created time in 2 months

Pull request review commentNUbots/dashboard

Implement UDP networking layer

 export type TeamData = {  type Listener = {   server: dgram.Socket;+  ipv6: boolean;

Do we actually need to know this after we have created it?

Bidski

comment created time in 2 months

push eventFastcode/NUClear

Trent Houliston

commit sha e4aee1ec9c98211fce776ddc996141ed2fdcdf82

Fix detection logic for multicast address

view details

push time in 2 months

Pull request review commentNUbots/dashboard

Implement UDP networking layer

 import compression from 'compression'; import history from 'connect-history-api-fallback'; import express from 'express'; import http from 'http';+import minimist from 'minimist'; import favicon from 'serve-favicon';+import sio from 'socket.io'; import webpack from 'webpack'; import webpackDevMiddleware from 'webpack-dev-middleware';  import webpackConfig from '../../webpack.config'; +import { UDPServer } from './network/network';++const args = minimist(process.argv.slice(2));+const redTeamAddress = args.team_a || '239.226.152.162';+const blueTeamAddress = args.team_b || '239.226.152.163';+ const compiler = webpack(webpackConfig); const app = express(); const server = http.createServer(app);+const sioNetwork = sio(server);++// Start listening to the multicast groups+const udpServer = UDPServer.of(redTeamAddress, blueTeamAddress);++// Whenever we get a new client connection let the UDP server know about it+sioNetwork.on('connection', (socket: sio.Socket) => {+  const off_cb = udpServer.on(+    socket.client.id,+    (event: string, ...args: any[]) => {

What is the any array that goes here? Does it have a type?

Bidski

comment created time in 2 months

Pull request review commentNUbots/dashboard

Implement UDP networking layer

 import compression from 'compression'; import history from 'connect-history-api-fallback'; import express from 'express'; import http from 'http';+import minimist from 'minimist'; import favicon from 'serve-favicon';+import sio from 'socket.io';++import { WebSocketProxyUDPServer } from './network/network';+import { WebSocketServer } from './network/web_socket_server';++const args = minimist(process.argv.slice(2));

I would change the arguments to be more like 'NUbots:239.226.152.162:12345' or 'Blue Team:239.226.152.162:12345' and just give a bunch of those instead of hard coded values

Bidski

comment created time in 2 months

more