DYT/Tool/matlab/include/shared_autonomous/autonomouscodegen_reeds_shepp.hpp

506 lines
21 KiB
C++
Raw Permalink Normal View History

2024-11-22 15:19:31 +00:00
/* Copyright 2017-2021 The MathWorks, Inc. */
/**
* @file
* Main interfaces for Reeds-Shepp motion primitive calculations.
* To fully support code generation, note that this file needs to be fully
* compliant with the C++98 standard.
*/
#ifndef AUTONOMOUSCODEGEN_REEDSSHEPP_H_
#define AUTONOMOUSCODEGEN_REEDSSHEPP_H_
#include <math.h> // for sqrt, trigonometric functions
#include <algorithm> // for max
#include <vector>
#ifdef BUILDING_LIBMWAUTONOMOUSCODEGEN
#include "autonomouscodegen/autonomouscodegen_reeds_shepp_primitives.hpp"
#else
// To deal with the fact that PackNGo has no include file hierarchy during test
#include "autonomouscodegen_reeds_shepp_primitives.hpp"
#endif
namespace autonomous {
namespace reedsshepp {
/*
* The code for ReedsShepp primitives and computation of the various
* segment paths is inspired from Open Motion Planning Library source.
*/
/*
* RSSegmentType - Enumeration for holding segment type
*/
enum RSSegmentType { Left = 0, Right, Straight, NOP };
const RSSegmentType pathToSegment[18][5] = {
{autonomous::reedsshepp::Left, autonomous::reedsshepp::Right, autonomous::reedsshepp::Left,
autonomous::reedsshepp::NOP, autonomous::reedsshepp::NOP},
{autonomous::reedsshepp::Right, autonomous::reedsshepp::Left, autonomous::reedsshepp::Right,
autonomous::reedsshepp::NOP, autonomous::reedsshepp::NOP},
{autonomous::reedsshepp::Left, autonomous::reedsshepp::Right, autonomous::reedsshepp::Left,
autonomous::reedsshepp::Right, autonomous::reedsshepp::NOP},
{autonomous::reedsshepp::Right, autonomous::reedsshepp::Left, autonomous::reedsshepp::Right,
autonomous::reedsshepp::Left, autonomous::reedsshepp::NOP},
{autonomous::reedsshepp::Left, autonomous::reedsshepp::Right, autonomous::reedsshepp::Straight,
autonomous::reedsshepp::Left, autonomous::reedsshepp::NOP},
{autonomous::reedsshepp::Right, autonomous::reedsshepp::Left, autonomous::reedsshepp::Straight,
autonomous::reedsshepp::Right, autonomous::reedsshepp::NOP},
{autonomous::reedsshepp::Left, autonomous::reedsshepp::Straight, autonomous::reedsshepp::Right,
autonomous::reedsshepp::Left, autonomous::reedsshepp::NOP},
{autonomous::reedsshepp::Right, autonomous::reedsshepp::Straight, autonomous::reedsshepp::Left,
autonomous::reedsshepp::Right, autonomous::reedsshepp::NOP},
{autonomous::reedsshepp::Left, autonomous::reedsshepp::Right, autonomous::reedsshepp::Straight,
autonomous::reedsshepp::Right, autonomous::reedsshepp::NOP},
{autonomous::reedsshepp::Right, autonomous::reedsshepp::Left, autonomous::reedsshepp::Straight,
autonomous::reedsshepp::Left, autonomous::reedsshepp::NOP},
{autonomous::reedsshepp::Right, autonomous::reedsshepp::Straight, autonomous::reedsshepp::Right,
autonomous::reedsshepp::Left, autonomous::reedsshepp::NOP},
{autonomous::reedsshepp::Left, autonomous::reedsshepp::Straight, autonomous::reedsshepp::Left,
autonomous::reedsshepp::Right, autonomous::reedsshepp::NOP},
{autonomous::reedsshepp::Left, autonomous::reedsshepp::Straight, autonomous::reedsshepp::Right,
autonomous::reedsshepp::NOP, autonomous::reedsshepp::NOP},
{autonomous::reedsshepp::Right, autonomous::reedsshepp::Straight, autonomous::reedsshepp::Left,
autonomous::reedsshepp::NOP, autonomous::reedsshepp::NOP},
{autonomous::reedsshepp::Left, autonomous::reedsshepp::Straight, autonomous::reedsshepp::Left,
autonomous::reedsshepp::NOP, autonomous::reedsshepp::NOP},
{autonomous::reedsshepp::Right, autonomous::reedsshepp::Straight, autonomous::reedsshepp::Right,
autonomous::reedsshepp::NOP, autonomous::reedsshepp::NOP},
{autonomous::reedsshepp::Left, autonomous::reedsshepp::Right, autonomous::reedsshepp::Straight,
autonomous::reedsshepp::Left, autonomous::reedsshepp::Right},
{autonomous::reedsshepp::Right, autonomous::reedsshepp::Left, autonomous::reedsshepp::Straight,
autonomous::reedsshepp::Right, autonomous::reedsshepp::Left}};
/*
* shortestReedsSheppPath returns shortest normalized Reeds-Shepp path.
*/
inline autonomous::reedsshepp::ReedsSheppPath shortestReedsSheppPath(real64_T x,
real64_T y,
real64_T phi,
real64_T reverseCost) {
autonomous::reedsshepp::ReedsSheppPath minPath, tempPath;
real64_T minLength, tempLength;
autonomous::reedsshepp::computeCSCPath(x, y, phi, reverseCost, minPath);
minLength = minPath.length();
autonomous::reedsshepp::computeCCCPath(x, y, phi, reverseCost, tempPath);
tempLength = tempPath.length();
if (tempLength < minLength) {
minLength = tempLength;
minPath = tempPath;
}
autonomous::reedsshepp::computeCCCCPath(x, y, phi, reverseCost, tempPath);
tempLength = tempPath.length();
if (tempLength < minLength) {
minLength = tempLength;
minPath = tempPath;
}
autonomous::reedsshepp::computeCCSCPath(x, y, phi, reverseCost, tempPath);
tempLength = tempPath.length();
if (tempLength < minLength) {
minLength = tempLength;
minPath = tempPath;
}
autonomous::reedsshepp::computeCCSCCPath(x, y, phi, reverseCost, tempPath);
tempLength = tempPath.length();
if (tempLength < minLength) {
minLength = tempLength;
minPath = tempPath;
}
return minPath;
}
/*
* computeReedsSheppPath - compute Reeds-Shepp shortest/all path.
*/
inline autonomous::reedsshepp::ReedsSheppPath computeReedsSheppPath(
const real64_T initialConfiguration[3],
const real64_T finalConfiguration[3],
const real64_T turningRadius,
const real64_T reverseCost) {
real64_T x1 = initialConfiguration[0];
real64_T y1 = initialConfiguration[1];
real64_T theta1 = initialConfiguration[2];
real64_T x2 = finalConfiguration[0];
real64_T y2 = finalConfiguration[1];
real64_T theta2 = finalConfiguration[2];
real64_T dx = x2 - x1;
real64_T dy = y2 - y1;
real64_T c = cos(theta1);
real64_T s = sin(theta1);
real64_T x = c * dx + s * dy;
real64_T y = -s * dx + c * dy;
real64_T phi = theta2 - theta1;
return shortestReedsSheppPath(x / turningRadius, y / turningRadius, phi, reverseCost);
}
/*
* AllReedsSheppPath returns all normalized Reeds-Shepp path.
*/
inline std::vector<autonomous::reedsshepp::ReedsSheppPath> AllReedsSheppPath(
real64_T x,
real64_T y,
real64_T phi,
real64_T forwardCost,
real64_T reverseCost,
const boolean_T isOptimal,
const boolean_T allPathTypes[autonomous::reedsshepp::TotalNumPaths],
const uint32_T numTotalPathTypes) {
std::vector<autonomous::reedsshepp::ReedsSheppPath> allPaths;
allPaths.reserve(numTotalPathTypes);
autonomous::reedsshepp::computeCSCPathAll(x, y, phi, forwardCost, reverseCost, &allPathTypes[0],
&allPaths);
autonomous::reedsshepp::computeCCCPathAll(x, y, phi, forwardCost, reverseCost, &allPathTypes[0],
&allPaths);
autonomous::reedsshepp::computeCCCCPathAll(x, y, phi, forwardCost, reverseCost,
&allPathTypes[0], &allPaths);
autonomous::reedsshepp::computeCCSCPathAll(x, y, phi, forwardCost, reverseCost,
&allPathTypes[0], &allPaths);
autonomous::reedsshepp::computeCCSCCPathAll(x, y, phi, forwardCost, reverseCost,
&allPathTypes[0], &allPaths);
if (isOptimal) {
real64_T optimalPath = autonomous::inf;
uint32_T optimalInd = 0;
// Round up to 15 decimal point to get same optimal path in
// all system (maci, linux, windows). (Geck --> g1770360)
real64_T round_val = pow(10.0, 15);
for (uint32_T ind = 0; ind < numTotalPathTypes; ++ind) {
// Round up to 15 decimal point to get same optimal path in
// all system (maci, linux, windows . (Geck --> g1770360)
real64_T tempcost = round(allPaths[ind].cost() * round_val) / round_val;
if (optimalPath > tempcost) {
optimalPath = tempcost;
optimalInd = ind;
}
}
std::vector<autonomous::reedsshepp::ReedsSheppPath> path(1);
path[0] = allPaths[optimalInd];
return path;
}
return allPaths;
}
/*
* computeAllReedsSheppPaths - compute Reeds-Shepp shortest/all path.
*/
inline std::vector<autonomous::reedsshepp::ReedsSheppPath> computeAllReedsSheppPaths(
const real64_T initialConfiguration[3],
const real64_T finalConfiguration[3],
const real64_T turningRadius,
const real64_T forwardCost,
const real64_T reverseCost,
const boolean_T isOptimal,
const boolean_T allPathTypes[autonomous::reedsshepp::TotalNumPaths],
const uint32_T numTotalPathTypes) {
real64_T x1 = initialConfiguration[0];
real64_T y1 = initialConfiguration[1];
real64_T theta1 = initialConfiguration[2];
real64_T x2 = finalConfiguration[0];
real64_T y2 = finalConfiguration[1];
real64_T theta2 = finalConfiguration[2];
real64_T dx = x2 - x1;
real64_T dy = y2 - y1;
real64_T c = cos(theta1);
real64_T s = sin(theta1);
real64_T x = c * dx + s * dy;
real64_T y = -s * dx + c * dy;
real64_T phi = theta2 - theta1;
return AllReedsSheppPath(x / turningRadius, y / turningRadius, phi, forwardCost, reverseCost,
isOptimal, &allPathTypes[0], numTotalPathTypes);
}
/*
* Compute direction value for start/goal pose.
*
* 1) For segmentLengths input {0, 9, 2, -10, 0},
*
* computeDirectionAtEdges({0, 9, 2, -10, 0}, true) or
* computeDirectionAtEdges({0, 9, 2, -10, 0}) will return 1, sign of first
* non-zero segment (sign(9)) i.e. direction value of start pose.
*
* computeDirectionAtEdges({0, 9, 2, -10, 0}, false) will return -1, sign
* of last non-zero segment (sign(-10)) i.e. direction value of goal pose.
*
* 2) For segmentLengths input {-8, -1, 2, 10, 0},
*
* computeDirectionAtEdges({-8, -1, 2, 10, 0}, true) or
* computeDirectionAtEdges({-8, -1, 2, 10, 0}) will return -1, sign of first
* non-zero segment (sign(-8)) i.e. direction value of start pose.
*
* computeDirectionAtEdges({-8, -1, 2, 10, 0}, false) will return 1, sign
* of last non-zero segment (sign(10)) i.e. direction value of goal pose.
*
*/
inline real64_T computeDirectionAtEdges(const real64_T* segmentLengths, boolean_T startFlag = true)
{
real64_T direction = 1;
for (uint32_T i = 0; i < 5; i++){
if(segmentLengths[i] != 0){
direction = ((segmentLengths[i]<0) ? -1 : 1);
//Exit from loop for start pose direction computation
if (startFlag){
break;
}
}
}
return direction;
}
/*
* interpolateAlongInitializedRSPath - interpolate points along a
* pre-computed ReedsShepp path.
*/
inline real64_T interpolateAlongInitializedRSPath(const real64_T pathLength,
const RSSegmentType* segments,
const real64_T* segmentLengths,
const real64_T* from,
const real64_T* towards,
const real64_T t,
const real64_T turningRadius,
real64_T* state) {
real64_T direction = 1;
if (t <= 0.0) {
state[0] = from[0];
state[1] = from[1];
state[2] = from[2];
// To ensure first pose direction is correct
direction = computeDirectionAtEdges(segmentLengths);
} else if (t >= 1.0) {
state[0] = towards[0];
state[1] = towards[1];
state[2] = towards[2];
// To ensure last pose direction is correct
direction = computeDirectionAtEdges(segmentLengths, false);
} else {
// Initialize at [0, 0, theta]
state[0] = 0;
state[1] = 0;
state[2] = from[2];
real64_T seg = t * pathLength;
real64_T v, phi;
// Compute normalized update.
for (uint32_T i = 0; i < 5 && seg > 0; ++i) {
if (segmentLengths[i] < 0) {
v = std::max(-seg, segmentLengths[i]);
seg += v;
direction = -1;
} else {
v = std::min(seg, segmentLengths[i]);
seg -= v;
direction = 1;
}
phi = state[2];
switch (segments[i]) {
case autonomous::reedsshepp::Left:
state[0] += sin(phi + v) - sin(phi);
state[1] += -cos(phi + v) + cos(phi);
state[2] = autonomous::wrapToTwoPi(phi + v);
break;
case autonomous::reedsshepp::Right:
state[0] += -sin(phi - v) + sin(phi);
state[1] += cos(phi - v) - cos(phi);
state[2] = autonomous::wrapToTwoPi(phi - v);
break;
case autonomous::reedsshepp::Straight:
state[0] += v * cos(phi);
state[1] += v * sin(phi);
break;
case autonomous::reedsshepp::NOP:
// no update needed
break;
}
}
// Denormalize and update.
state[0] = from[0] + state[0] * turningRadius;
state[1] = from[1] + state[1] * turningRadius;
}
return direction;
}
/*
* interpolateRS - interpolate along ReedsShepp curve between states.
*/
inline void interpolateRS(const real64_T* from,
const real64_T* towards,
const real64_T maxDistance,
const uint32_T numSteps,
const real64_T turningRadius,
const real64_T reverseCost,
real64_T* state) {
// Compute ReedsShepp path.
autonomous::reedsshepp::ReedsSheppPath path =
computeReedsSheppPath(from, towards, turningRadius, reverseCost);
const RSSegmentType* segments = pathToSegment[path.getPathType()];
// Compute the fraction of path to be traversed based on maximum
// connection distance (maxDistance).
// * If the distance between the states is less than maxDistance, we
// interpolate all the through to the destination state (towards).
// * If the distance between the states is more than maxDistance, we
// only interpolate a fraction of the path between the two states.
// Find the distance between the states.
const real64_T pathLength = path.length();
const real64_T dist = pathLength * turningRadius;
// Find the fraction of the path to interpolate.
const real64_T t = std::min(maxDistance / dist, 1.0);
// Find interpolation step based on number of steps.
const real64_T step = t / static_cast<real64_T>(numSteps);
std::vector<real64_T> temp(3, 0);
real64_T fraction = 0;
// Interpolate along transition points
const uint32_T numTransitions = 4;
const uint32_T arrLength = numSteps + numTransitions;
const real64_T* segLengths = path.getSegmentLengths();
for (uint32_T n = 0; n < numTransitions; ++n) {
// Compute fraction along path corresponding to n-th transition
// point
fraction += (autonomous::abs(segLengths[n]) / pathLength);
// Saturate at maxDistance. This has the effect of returning
// the ending pose for all transition poses that come after the
// maxDistance has been reached.
fraction = std::min(fraction, t);
interpolateAlongInitializedRSPath(pathLength, segments, segLengths, from, towards, fraction,
turningRadius, &temp[0]);
state[n] = temp[0];
state[n + arrLength] = temp[1];
state[n + 2 * arrLength] = temp[2];
}
// Interpolate along path at equidistant intervals
fraction = 0;
for (uint32_T n = numTransitions; n < arrLength; ++n) {
fraction += step;
interpolateAlongInitializedRSPath(pathLength, segments, segLengths, from, towards, fraction,
turningRadius, &temp[0]);
state[n] = temp[0];
state[n + arrLength] = temp[1];
state[n + 2 * arrLength] = temp[2];
}
}
/*
* interpolateReedsSheppSegments - interpolate along given states and Reeds-Shepp curve.
*/
inline void interpolateReedsSheppSegments(const real64_T* from,
const real64_T* towards,
const real64_T* samples,
const uint32_T numSamples,
const real64_T turningRadius,
const real64_T* segmentLengths,
const int32_T* segmentDirections,
const uint32_T* segmentTypes,
real64_T* state,
real64_T* directions) {
RSSegmentType segments[5] = {static_cast<RSSegmentType>(segmentTypes[0]),
static_cast<RSSegmentType>(segmentTypes[1]),
static_cast<RSSegmentType>(segmentTypes[2]),
static_cast<RSSegmentType>(segmentTypes[3]),
static_cast<RSSegmentType>(segmentTypes[4])};
real64_T temp[3] = {0, 0, 0};
const real64_T pathLength = segmentLengths[0] + segmentLengths[1] +
segmentLengths[2] + segmentLengths[3] + segmentLengths[4];
real64_T normalizedSegmentLengths[5] = {segmentLengths[0] / turningRadius,
segmentLengths[1] / turningRadius,
segmentLengths[2] / turningRadius,
segmentLengths[3] / turningRadius,
segmentLengths[4] / turningRadius};
const real64_T normalizedPathLength =
normalizedSegmentLengths[0] + normalizedSegmentLengths[1] +
normalizedSegmentLengths[2] + normalizedSegmentLengths[3] +
normalizedSegmentLengths[4];
real64_T round_val = pow(10.0, 15);
normalizedSegmentLengths[0] = round(normalizedSegmentLengths[0] * round_val) / round_val;
normalizedSegmentLengths[1] = round(normalizedSegmentLengths[1] * round_val) / round_val;
normalizedSegmentLengths[2] = round(normalizedSegmentLengths[2] * round_val) / round_val;
normalizedSegmentLengths[3] = round(normalizedSegmentLengths[3] * round_val) / round_val;
normalizedSegmentLengths[4] = round(normalizedSegmentLengths[4] * round_val) / round_val;
// Round up to 15 decimal point to get same optimal path in all system
// (maci, linux, windows). (Geck --> g1770360)
normalizedSegmentLengths[0] = normalizedSegmentLengths[0]*static_cast<real64_T>(segmentDirections[0]);
normalizedSegmentLengths[1] = normalizedSegmentLengths[1]*static_cast<real64_T>(segmentDirections[1]);
normalizedSegmentLengths[2] = normalizedSegmentLengths[2]*static_cast<real64_T>(segmentDirections[2]);
normalizedSegmentLengths[3] = normalizedSegmentLengths[3]*static_cast<real64_T>(segmentDirections[3]);
normalizedSegmentLengths[4] = normalizedSegmentLengths[4]*static_cast<real64_T>(segmentDirections[4]);
for (uint32_T n = 0; n < numSamples; ++n) {
// Compute fraction along path corresponding to n-th transition
// point
// Round up to 15 decimal point to get same optimal path in all
// system (maci, linux, windows). (Geck --> g1770360)
real64_T roundedSample = round(samples[n] * round_val) / round_val;
roundedSample = roundedSample / pathLength;
if (directions){
directions[n] = interpolateAlongInitializedRSPath(normalizedPathLength, segments, normalizedSegmentLengths,
from, towards, roundedSample, turningRadius, &temp[0]);
}else{
interpolateAlongInitializedRSPath(normalizedPathLength, segments, normalizedSegmentLengths,
from, towards, roundedSample, turningRadius, &temp[0]);
}
state[n] = round(temp[0] * round_val) / round_val;
state[n + numSamples] = round(temp[1] * round_val) / round_val;
state[n + 2 * numSamples] = round(temp[2] * round_val) / round_val;
}
}
} // namespace reedsshepp
} // namespace autonomous
#endif /* AUTONOMOUSCODEGEN_REEDSSHEPP_H_ */