Description
Hi,
I am using the multihypo keyword for uncertain data association and cannot achieve the results I expect even on tiny examples.
I looked through most of Caesars, Romes and IIFs smaller examples where the multihypo keyword is used and mostly found it being used directly on prior measurements or a relative measurement directly attached to a variable that has a prior. Multihypo-localization on a known map is also working with the tiny example I came up with myself. But if I go to a more realistic SLAM-Scenario that is only anchored using one prior in the beginning, multihypo-measurements produce wrong and very indeterministic results (every run can yield totally different landmark positions even for the tiny example).
The tiny example I attached has 3 poses and 3 landmarks. Every landmark is measured twice and for every measurement has the right landmark and a wrong landmark (which is a different one for the two measurements) assigned. So theoretically the strongest mode in the result should originate from the right associations. Unfortunately this is not the case. I even tried to initialize the landmarks using the GT. Running the solver on a perfecly initialized example did not produce the results I expected.
using RoME, RoMEPlotting
pRight = 0.9
pWrong = 0.1
ΣOdo = Diagonal([0.01;0.01;0.001].^2)
ΣLm = Diagonal([0.1;0.1;0.01].^2)
gtx1 = [0;0;0]
gtx2 = [1;0;0]
gtx3 = [1;1;0]
gtl1 = [0;1;-pi/2]
gtl2 = [2;0;0]
gtl3 = [2;1;pi/2]
fg = LightDFG{SolverParams}(solverParams=SolverParams(logpath="minimal_multihypo"))
getSolverParams(fg).useMsgLikelihoods = false
addVariable!(fg, :x1, Pose2)
pri1 = addFactor!(fg, [:x1], PriorPoint2(MvNormal(gtx1, Diagonal([0.01;0.01;0.001].^2))))
initManual!(fg, :x1, [pri1.label])
addVariable!(fg, :l1, Pose2)
addVariable!(fg, :l2, Pose2)
dx1l1 = MvNormal(gtl1-gtx1, ΣLm)
tfx1l1l2 = addFactor!(fg, [:x1,:l1,:l2], Pose2Pose2(dx1l1), multihypo = [1.0,pRight,pWrong], graphinit=false)
addVariable!(fg, :x2, Pose2)
odo12 = addFactor!(fg, [:x1,:x2], Pose2Pose2(MvNormal(gtx2-gtx1, ΣOdo)))
initManual!(fg, :x2, [odo12.label])
addVariable!(fg, :l3, Pose2)
dx2l2 = MvNormal(gtl2-gtx2, ΣLm)
tfx2l2l1 = addFactor!(fg, [:x2,:l2,:l1], Pose2Pose2(dx2l2), multihypo = [1.0,pRight,pWrong], graphinit=false)
dx2l3 = MvNormal(gtl3-gtx2, ΣLm) # Typo -gtl2 corrected to -gtx2
tfx2l3l2 = addFactor!(fg, [:x2,:l3,:l2], Pose2Pose2(dx2l3), multihypo = [1.0,pRight,pWrong], graphinit=false)
addVariable!(fg, :x3, Pose2)
odo23 = addFactor!(fg, [:x2,:x3], Pose2Pose2(MvNormal(gtx3-gtx2, ΣOdo)))
initManual!(fg, :x3, [odo23.label])
dx3l2 = MvNormal(gtl2-gtx3, ΣLm)
tfx3l2l3 = addFactor!(fg, [:x3,:l2,:l3], Pose2Pose2(dx3l2), multihypo = [1.0,pRight,pWrong], graphinit=false)
dx3l3 = MvNormal(gtl3-gtx3, ΣLm)
tfx3l3l1 = addFactor!(fg, [:x3,:l3,:l1], Pose2Pose2(dx3l3), multihypo = [1.0,pRight,pWrong], graphinit=false)
dx3l1 = MvNormal(gtl1-gtx3, ΣLm)
tfx3l1l3 = addFactor!(fg, [:x3,:l1,:l3], Pose2Pose2(dx3l1), multihypo = [1.0,pRight,pWrong], graphinit=false)
# initManual!(fg, :l1, [tfx1l1l2.label, tfx3l1l3.label])
# initManual!(fg, :l2, [tfx2l2l1.label, tfx3l2l3.label])
# initManual!(fg, :l3, [tfx2l3l2.label, tfx3l3l1.label])
px1 = getPoints(getKDE(fg,:x1))
px1l1 = rand(dx1l1,100)
initManual!(fg,:l1,px1.+px1l1)
px2 = getPoints(getKDE(fg,:x2))
px2l2 = rand(dx2l2,100)
initManual!(fg,:l2,px2.+px2l2)
px3 = getPoints(getKDE(fg,:x3))
px3l3 = rand(dx3l3,100)
initManual!(fg,:l3,px3.+px3l3)
pl3i = plotSLAM2D(fg;contour=false)
pl3l1i = plotPose(fg,:l1)
pl3l2i = plotPose(fg,:l2)
pl3l3i = plotPose(fg,:l3)
tree, smt, hist = solveTree!(fg)
pl3 = plotSLAM2D(fg;contour=false)
pl3l1 = plotPose(fg,:l1)
pl3l2 = plotPose(fg,:l2)
pl3l3 = plotPose(fg,:l3)
Are there any examples I overlooked that test a similar case to mine?
Do you have any suggestions why my example is failing?
Best,
Leo