Skip to content

Commit b2457eb

Browse files
authored
Merge pull request #907 from JuliaRobotics/22Q3/enh/stash_andmore
test solver using data blobs (via stashing)
2 parents f92d54f + 981d689 commit b2457eb

13 files changed

Lines changed: 303 additions & 45 deletions

File tree

.github/workflows/ci.yml

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,7 @@ jobs:
1616
fail-fast: false
1717
matrix:
1818
version:
19-
- '1.6'
20-
- '1.7'
19+
- '1.8'
2120
- 'nightly'
2221
os:
2322
- ubuntu-latest
@@ -66,7 +65,7 @@ jobs:
6665

6766
- uses: julia-actions/setup-julia@v1
6867
with:
69-
version: 1.7
68+
version: 1.8
7069
arch: x64
7170

7271
- uses: actions/cache@v1
@@ -107,7 +106,7 @@ jobs:
107106
- uses: actions/checkout@v2
108107
- uses: julia-actions/setup-julia@v1
109108
with:
110-
version: 1.7
109+
version: 1.8
111110
- name: 'Docs on ${{ github.head_ref }}'
112111
run: |
113112
export JULIA_PKG_SERVER=""

Project.toml

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,11 @@ name = "Caesar"
22
uuid = "62eebf14-49bc-5f46-9df9-f7b7ef379406"
33
keywords = ["SLAM", "state-estimation", "MM-iSAM", "MM-iSAMv2", "inference", "robotics", "ROS"]
44
desc = "Non-Gaussian simultaneous localization and mapping"
5-
version = "0.13.4"
5+
version = "0.13.5"
66

77
[deps]
88
ApproxManifoldProducts = "9bbbb610-88a1-53cd-9763-118ce10c1f89"
9+
Base64 = "2a0f44e3-6c83-55bd-87e4-b1978d98bd5f"
910
Combinatorics = "861a8166-3701-5b0c-9a16-15d98fcdc6aa"
1011
CoordinateTransformations = "150eb455-5306-5404-9cee-2592286d6298"
1112
DataStructures = "864edb3b-99cc-5e75-8d2d-829cb0a9cfe8"
@@ -59,7 +60,7 @@ FFTW = "1"
5960
FileIO = "1"
6061
ImageCore = "0.8, 0.9"
6162
ImageMagick = "1"
62-
IncrementalInference = "0.30"
63+
IncrementalInference = "0.30, 0.31"
6364
JLD2 = "0.3, 0.4"
6465
JSON = "0.20, 0.21"
6566
JSON2 = "0.3, 0.4"
@@ -71,7 +72,7 @@ Optim = "1"
7172
ProgressMeter = "1"
7273
Reexport = "1"
7374
Requires = "1"
74-
RoME = "0.20"
75+
RoME = "0.20, 0.21"
7576
Rotations = "1.1"
7677
StaticArrays = "1"
7778
StatsBase = "0.33"

docs/src/examples/custom_factor_features.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,8 @@ The MM-iSAMv2 algorithm relies on the Kolmogorov-Criteria as well as uncorrelate
2020

2121
At present `cfo` contains three main fields:
2222
- `cfo.factor::MyFactor` the factor object as defined in the `struct` definition,
23-
- `cfo.metadata::FactorMetadata`, which is currently under development and likely to change.
24-
- This contains references to the connected variables to the factor and more, and is useful for large data retrieval such as used in Terrain Relative Navigation (TRN).
23+
- `cfo.fullvariables`, which can be used for large data blob retrieval such as used in Terrain Relative Navigation (TRN).
24+
- Also see [Stashing and Caching](@ref section_stash_and_cache)
2525
- `cfo._sampleIdx` is the index of which computational sample is currently being calculated.
2626

2727

src/3rdParty/_PCL/services/PlottingUtilsPCL.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
## _PCL plotting utils
88
## =====================================================================================
99

10-
# FIXME move pointcloud plotting to Arena.jl instead
10+
# NOTE moved pointcloud plotting to and see PR Arena.jl#94
1111
function plotPointCloud(pc::PointCloud)
1212
x = (s->s.data[1]).(pc.points)
1313
y = (s->s.data[2]).(pc.points)

src/3rdParty/_PCL/services/PointCloud.jl

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -364,7 +364,11 @@ end
364364
## =========================================================================================================
365365

366366

367-
function _filterMinRange(pts, minrange, maxrange)
367+
function _filterMinRange(
368+
pts::AbstractVector{<:AbstractVector{<:Real}},
369+
minrange::Real,
370+
maxrange::Real
371+
)
368372
# filter pointcloud section of interest
369373
msk = findall(x-> minrange < norm(x) < maxrange, pts)
370374
pts[msk]

src/Caesar.jl

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ using
3131
CoordinateTransformations,
3232
JSON,
3333
JSON2,
34+
Base64,
3435
FileIO,
3536
DataStructures,
3637
ProgressMeter,
@@ -100,6 +101,7 @@ function __init__()
100101
include("images/ScatterAlignPose2.jl")
101102

102103
@require Gadfly="c91e804a-d5a3-530f-b6f0-dfbca275c004" include("plotting/ScatterAlignPlotting.jl")
104+
@require RobotOS="22415677-39a4-5241-a37a-00beabbbdae8" include("images/ROSConversions.jl")
103105
end
104106
@require Distributed="8ba89e20-285c-5b6f-9357-94700520ee1b" include("images/DistributedUtils.jl")
105107
end

src/beamforming/SASBearing2D.jl

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -120,14 +120,14 @@ function (cfo::CalcFactor{<:SASBearing2D})( meas,
120120
XX... )
121121
#
122122
sas2d = cfo.factor
123-
userdata = cfo.metadata
123+
# userdata = cfo.metadata # OUT OF DATE, use CalcFactor.fullvariables
124124
idx = cfo._sampleIdx
125125
#
126126
dx, dy, azi = 0.0, 0.0, 0.0
127127
thread_data = sas2d.threadreuse[Threads.threadid()]
128128
res = [0.0;]
129129

130-
if string(userdata.solvefor)[1] == 'l'
130+
if cf.solvefor == 1
131131
# Solving all poses to Landmark
132132
# Reference the filter positions locally (first element)
133133

@@ -140,8 +140,8 @@ function (cfo::CalcFactor{<:SASBearing2D})( meas,
140140
# ccall(:jl_, Void, (Any,), "idx=$(idx)\n")
141141
thread_data.oncebackidx[1] = idx
142142
#run for eacn new idx
143-
thread_data.workvarlist = userdata.variablelist[2:end] # skip landmark element
144-
thread_data.looelement = findfirst(thread_data.workvarlist .== userdata.solvefor)
143+
thread_data.workvarlist = cfo.variablelist[2:end] # skip landmark element
144+
thread_data.looelement = findfirst(thread_data.workvarlist .== cfo.solvefor)
145145
thread_data.elementset = setdiff(Int[1:length(thread_data.workvarlist);], [thread_data.looelement;])
146146

147147
# Reference first or second element

src/images/ROSConversions.jl

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
@info "Caesar.jl is loading tools relating to Images.jl and RobotOS.jl"
2+
3+
using .RobotOS
4+
5+
import Unmarshal: unmarshal
6+
7+
@rosimport std_msgs.msg: Header
8+
@rosimport sensor_msgs.msg: Image
9+
10+
11+
function unmarshal(
12+
header::Main.std_msgs.msg.Header
13+
)
14+
#
15+
Dict{String,Any}(
16+
"seq" => header.seq,
17+
"stamp" => Dict{String,Int}(
18+
"secs"=>header.stamp.secs,
19+
"nsecs"=>header.stamp.nsecs
20+
),
21+
"frame_id" => header.frame_id,
22+
"_type" => "ROS1/std_msgs/Header"
23+
)
24+
end
25+
26+
function unmarshal(
27+
msg::Main.sensor_msgs.msg.Image
28+
)
29+
Dict{String,Any}(
30+
"width" => Int(msg.width),
31+
"height" => Int(msg.height),
32+
"step" => Int(msg.step),
33+
"data_b64" => base64encode(msg.data),
34+
"encoding" => msg.encoding,
35+
"is_bigendian" => msg.is_bigendian === 0x01,
36+
"header" => unmarshal(msg.header),
37+
"_type" => "ROS1/sensor_msgs/Image?base64",
38+
"description" => "Caesar.toImage(JSON.parse(jstr))"
39+
)
40+
end
41+
42+
43+
function toImage(msgd::Dict{String,Any})
44+
data = base64decode(msgd["data_b64"])
45+
h, w = msgd["height"], msgd["width"]
46+
47+
if msgd["encoding"] == "mono8"
48+
img = Matrix{Gray{N0f8}}(undef, h, w)
49+
# assuming one endian type for now, TODO both little and big endian
50+
for i in 1:h, j in 1:w
51+
img[i,j] = Gray{N0f8}(data[msgd["step"]*(i-1)+j]/255)
52+
end
53+
img
54+
else
55+
error("Conversion for ROS sensor_msgs.Image encoding not implemented yet $(msgd["encoding"])")
56+
end
57+
end
58+
59+
toImage(msg::Main.sensor_msgs.msg.Image) = unmarshal(msg) |> toImage
60+
61+
#

src/images/ScatterAlignPose2.jl

Lines changed: 55 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,15 @@
11

22

3-
import IncrementalInference: getSample, preambleCache
3+
import IncrementalInference: getSample, preambleCache, _update!
44
import Base: convert, show
55
# import DistributedFactorGraphs: getManifold
6-
import ApproxManifoldProducts: sample
6+
import ApproxManifoldProducts: sample, _update!
77

8+
using UUIDs
89
using .Images
910

1011
export ScatterAlignPose2, PackedScatterAlignPose2
11-
export ScatterAlignPose3
12+
export ScatterAlignPose3, PackedScatterAlignPose3
1213

1314
export overlayScatter, overlayScatterMutate
1415

@@ -67,7 +68,7 @@ Base.@kwdef struct ScatterAlign{P,
6768
Arg 0 < `rescale` ≤ 1 is also used to rescale the images to lower resolution for speed. """
6869
gridscale::Float64 = 1.0
6970
""" how many heatmap sampled particles to use for mmd alignment """
70-
sample_count::Int = 100
71+
sample_count::Int = 500
7172
""" bandwidth to use for mmd """
7273
bw::Float64 = 1.0
7374
""" EXPERIMENTAL, flag whether to use 'stashing' for large point cloud, see [Stash & Cache](@ref section_stash_unstash) """
@@ -196,7 +197,11 @@ getManifold(::IIF.InstanceType{<:ScatterAlignPose2}) = getManifold(Pose2Pose2)
196197
getManifold(::IIF.InstanceType{<:ScatterAlignPose3}) = getManifold(Pose3Pose3)
197198

198199
# runs once upon addFactor! and returns object later used as `cache`
199-
function preambleCache(dfg::AbstractDFG, vars::AbstractVector{<:DFGVariable}, fnc::Union{<:ScatterAlignPose2,<:ScatterAlignPose3})
200+
function preambleCache(
201+
dfg::AbstractDFG,
202+
vars::AbstractVector{<:DFGVariable},
203+
fnc::Union{<:ScatterAlignPose2,<:ScatterAlignPose3}
204+
)
200205
#
201206
M = getManifold(_getPoseType(fnc.align))
202207
e0 = getPointIdentity(M)
@@ -205,10 +210,14 @@ function preambleCache(dfg::AbstractDFG, vars::AbstractVector{<:DFGVariable}, fn
205210
for (va,de,cl) in zip(vars,[fnc.align.dataEntry_cloud1,fnc.align.dataEntry_cloud2],[fnc.align.cloud1,fnc.align.cloud2])
206211
if fnc.align.useStashing
207212
@assert 0 < length(de) "cannot reconstitute ScatterAlignPose2 without necessary data entry, only have $de"
208-
_, db = getData(dfg, getLabel(va), Symbol(de)) # fnc.align.dataStoreHint
213+
_, db = getData(dfg, getLabel(va), UUID(de)) # fnc.align.dataStoreHint
214+
# Assume PackedManifoldKernelDensity
209215
cld = convert(SamplableBelief, String(take!(IOBuffer(db))))
210-
# cld = unpackDistribution(strdstr)
211-
IIF._update!(cl, cld)
216+
# payload = JSON.parse(String(take!(IOBuffer(db))))
217+
# dstr = unmarshal PackedManifoldKernelDensity
218+
# cld = unpackDistribution(dstr)
219+
# update either a HGD or MKD
220+
_update!(cl, cld)
212221
end
213222
end
214223

@@ -409,24 +418,42 @@ Base.@kwdef struct PackedScatterAlignPose2 <: AbstractPackedFactor
409418
dataStoreHint::String = ""
410419
end
411420

421+
Base.@kwdef struct PackedScatterAlignPose3 <: AbstractPackedFactor
422+
_type::String = "Caesar.PackedScatterAlignPose3"
423+
cloud1::_PARCHABLE_PACKED_CLOUD
424+
cloud2::_PARCHABLE_PACKED_CLOUD
425+
gridscale::Float64 = 1.0
426+
sample_count::Int = 50
427+
bw::Float64 = 0.01
428+
""" EXPERIMENTAL, flag whether to use 'stashing' for large point cloud, see [Stash & Cache](@ref section_stash_unstash) """
429+
useStashing::Bool = false
430+
""" DataEntry ID for stash store of cloud 1 & 2 """
431+
dataEntry_cloud1::String = ""
432+
dataEntry_cloud2::String = ""
433+
""" Data store hint where likely to find the data entries and blobs for reconstructing cloud1 and cloud2"""
434+
dataStoreHint::String = ""
435+
end
412436

413-
function convert(::Type{<:PackedScatterAlignPose2}, arp::ScatterAlignPose2)
414-
437+
function convert(
438+
::Type{T},
439+
arp::Union{<:ScatterAlignPose2,<:ScatterAlignPose3}
440+
) where {T <: Union{<:PackedScatterAlignPose2,<:PackedScatterAlignPose3}}
441+
#
415442
cld1 = arp.align.cloud1
416443
cld2 = arp.align.cloud2
417444

418445
# reconstitute full type during the preambleCache step
419446
if arp.align.useStashing
420-
@assert length(arp.align.dataEntry_cloud1) !== 0 "packing of ScatterAlignPose2 asked to be `useStashing=true`` yet no `.dataEntry_cloud1` exists for later loading"
447+
@assert length(arp.align.dataEntry_cloud1) !== 0 "packing of ScatterAlignPose asked to be `useStashing=true`` yet no `.dataEntry_cloud1` exists for later loading"
421448
cld1 = IIF.parchDistribution(arp.align.cloud1)
422-
@assert length(arp.align.dataEntry_cloud2) !== 0 "packing of ScatterAlignPose2 asked to be `useStashing=true`` yet no `.dataEntry_cloud2` exists for later loading"
449+
@assert length(arp.align.dataEntry_cloud2) !== 0 "packing of ScatterAlignPose asked to be `useStashing=true`` yet no `.dataEntry_cloud2` exists for later loading"
423450
cld2 = IIF.parchDistribution(arp.align.cloud2)
424451
end
425452

426453
cloud1 = packDistribution(cld1)
427454
cloud2 = packDistribution(cld2)
428455

429-
PackedScatterAlignPose2(;
456+
T(;
430457
cloud1,
431458
cloud2,
432459
gridscale = arp.align.gridscale,
@@ -435,22 +462,29 @@ function convert(::Type{<:PackedScatterAlignPose2}, arp::ScatterAlignPose2)
435462
useStashing = arp.align.useStashing,
436463
dataEntry_cloud1 = arp.align.dataEntry_cloud1,
437464
dataEntry_cloud2 = arp.align.dataEntry_cloud2,
438-
dataStoreHint = arp.align.dataStoreHint )
465+
dataStoreHint = arp.align.dataStoreHint
466+
)
439467
end
440468

441-
function convert(::Type{<:ScatterAlignPose2}, parp::PackedScatterAlignPose2)
469+
function convert(
470+
::Type{T},
471+
parp::Union{<:PackedScatterAlignPose2,<:PackedScatterAlignPose3}
472+
) where {T <: Union{<:ScatterAlignPose2,<:ScatterAlignPose3}}
442473
#
443-
474+
_selectPoseT(::Type{<:ScatterAlignPose2}) = Pose2
475+
_selectPoseT(::Type{<:ScatterAlignPose3}) = Pose3
476+
444477
function _resizeCloudData!(cl::PackedHeatmapGridDensity)
445-
typ, col, row = typeof(cl.data[1][1]), Int(cl.data[1][2]), Int(cl.data[2][1])
478+
row=Int(cl.data[2][1])
479+
typ, col = typeof(cl.data[1][1]), Int(cl.data[1][2])
446480
resize!(cl.data,row)
447481
for i in 1:row
448482
cl.data[i] = Vector{typ}(undef, col)
449483
end
450484
nothing
451485
end
452-
_resizeCloudData!(cl::ManifoldKernelDensity) = nothing
453-
486+
_resizeCloudData!(cl::PackedManifoldKernelDensity) = nothing
487+
454488
# prep cloud1.data fields for larger data
455489
if parp.useStashing
456490
_resizeCloudData!(parp.cloud1)
@@ -461,7 +495,8 @@ function convert(::Type{<:ScatterAlignPose2}, parp::PackedScatterAlignPose2)
461495
cloud2 = unpackDistribution(parp.cloud2)
462496

463497
# and build the final object
464-
ScatterAlignPose2(ScatterAlign{Pose2, typeof(cloud1), typeof(cloud2)}(;
498+
poseT = _selectPoseT(T)
499+
T(ScatterAlign{poseT, typeof(cloud1), typeof(cloud2)}(;
465500
cloud1,
466501
cloud2,
467502
gridscale=parp.gridscale,

test/ICRA2022_tests/nongaussian_mixture.jl

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ using IncrementalInference
1818

1919
# Start with an empty factor graph
2020
fg = initfg()
21+
getSolverParams(fg).useMsgLikelihoods = true
2122

2223
# add the first node
2324
addVariable!(fg, :x0, ContinuousScalar)
@@ -92,6 +93,8 @@ tree = solveGraph!(fg);
9293

9394
ppes = DFG.getPPESuggested.(fg, [:x0;:x1;:x2;:x3])
9495

96+
#
97+
9598
@test isapprox( getPPESuggested(fg, :x0)[1], 0; atol=1)
9699
@test isapprox( getPPESuggested(fg, :x1)[1], 10; atol=1)
97100
@test isapprox( getPPESuggested(fg, :x2)[1], 20; atol=2)

0 commit comments

Comments
 (0)