diff --git a/grid/walk/v2/modules/WalkModuleHeadingVonMises.h b/grid/walk/v2/modules/WalkModuleHeadingVonMises.h new file mode 100644 index 0000000..9c01a79 --- /dev/null +++ b/grid/walk/v2/modules/WalkModuleHeadingVonMises.h @@ -0,0 +1,123 @@ +#ifndef WALKMODULEHEADINGVONMISES_H +#define WALKMODULEHEADINGVONMISES_H + +#include "WalkModule.h" +#include "WalkStateHeading.h" + +#include "../../../../geo/Heading.h" +#include "../../../../math/Distributions.h" + + +/** keep the state's heading */ +template class WalkModuleHeadingVonMises : public WalkModule { + +private: + + /** van-Mises distribution */ + Distribution::VonMises dist; + + /** random noise */ + Distribution::Normal distNoise; + + const Control* ctrl; + +public: + + /** ctor 3.0 should be OK! */ + WalkModuleHeadingVonMises(const Control* ctrl, const float sensorNoiseDegreesSigma) : + dist(Distribution::VonMises(0.0f, 2.0f)), + distNoise(0, Angle::degToRad(sensorNoiseDegreesSigma)), + ctrl(ctrl) { + + // ensure the template WalkState inherits from 'WalkStateHeading'! + StaticAssert::AinheritsB(); + + } + + + virtual void updateBefore(WalkState& state, const Node& startNode) override { + + // NOTE: ctrl->turnAngle is cumulative SINCE the last transition! + // reset this one after every transition! + Assert::isBetween(ctrl->turnSinceLastTransition_rad, -3.0f, +3.0f, "the given turn angle is too high to make sense.. did you forget to set ctrl->turnAngle = 0 after each transition?"); + + // sensor noise + float var = distNoise.draw(); + + // stair? -> increase variance + if (startNode.getType() == GridNode::TYPE_STAIR) {var *= 3;} + + // adjust the state's heading using the control-data + state.heading.direction += ctrl->turnSinceLastTransition_rad + var; + + //set kappa of mises + float kappa = 5 / std::exp(2 * std::abs(ctrl->motionDeltaAngle_rad)); + dist.setKappa(kappa); + + } + + virtual void updateAfter(WalkState& state, const Node& startNode, const Node& endNode) override { + (void) state; + (void) startNode; + (void) endNode; + } + + virtual void step(WalkState& state, const Node& curNode, const Node& nextNode) override { + + (void) state; + + // ignore for stairs? + //if (nextNode.getType() == GridNode::TYPE_STAIR) {return;} + + // for elevator edges [same (x,y) but different z] do not adjust anything + if (nextNode.getType() == GridNode::TYPE_ELEVATOR) {return;} + if (curNode.getType() == GridNode::TYPE_ELEVATOR) {return;} + //if (curNode.x_cm == nextNode.x_cm && curNode.y_cm == nextNode.y_cm && curNode.z_cm != nextNode.z_cm) {return;} + + // get the heading denoted by the way from curNode to nextNode + const Heading head(curNode.x_cm, curNode.y_cm, nextNode.x_cm, nextNode.y_cm); + + // get the heading requested by the state + const Heading stateHead = state.heading.direction; + + // get the error (signed difference) between both + const float angularDiff = stateHead.getSignedDiff(head); + + // adjust the error. + // note: the error may get > +/- 2PI but this is not an issue! + // when the error is added to the current heading within getProbability(), + // it is ensured their sum is within [0:2pi] + state.heading.error += angularDiff; + + } + + double getProbability(const WalkState& state, const Node& startNode, const Node& curNode, const Node& potentialNode) const override { + + (void) startNode; + + // ignore for stairs? + //if (potentialNode.getType() == GridNode::TYPE_STAIR) {return 1.0;} + + // for elevator edges [same (x,y) but different z] just return 1 + if (potentialNode.getType() == GridNode::TYPE_ELEVATOR) {return 1.0;} + if (curNode.getType() == GridNode::TYPE_ELEVATOR) {return 1.0;} + //if (curNode.x_cm == potentialNode.x_cm && curNode.y_cm == potentialNode.y_cm && curNode.z_cm != potentialNode.z_cm) {return 1.0;} + + // get the heading between curNode and potentialNode + const Heading head(curNode.x_cm, curNode.y_cm, potentialNode.x_cm, potentialNode.y_cm); + + // compare the heading against the state's heading - the last error + const Heading stateHead = state.heading.direction + state.heading.error; + + // get the difference + const float angularDiff = head.getDiffHalfRAD(stateHead); + + // determine probability + return dist.getProbability(angularDiff); + + } + + +}; + +#endif // WALKMODULEHEADING_H