Custom Factor Features
Contributing back to the Community
Consider contributioning back, so if you have developed variables and factors that may be useful to the community, please write up an issue in Caesar.jl or submit a PR to the relavent repo.
What is CalcFactor
CalcFactor
is part of the IIF
interface to all factors. It contains metadata and other important bits of information that are useful in a wide swath of applications. As work requires more interesting features from the code base, it is likely that the cfo::CalcFactor
object will contain such data. If not, please open an issue with Caesar.jl so that the necessary options may be added.
The cfo
object contains the field .factor::T
which is the type of the user factor being used, e.g. myprior
from above example. That is cfo.factor::MyPrior
. This is why getSample
is using rand(cfo.factor.Z)
.
CalcFactor
was introduced in IncrementalInference v0.20
to consolidate and standardize a variety of features that had previously been diseparate and unwieldy.
The MM-iSAMv2 algorithm relies on the Kolmogorov-Criteria as well as uncorrelated factor sampling. This means that when generating fresh samples for a factor, those samples should not depend on values of variables in the graph or independent volatile variables. That said, if you have a non-violating reason for using additional data in the factor sampling or residual calculation process, you can do so via the cf::CalcFactor
interface.
At present cf
contains three main fields:
cf.factor::MyFactor
the factor object as defined in thestruct
definition,cf.fullvariables
, which can be used for large data blob retrieval such as used in Terrain Relative Navigation (TRN).- Also see Stashing and Caching
cf.cache
, which is user controlled viapreambleCache
function, see Cache Section.cf.manifold
, for the manifold the factor operates on.cf._sampleIdx
is the index of which computational sample is currently being calculated.
IncrementalInference.CalcFactor
— TypeResidual function for MutablePose2Pose2Gaussian.
Related
Pose2Pose2, Pose3Pose3, InertialPose3, DynPose2Pose2, Point2Point2, VelPoint2VelPoint2
Many factors already exists in IncrementalInference
, RoME
, and Caesar
. Please see their src
directories for more details.
The old .specialSampler
framework has been replaced with the standardized ::CalcFactor
interface. See http://www.github.com/JuliaRobotics/IIF.jl/issues/467 for details.
Partial Factors
In some cases a factor only effects a partial set of dimensions of a variable. For example a magnetometer being added onto a Pose2
variable would look something like this:
struct MyMagnetoPrior{T<:SamplableBelief} <: AbstractPrior
Z::T
partial::Tuple{Int}
end
# define a helper constructor
MyMagnetoPrior(z) = MyMagnetoPrior(z, (3,))
getSample(cfo::CalcFactor{<:MyMagnetoPrior}) = samplePoint(cfo.factor.Z)
Similarly for <:IIF.AbstractRelativeMinimize
, and note that the Roots version currently does not support the .partial
option.
Factors supporting a Parametric Solution
See the parametric solve section
Standardized Factor Serialization
To take advantage of features like DFG.saveDFG
and DFG.loadDFG
a user specified type should be able to serialize via JSON standards. The decision was taken to require bespoke factor types to always be converted into a JSON friendly struct
which must be prefixed as type name with PackedMyPrior{T}
. Similarly, the user must also overload Base.convert
as follows:
# necessary for overloading Base.convert
import Base: convert
struct PackedMyPrior <: AbstractPackedFactor
Z::String
end
# IIF provides convert methods for `SamplableBelief` types
convert(::Type{PackedMyPrior}, pr::MyPrior{<:SamplableBelief}) = PackedMyPrior(convert(PackedSamplableBelief, pr.Z))
convert(::Type{MyPrior}, pr::PackedMyPrior) = MyPrior(IIF.convert(SamplableBelief, pr.Z))
Now you should be able to saveDFG
and loadDFG
your own factor graph types to Caesar.jl / FileDFG standard .tar.gz
format.
fg = initfg()
addVariable!(fg, :x0, ContinuousScalar)
addFactor!(fg, [:x0], MyPrior(Normal()))
# generate /tmp/myfg.tar.gz
saveDFG("/tmp/myfg", fg)
# test loading the .tar.gz (extension optional)
fg2 = loadDFG("/tmp/myfg")
# list the contents
ls(fg2), lsf(fg2)
# should see :x0 and :x0f1 listed