Skip to content

Commit 8ad743d

Browse files
authored
Merge pull request #515 from JuliaRobotics/21Q4/enh/growhelix
allow helix generator to grow graph
2 parents fbef73b + 0610a89 commit 8ad743d

File tree

2 files changed

+70
-13
lines changed

2 files changed

+70
-13
lines changed

src/canonical/GenerateHelix.jl

+23-13
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,9 @@ Notes
1717
- See related wrapper functions for convenient generators of helix patterns in 2D,
1818
- Real valued `xr_t(t)` and `yr_t(t)` can be modified (and will override) complex valued `spine_t` instead.
1919
- use `postpose_cb = (fg_, lastestpose) -> ...` for additional user features after each new pose
20+
- can be used to grow a graph with repeated calls, but keyword parameters are assumed identical between calls.
2021
21-
Related
22-
23-
[`generateCanonicalFG_Helix2DSlew!`](@ref), [`generateCanonicalFG_Helix2DSpiral!`](@ref)
22+
See also: [`generateCanonicalFG_Helix2DSlew!`](@ref), [`generateCanonicalFG_Helix2DSpiral!`](@ref), [`generateCanonicalFG_Beehive!`](@ref)
2423
"""
2524
function generateCanonicalFG_Helix2D!(numposes::Integer=40;
2625
posesperturn::Integer=20,
@@ -34,40 +33,51 @@ function generateCanonicalFG_Helix2D!(numposes::Integer=40;
3433
poseRegex::Regex=r"x\d+",
3534
μ0=[0;0;pi/2],
3635
refKey::Symbol=:simulated,
37-
Qd::Matrix{<:Real}=diagm( [0.1;0.1;0.05].^2 ),
36+
Qd::AbstractMatrix{<:Real}=diagm( [0.1;0.1;0.05].^2 ),
3837
postpose_cb::Function=(fg_,latestpose)->() )
3938
#
4039

4140
# add first pose if not already exists
42-
if !( :x0 in ls(dfg) )
41+
_initpose = Symbol(match(r"[A-Za-z]+", poseRegex.pattern).match, 0)
42+
if !exists( dfg, _initpose )
4343
generateCanonicalFG_ZeroPose(dfg=dfg, μ0=μ0, graphinit=graphinit, postpose_cb=postpose_cb) # , μ0=[0;0;1e-5] # tried for fix NLsolve on wrap issue
4444
getSolverParams(dfg).useMsgLikelihoods = useMsgLikelihoods
4545
# reference ppe on :x0
4646
ppe = DFG.MeanMaxPPE(refKey, μ0, μ0, μ0)
4747
setPPE!(dfg[:x0], refKey, DFG.MeanMaxPPE, ppe)
4848
end
4949

50-
# what is the last pose
51-
lastpose = (ls(dfg, poseRegex) |> sortDFG)[end]
52-
# get latest posecount number
50+
# start from existsing poses
51+
_poses = ls(dfg, poseRegex) |> sortDFG
52+
# what is the last pose and posecount number
53+
lastpose = _poses[end]
5354
posecount = match(r"\d+", string(lastpose)).match |> x->parse(Int,x)
55+
# init how many poses at the beginning of a new turn
56+
bidx = length(_poses) # 1
5457

58+
# fractional number of turns to make in total (after all graph generation is done)
5559
turns = numposes/posesperturn
56-
# TODO dont always start from 0
60+
# generate helix pattern algebraically
5761
tmp = calcHelix_T(0, turns, posesperturn, radius=radius, spine_t=spine_t, xr_t=xr_t, yr_t=yr_t)
58-
59-
= SE2(μ0-[0;0;pi/2])
60-
61-
bidx = 1
62+
# TODO, dont always start from 0 -- i.e. chop first repeat elements from deterministic helix
63+
64+
# select the starting point
65+
_μ0 = μ0
66+
# @show _μ0 = 1 == bidx ? μ0 : getPPE(dfg, lastpose, refKey).suggested
67+
= SE2(_μ0-[0;0;pi/2])
68+
69+
# current end pose count for number of turns
6270
eidx = 1
6371
for tn in 0:(ceil(Int, turns)-1)
6472
eidx += posesperturn
73+
# skip out early if extending a previous existing graph
6574
eidx = minimum( [eidx, length(tmp[1])] )
6675
# tmp_ = _calcHelix2DApprox(N_ppt=posesperturn, radius=radius, runback=runback)
6776
tmp_ = hcat(tmp[2][bidx:eidx,:],tmp[3][bidx:eidx])'
6877
# adjust for turn progression in x
6978
# tmp_[1,:] .+= tn*(2radius*(1-runback))
7079
oldpose =*SE2(tmp_[:,1])
80+
eidx < bidx ? continue : nothing
7181

7282
# add each new pose (skippin the first element)
7383
for ps in 2:size(tmp_,2)

test/testGenerateHelix.jl

+47
Original file line numberDiff line numberDiff line change
@@ -70,9 +70,56 @@ fg = RoME.generateCanonicalFG_Helix2DSpiral!(200, graphinit=false, rate_r=0.6, r
7070

7171

7272
##
73+
end
74+
75+
76+
@testset "test extending fg with helix generator" begin
77+
##
78+
79+
fg = generateCanonicalFG_Helix2D!(5, posesperturn=15, radius=10, graphinit=false)
80+
81+
@test !getSolverParams(fg).graphinit
82+
83+
# check the helix is being constructed in a consistent way, using ppe solveKey :simulated
84+
vars = sortDFG(ls(fg))
85+
ppes = [
86+
[0.0, 0.0, 1.5707963267948966],
87+
[0.8645454235739924, 4.067366430758004, 1.151917276019672],
88+
[3.3086939364114176, 7.431448254773942, 0.7330382545911657],
89+
[6.909830056250526, 9.510565162951536, 0.31415923447063226],
90+
[11.045284632676536, 9.945218953682733, -0.10471978645923721],
91+
]
92+
93+
for (i,v) in enumerate(vars)
94+
@test isapprox(ppes[i], getPPE(fg, v, :simulated).suggested; atol=1e-5 )
95+
end
96+
7397

98+
# check that the graph can be expanded with the same generator function
99+
100+
generateCanonicalFG_Helix2D!(5, dfg=fg, posesperturn=15, radius=10, graphinit=false)
101+
# check that no new variables were added
102+
@test length(ls(fg)) == length(vars)
103+
@test !exists(fg, :x5)
104+
105+
##
106+
107+
generateCanonicalFG_Helix2D!(6, dfg=fg, posesperturn=15, radius=10, graphinit=false)
108+
# check that only one variable has been added
109+
@test length(ls(fg)) == length(vars) + 1
110+
@test exists(fg, :x5)
111+
112+
# check the simulated location of the new variable is also at the right location
113+
push!(vars, :x5)
114+
push!(ppes, [ 15.0;8.660254037844387;-0.5235988055902416] )
115+
116+
@test isapprox(ppes[end], getPPE(fg, :x5, :simulated).suggested; atol=1e-5 )
117+
118+
119+
##
74120
end
75121

122+
76123
##
77124

78125
# using TensorCast

0 commit comments

Comments
 (0)