function
Vehicles.Rdd2.simulateOpticalFlowPlane
Generate raw plane-induced flow for a co-located nadir camera
Public declarations
Explicit source declarations; dimensions, modifications and defaults are shown as written, without evaluation.
| Role | Name | Type | Dimensions / attributes / default | Description |
|---|---|---|---|---|
| input | positionWorldEnu_m | Real | [3] | |
| input | velocityWorldEnu_m_s | Real | [3] | |
| input | rotationWorldBody | Real | [3, 3] | |
| input | angularVelocityBodyFlu_rad_s | Real | [3] | |
| input | groundNormalWorldEnu | Real | [3] = {0.0, 0.0, 1.0} | |
| input | groundPlaneOffset_m | Real | = 0.0 | |
| input | integrationTime_s | Real | = 0.005 | |
| input | normalizedImageRadius | Real | = 0.35 | Feature-grid radius in normalized focal-length coordinates |
| output | integratedLineOfSight_rad | Real | [2] | Mean raw right-handed scene rotation about body FLU x/y |
| output | groundDistance_m | Real | | Distance along the central -body-z camera ray |
| output | surfaceVisibility | Real | | One when every feature ray intersects the plane in front of the camera |
Modelica declarations and implementation
Show parameters, interfaces and source
Parameters, inputs, outputs, defaults and equations from the source file.
function simulateOpticalFlowPlane
"Generate raw plane-induced flow for a co-located nadir camera"
input Real positionWorldEnu_m[3];
input Real velocityWorldEnu_m_s[3];
input Real rotationWorldBody[3, 3];
input Real angularVelocityBodyFlu_rad_s[3];
input Real groundNormalWorldEnu[3] = {0.0, 0.0, 1.0};
input Real groundPlaneOffset_m = 0.0;
input Real integrationTime_s = 0.005;
input Real normalizedImageRadius = 0.35
"Feature-grid radius in normalized focal-length coordinates";
output Real integratedLineOfSight_rad[2]
"Mean raw right-handed scene rotation about body FLU x/y";
output Real groundDistance_m
"Distance along the central -body-z camera ray";
output Real surfaceVisibility
"One when every feature ray intersects the plane in front of the camera";
protected
constant Integer FeatureCount = 9;
Real featureU[FeatureCount];
Real featureV[FeatureCount];
Real rayBody[3];
Real rayWorld[3];
Real denominator;
Real numerator;
Real featureDistance_m;
Real relativeBody_m[3];
Real relativeDerivativeBody_m_s[3];
Real normalizedRate[2];
Real translationFlow_rad[2];
Real flatFieldScale;
Real velocityBody[3];
Boolean allRaysVisible;
algorithm
featureU := {-normalizedImageRadius, 0.0, normalizedImageRadius,
-normalizedImageRadius, 0.0, normalizedImageRadius,
-normalizedImageRadius, 0.0, normalizedImageRadius};
featureV := {-normalizedImageRadius, -normalizedImageRadius,
-normalizedImageRadius, 0.0, 0.0, 0.0,
normalizedImageRadius, normalizedImageRadius, normalizedImageRadius};
velocityBody := transpose(rotationWorldBody) * velocityWorldEnu_m_s;
numerator := groundPlaneOffset_m
- groundNormalWorldEnu * positionWorldEnu_m;
denominator := groundNormalWorldEnu
* (rotationWorldBody * {0.0, 0.0, -1.0});
allRaysVisible := false;
if abs(denominator) > 1.0e-6 then
allRaysVisible := numerator / denominator > 0.05;
end if;
groundDistance_m := if allRaysVisible then numerator / denominator else 0.0;
translationFlow_rad := zeros(2);
for feature in 1:FeatureCount loop
rayBody := {featureU[feature], featureV[feature], -1.0};
rayWorld := rotationWorldBody * rayBody;
denominator := groundNormalWorldEnu * rayWorld;
featureDistance_m := if abs(denominator) > 1.0e-6 then
numerator / denominator else -1.0;
allRaysVisible := allRaysVisible and featureDistance_m > 0.05;
if featureDistance_m > 0.05 then
relativeBody_m := featureDistance_m * rayBody;
relativeDerivativeBody_m_s := -velocityBody;
normalizedRate := {
-(relativeDerivativeBody_m_s[1] * relativeBody_m[3]
- relativeBody_m[1] * relativeDerivativeBody_m_s[3])
/ (relativeBody_m[3] * relativeBody_m[3]),
-(relativeDerivativeBody_m_s[2] * relativeBody_m[3]
- relativeBody_m[2] * relativeDerivativeBody_m_s[3])
/ (relativeBody_m[3] * relativeBody_m[3])};
translationFlow_rad := translationFlow_rad
+ {normalizedRate[2] / (1.0 + featureV[feature]^2),
-normalizedRate[1] / (1.0 + featureU[feature]^2)}
* integrationTime_s / FeatureCount;
end if;
end for;
// A real flow unit calibrates its field aggregate so flat-ground lateral
// translation obeys flow = velocity / center range. For this symmetric
// three-by-three grid the raw angular average has the exact scale below.
// Apply that calibration only to translation: co-timed gyro rotation must
// remain one-for-one, while feature-dependent depths still preserve the
// observable effect of a plane inclined relative to the camera.
flatFieldScale := (1.0 + 2.0
/ (1.0 + normalizedImageRadius * normalizedImageRadius)) / 3.0;
integratedLineOfSight_rad := if allRaysVisible then
translationFlow_rad / flatFieldScale
- angularVelocityBodyFlu_rad_s[1:2] * integrationTime_s
else zeros(2);
surfaceVisibility := if allRaysVisible then 1.0 else 0.0;
end simulateOpticalFlowPlane;