From 1cc607162329d0355f31b27be07df84c18aaa654 Mon Sep 17 00:00:00 2001 From: Johannes Terblanche Date: Tue, 19 Apr 2022 18:39:57 +0200 Subject: [PATCH 01/15] __Data kwargs --- src/navability/entities/Factor.jl | 41 +++++++++++++++++-------------- 1 file changed, 22 insertions(+), 19 deletions(-) diff --git a/src/navability/entities/Factor.jl b/src/navability/entities/Factor.jl index 087f4cb..f20a0c8 100644 --- a/src/navability/entities/Factor.jl +++ b/src/navability/entities/Factor.jl @@ -40,8 +40,8 @@ Create a prior factor for a ContinuousScalar (a.k.a. Pose1) with a distribution Default value of Z = `Normal(0.0, 0.1)`. """ -function PriorData(;Z::Distribution = Normal(0.0, 0.1))::FactorData - data = FactorData(fnc = ZInferenceType(Z), certainhypo = [1]) +function PriorData(;Z::Distribution = Normal(0.0, 0.1), kwargs...)::FactorData + data = FactorData(;fnc = ZInferenceType(Z), certainhypo = [1], kwargs...) return data end @@ -52,8 +52,8 @@ Create a prior factor for a Pose2 with a distribution Z representing (x,y,theta) Default value of Z = `FullNormal([0.0, 0.0, 0.0], diagm([0.01, 0.01, 0.01]))`. """ -function PriorPose2Data(;Z::Distribution = FullNormal([0.0, 0.0, 0.0], diagm([0.01, 0.01, 0.01])))::FactorData - data = FactorData(fnc = ZInferenceType(Z), certainhypo = [1]) +function PriorPose2Data(;Z::Distribution = FullNormal([0.0, 0.0, 0.0], diagm([0.01, 0.01, 0.01])), kwargs...)::FactorData + data = FactorData(;fnc = ZInferenceType(Z), certainhypo = [1], kwargs...) return data end @@ -64,8 +64,8 @@ Create a prior factor for a Point2 with a distribution Z representing (x,y) prio Default value of Z = `FullNormal([0.0, 0.0], diagm([0.01, 0.01]))`. """ -function PriorPoint2Data(;Z::Distribution = FullNormal([0.0, 0.0], diagm([0.01, 0.01])))::FactorData - data = FactorData(fnc = ZInferenceType(Z), certainhypo = [1]) +function PriorPoint2Data(;Z::Distribution = FullNormal([0.0, 0.0], diagm([0.01, 0.01])), kwargs...)::FactorData + data = FactorData(;fnc = ZInferenceType(Z), certainhypo = [1], kwargs...) return data end @@ -76,8 +76,8 @@ between the variables, e.g. `Normal(1.0, 0.1)`. Default value of Z = `Normal(1.0, 0.1)`. """ -function LinearRelativeData(;Z::Distribution = Normal(1.0, 0.1))::FactorData - data = FactorData(fnc = ZInferenceType(Z), certainhypo = [1, 2]) +function LinearRelativeData(;Z::Distribution = Normal(1.0, 0.1), kwargs...)::FactorData + data = FactorData(;fnc = ZInferenceType(Z), certainhypo = [1, 2], kwargs...) return data end @@ -88,8 +88,8 @@ between the variables, e.g. `FullNormal([1,0,0.3333*π], diagm([0.01,0.01,0.01]) Default value of Z = `FullNormal([1,0,0.3333*π], diagm([0.01,0.01,0.01]))`. """ -function Pose2Pose2Data(;Z::Distribution = FullNormal([1,0,0.3333*π], diagm([0.01, 0.01, 0.01])))::FactorData - data = FactorData(fnc = ZInferenceType(Z), certainhypo = [1, 2]) +function Pose2Pose2Data(;Z::Distribution = FullNormal([1,0,0.3333*π], diagm([0.01, 0.01, 0.01])), kwargs...)::FactorData + data = FactorData(;fnc = ZInferenceType(Z), certainhypo = [1, 2], kwargs...) return data end @@ -99,8 +99,8 @@ Create a Pose2->Point2 bearing+range factor with 1D distributions: - bearing: The bearing from the pose to the point, default `Normal(0, 1)`. - range: The range from the pose to the point, default `Normal(1, 1)`. """ -function Pose2Point2BearingRangeData(;bearing::Distribution = Normal(0, 1), range::Distribution = Normal(1, 1))::FactorData - data = FactorData(fnc = Pose2Point2BearingRangeInferenceType(bearing, range), certainhypo = [1, 2]) +function Pose2Point2BearingRangeData(;bearing::Distribution = Normal(0, 1), range::Distribution = Normal(1, 1), kwargs...)::FactorData + data = FactorData(;fnc = Pose2Point2BearingRangeInferenceType(bearing, range), certainhypo = [1, 2], kwargs...) return data end @@ -109,8 +109,8 @@ $(SIGNATURES) Create a Point2->Point2 range factor with a 1D distribution: - range: The range from the pose to the point, default `Normal(1, 1)`. """ -function Point2Point2RangeData(;range::Distribution = Normal(1, 1))::FactorData - data = FactorData(fnc = ZInferenceType(range), certainhypo = [1, 2]) +function Point2Point2RangeData(;range::Distribution = Normal(1, 1), kwargs...)::FactorData + data = FactorData(;fnc = ZInferenceType(range), certainhypo = [1, 2], kwargs...) return data end @@ -119,7 +119,7 @@ $(SIGNATURES) Create a AprilTags factor that directly relates a Pose2 to the information from an AprilTag reading. Corners need to be provided, homography and tag length are defaulted and can be overwritten. """ -function Pose2AprilTag4CornersData(id, corners::Vector{Float64}, homography::Vector{Float64}; K::Vector{Float64}=[300.0,0.0,0.0,0.0,300.0,0.0,180.0,120.0,1.0], taglength::Float64=0.25)::FactorData +function Pose2AprilTag4CornersData(id, corners::Vector{Float64}, homography::Vector{Float64}; K::Vector{Float64}=[300.0,0.0,0.0,0.0,300.0,0.0,180.0,120.0,1.0], taglength::Float64=0.25, kwargs...)::FactorData fnc = Pose2AprilTag4CornersInferenceType( corners=corners, homography=homography, @@ -127,7 +127,7 @@ function Pose2AprilTag4CornersData(id, corners::Vector{Float64}, homography::Vec taglength=taglength, id=id ) - data = FactorData(fnc = fnc, certainhypo = [1, 2]) + data = FactorData(;fnc = fnc, certainhypo = [1, 2], kwargs...) return data end @@ -154,7 +154,7 @@ function MixtureData( probabilities::Vector{Float64}, dims::Integer # TODO: Confirming we can remove. )::FactorData #where T<:FactorData - data = FactorData( + data = FactorData(; fnc = MixtureInferenceType( N = length(components), # @jim-hill-r this is why I don't like the Data suffix. @@ -167,10 +167,13 @@ function MixtureData( return data end -function Factor(label::String, fncType::String, variableOrderSymbols::Vector{String}, data::FactorData; tags::Vector{String}=["FACTOR"], timestamp::String = string(now(Dates.UTC))*"Z", multihypo=Float64[])::Factor +function Factor(label::String, fncType::String, variableOrderSymbols::Vector{String}, data::FactorData; tags::Vector{String}=["FACTOR"], timestamp::String = string(now(Dates.UTC))*"Z", multihypo=nothing)::Factor # TODO: Remove independent updates of this and set certainhypo here. data.certainhypo = Vector{Int}(1:size(variableOrderSymbols)[1]) - data.multihypo = multihypo + + if multihypo !== nothing + data.multihypo = multihypo + end result = Factor( label, From 7cdf1e782e817dbca7382ad6541f150737ea4141 Mon Sep 17 00:00:00 2001 From: Johannes Terblanche Date: Tue, 19 Apr 2022 18:41:01 +0200 Subject: [PATCH 02/15] More py SKD like on InferenceType --- src/navability/entities/InferenceTypes.jl | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/navability/entities/InferenceTypes.jl b/src/navability/entities/InferenceTypes.jl index ad3258b..37b1df9 100644 --- a/src/navability/entities/InferenceTypes.jl +++ b/src/navability/entities/InferenceTypes.jl @@ -20,6 +20,15 @@ Base.@kwdef struct ZInferenceType <: InferenceType Z::Distribution end +Base.@kwdef struct LinearRelative <: InferenceType + Z::Distribution +end + +Base.@kwdef struct Prior <: InferenceType + Z::Distribution +end + + """ $(TYPEDEF) Pose2Point2BearingRangeInferenceType is used to represent a bearing From f956b3a740ac25137ee57585b50a6417dc6d565f Mon Sep 17 00:00:00 2001 From: Johannes Terblanche Date: Tue, 19 Apr 2022 18:42:01 +0200 Subject: [PATCH 03/15] Pose1->Position1 from #78 --- src/navability/entities/Variable.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/navability/entities/Variable.jl b/src/navability/entities/Variable.jl index 556af03..68d6838 100644 --- a/src/navability/entities/Variable.jl +++ b/src/navability/entities/Variable.jl @@ -7,8 +7,8 @@ _variableTypeConvert = Dict{Symbol, String}( :Point2 => "RoME.Point2", :Pose2 => "RoME.Pose2", :ContinuousScalar => "IncrementalInference.ContinuousScalar", - # TBD - https://github.com/JuliaRobotics/Caesar.jl/discussions/810 - :Pose1 => "IncrementalInference.ContinuousScalar" + # TBD - https://github.com/JuliaRobotics/Caesar.jl/discussions/807 + :Position1 => "IncrementalInference.ContinuousScalar" ) struct Variable From 9e5bb7489bae835112117c850eb98a35f1e2d17b Mon Sep 17 00:00:00 2001 From: Johannes Terblanche Date: Tue, 19 Apr 2022 18:43:41 +0200 Subject: [PATCH 04/15] Standard API POC from #78 and addFactor --- src/NavAbilitySDK.jl | 4 ++ src/navability/services/StandardAPI.jl | 95 ++++++++++++++++++++++++++ 2 files changed, 99 insertions(+) create mode 100644 src/navability/services/StandardAPI.jl diff --git a/src/NavAbilitySDK.jl b/src/NavAbilitySDK.jl index 19287a2..27dc24f 100644 --- a/src/NavAbilitySDK.jl +++ b/src/NavAbilitySDK.jl @@ -1,5 +1,8 @@ module NavAbilitySDK +const NVA = NavAbilitySDK +export NVA + # Global imports using DocStringExtensions using LinearAlgebra @@ -51,6 +54,7 @@ include("./navability/services/Factor.jl") include("./navability/services/Solve.jl") include("./navability/services/Status.jl") include("./navability/services/Utils.jl") +include("./navability/services/StandardAPI.jl") export getVariable, getVariables, listVariables, ls export addVariable, addPackedVariable export getFactor, getFactors, listFactors, lsf diff --git a/src/navability/services/StandardAPI.jl b/src/navability/services/StandardAPI.jl new file mode 100644 index 0000000..75850eb --- /dev/null +++ b/src/navability/services/StandardAPI.jl @@ -0,0 +1,95 @@ +## Wrap to standard API spec + + +# TODO What to use: +# - NavAbilityPlatform +# - NavAbilityConnection +# - NavAbilityClientContext +# - +mutable struct NavAbilityPlatform{T} + client + context::T +end + +function NavAbilityPlatform(; + apiUrl::AbstractString="https://api.navability.io", + UserId::AbstractString="guest@navability.io", + RobotId::AbstractString=ENV["USER"], + SessionId::AbstractString="Session_" * string(uuid4())[1:8]) + # + client = NavAbilityHttpsClient(apiUrl) + context = Client(UserId, RobotId, SessionId) + return NavAbilityPlatform(client, context) +end + +""" + addVariable +Add a variable to the NavAbility Platform service +Example +```julia +nva = NavAbilityPlatform() +addVariable(nva, "x0", NVA.Pose2) +``` +""" +function addVariable( + nva::NavAbilityPlatform, + lbl::Union{<:AbstractString,Symbol}, + varType::Union{<:AbstractString,Symbol} ) + # + + v = Variable(string(lbl), Symbol(varType)) + return addVariable(nva.client, nva.context, v) +end + + +function assembleFactorName(xisyms::Union{Vector{String},Vector{Symbol}}) + return string(xisyms...,"f_",string(uuid4())[1:4]) +end + +function getFncTypeName(fnc::InferenceType) + return split(string(typeof(fnc)),".")[end] +end + + +#TODO solverParams + +function addFactor(nva::NavAbilityPlatform, + xisyms::Union{Vector{String},Vector{Symbol}}, + fnc::InferenceType; + multihypo::Vector{Float64}=Float64[], + nullhypo::Float64=0.0, + solvable::Int=1, + tags::Vector{String}=["FACTOR"], + # timestamp::Union{DateTime,ZonedDateTime}=now(localzone()), + timestamp::String = string(now(Dates.UTC))*"Z", + inflation::Real=3.0, + namestring::String = assembleFactorName(xisyms), + nstime::String="0" + ) + # TODO maybe + # graphinit::Bool=true, + # threadmodel=SingleThreaded, + # suppressChecks::Bool=false, + # _blockRecursion::Bool=!getSolverParams(dfg).attemptGradients + # + # create factor data + factordata = FactorData(;fnc, multihypo, nullhypo, inflation) + + fncType = getFncTypeName(fnc) + # create factor + factor = Factor( + namestring, + nstime, + fncType, + string.(xisyms), + factordata, + solvable, + tags, + timestamp, + DFG_VERSION + ) + # add factor + resultId = addFactor(nva.client, nva.context, factor) + + return factor, resultId +end From 45ac076fdbd60a90e7f5e93d8b93b662c8caad93 Mon Sep 17 00:00:00 2001 From: Johannes Terblanche Date: Thu, 21 Apr 2022 21:56:10 +0200 Subject: [PATCH 05/15] Defer client_context --- src/navability/services/StandardAPI.jl | 51 +++++++++++++------------- 1 file changed, 25 insertions(+), 26 deletions(-) diff --git a/src/navability/services/StandardAPI.jl b/src/navability/services/StandardAPI.jl index 75850eb..1e21784 100644 --- a/src/navability/services/StandardAPI.jl +++ b/src/navability/services/StandardAPI.jl @@ -1,44 +1,42 @@ ## Wrap to standard API spec - +# Leaving as comment for future plans, see https://github.com/NavAbility/nva-sdk/issues/21 # TODO What to use: # - NavAbilityPlatform # - NavAbilityConnection # - NavAbilityClientContext # - -mutable struct NavAbilityPlatform{T} - client - context::T -end +# mutable struct NavAbilityPlatform{T} +# client +# context::T +# end -function NavAbilityPlatform(; - apiUrl::AbstractString="https://api.navability.io", - UserId::AbstractString="guest@navability.io", - RobotId::AbstractString=ENV["USER"], - SessionId::AbstractString="Session_" * string(uuid4())[1:8]) - # - client = NavAbilityHttpsClient(apiUrl) - context = Client(UserId, RobotId, SessionId) - return NavAbilityPlatform(client, context) -end +# function NavAbilityPlatform(; +# apiUrl::AbstractString="https://api.navability.io", +# UserId::AbstractString="guest@navability.io", +# RobotId::AbstractString=ENV["USER"], +# SessionId::AbstractString="Session_" * string(uuid4())[1:8]) +# # +# client = NavAbilityHttpsClient(apiUrl) +# context = Client(UserId, RobotId, SessionId) +# return NavAbilityPlatform(client, context) +# end """ addVariable Add a variable to the NavAbility Platform service Example ```julia -nva = NavAbilityPlatform() -addVariable(nva, "x0", NVA.Pose2) +addVariable(client, context, "x0", NVA.Pose2) ``` """ -function addVariable( - nva::NavAbilityPlatform, - lbl::Union{<:AbstractString,Symbol}, - varType::Union{<:AbstractString,Symbol} ) +function addVariable(client, + context, + lbl::Union{<:AbstractString,Symbol}, + varType::Union{<:AbstractString,Symbol}) # - v = Variable(string(lbl), Symbol(varType)) - return addVariable(nva.client, nva.context, v) + return addVariable(client, context, v) end @@ -53,14 +51,15 @@ end #TODO solverParams -function addFactor(nva::NavAbilityPlatform, +function addFactor(client, + context, xisyms::Union{Vector{String},Vector{Symbol}}, fnc::InferenceType; multihypo::Vector{Float64}=Float64[], nullhypo::Float64=0.0, solvable::Int=1, tags::Vector{String}=["FACTOR"], - # timestamp::Union{DateTime,ZonedDateTime}=now(localzone()), + # timestamp::Union{DateTime,ZonedDateTime}=now(localzone()), #TODO why timestamp difference from IIF timestamp::String = string(now(Dates.UTC))*"Z", inflation::Real=3.0, namestring::String = assembleFactorName(xisyms), @@ -89,7 +88,7 @@ function addFactor(nva::NavAbilityPlatform, DFG_VERSION ) # add factor - resultId = addFactor(nva.client, nva.context, factor) + resultId = addFactor(client, context, factor) return factor, resultId end From a0ac48f52afa624257ca855c55012cda282b777d Mon Sep 17 00:00:00 2001 From: Johannes Terblanche Date: Thu, 21 Apr 2022 22:15:16 +0200 Subject: [PATCH 06/15] Leave Pose1 until it can be deprecated --- src/navability/entities/Variable.jl | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/navability/entities/Variable.jl b/src/navability/entities/Variable.jl index 68d6838..42739f3 100644 --- a/src/navability/entities/Variable.jl +++ b/src/navability/entities/Variable.jl @@ -8,7 +8,9 @@ _variableTypeConvert = Dict{Symbol, String}( :Pose2 => "RoME.Pose2", :ContinuousScalar => "IncrementalInference.ContinuousScalar", # TBD - https://github.com/JuliaRobotics/Caesar.jl/discussions/807 - :Position1 => "IncrementalInference.ContinuousScalar" + :Position1 => "IncrementalInference.ContinuousScalar", + #TODO deprecate + :Pose1 => "IncrementalInference.ContinuousScalar" ) struct Variable From 9a4806db8be812e7c46a46d259c91085b44d5bf0 Mon Sep 17 00:00:00 2001 From: Johannes Terblanche Date: Thu, 21 Apr 2022 22:49:53 +0200 Subject: [PATCH 07/15] Basic tests of IIF like api --- src/navability/entities/InferenceTypes.jl | 8 +++++++ src/navability/services/StandardAPI.jl | 2 +- test/integration/testStandardAPI.jl | 28 +++++++++++++++++++++++ test/runtests.jl | 5 +++- 4 files changed, 41 insertions(+), 2 deletions(-) create mode 100644 test/integration/testStandardAPI.jl diff --git a/src/navability/entities/InferenceTypes.jl b/src/navability/entities/InferenceTypes.jl index 37b1df9..fb0acb8 100644 --- a/src/navability/entities/InferenceTypes.jl +++ b/src/navability/entities/InferenceTypes.jl @@ -28,6 +28,14 @@ Base.@kwdef struct Prior <: InferenceType Z::Distribution end +Base.@kwdef struct PriorPose2 <: InferenceType + Z::Distribution +end + +Base.@kwdef struct Pose2Pose2 <: InferenceType + Z::Distribution +end + """ $(TYPEDEF) diff --git a/src/navability/services/StandardAPI.jl b/src/navability/services/StandardAPI.jl index 1e21784..3bc9d45 100644 --- a/src/navability/services/StandardAPI.jl +++ b/src/navability/services/StandardAPI.jl @@ -90,5 +90,5 @@ function addFactor(client, # add factor resultId = addFactor(client, context, factor) - return factor, resultId + return resultId end diff --git a/test/integration/testStandardAPI.jl b/test/integration/testStandardAPI.jl new file mode 100644 index 0000000..4c5da57 --- /dev/null +++ b/test/integration/testStandardAPI.jl @@ -0,0 +1,28 @@ +apiUrl = get(ENV,"API_URL","https://api.navability.io") +userId = get(ENV,"USER_ID","guest@navability.io") +robotId = get(ENV,"ROBOT_ID","IntegrationRobot") +sessionId = get(ENV,"SESSION_ID","TestSession_"*string(uuid4())[1:8]) + +@testset "nva-sdk-standard-api-testset" begin + + client = NavAbilityHttpsClient(apiUrl) + context = Client(userId,robotId,sessionId) + + addVariable(client, context, "x0", :Pose2) + addFactor(client, context, ["x0"], NVA.PriorPose2(Z=FullNormal([0.,1.,0], diagm([1.,1,1])))) + + addVariable(client, context, :x1, :Pose2) + addFactor(client, context, [:x0,:x1], NVA.Pose2Pose2(Z=FullNormal([1.,0.,0], diagm([1.,1,1])))) + + addFactor(client, context, [:x1], NVA.PriorPose2(Z=FullNormal([1.,0.,0], diagm([1.,1,1]))); nullhypo=0.1) + + addFactor(client, context, ["x0"], NVA.PriorPose2(Z=FullNormal([0.5,0.5,0], diagm([1.,1,1])))) + + addVariable(client, context, :x2_a, :Pose2) + addVariable(client, context, :x2_b, :Pose2) + addFactor(client, context, ["x1", "x2_a", "x2_b"], NVA.PriorPose2(Z=FullNormal([0.5,0.5,0], diagm([1.,1,1]))); multihypo=[1,0.1,0.9]) + + addVariable(client, context, "y0", :Position1) + addFactor(client, context, ["y0"], NVA.Prior(Z=Normal(0.0, 1.0))) + +end \ No newline at end of file diff --git a/test/runtests.jl b/test/runtests.jl index eacfa8b..abaf0fc 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -1,2 +1,5 @@ include("./unit/runtests.jl") -include("./integration/runtests.jl") \ No newline at end of file +include("./integration/runtests.jl") + +#TODO I'm not familiar with the tests yet, so just dumping it here to get us started. +include("./integration/testStandardAPI.jl") \ No newline at end of file From 8c63000eb76b7f3fa9857f1fd98ca5f1355228d5 Mon Sep 17 00:00:00 2001 From: Johannes Terblanche Date: Thu, 21 Apr 2022 23:04:56 +0200 Subject: [PATCH 08/15] add a few Point2 factors --- src/navability/entities/InferenceTypes.jl | 14 ++++++++++++++ test/integration/testStandardAPI.jl | 7 +++++++ 2 files changed, 21 insertions(+) diff --git a/src/navability/entities/InferenceTypes.jl b/src/navability/entities/InferenceTypes.jl index fb0acb8..47c5a77 100644 --- a/src/navability/entities/InferenceTypes.jl +++ b/src/navability/entities/InferenceTypes.jl @@ -8,6 +8,7 @@ functions inside of factors. """ abstract type InferenceType end +#TODO maybe generate all ZInferenceTypes with a macro """ $(TYPEDEF) ZInferenceType is used by many factors as a common inference @@ -36,6 +37,19 @@ Base.@kwdef struct Pose2Pose2 <: InferenceType Z::Distribution end +Base.@kwdef struct PriorPoint2 <: InferenceType + Z::Distribution +end + +Base.@kwdef struct Point2Point2 <: InferenceType + Z::Distribution +end + +Base.@kwdef struct Point2Point2Range <: InferenceType + Z::Distribution +end + + """ $(TYPEDEF) diff --git a/test/integration/testStandardAPI.jl b/test/integration/testStandardAPI.jl index 4c5da57..d1de61b 100644 --- a/test/integration/testStandardAPI.jl +++ b/test/integration/testStandardAPI.jl @@ -25,4 +25,11 @@ sessionId = get(ENV,"SESSION_ID","TestSession_"*string(uuid4())[1:8]) addVariable(client, context, "y0", :Position1) addFactor(client, context, ["y0"], NVA.Prior(Z=Normal(0.0, 1.0))) + + addVariable(client, context, "z0", :Point2) + addFactor(client, context, ["z0"], NVA.PriorPoint2(Z=FullNormal([1.,0.], diagm([1.,1])))) + + addVariable(client, context, "z1", :Point2) + addFactor(client, context, ["z0", "z1"], NVA.Point2Point2(Z=FullNormal([1.,0.], diagm([1.,1])))) + end \ No newline at end of file From 3c04a50d3e5097c0713a0e99a2c313d88da0b2ae Mon Sep 17 00:00:00 2001 From: Dehann Fourie <6412556+dehann@users.noreply.github.com> Date: Sat, 23 Apr 2022 04:44:39 -0700 Subject: [PATCH 09/15] pass kw_sap arguments to ScatterAlignPose2 --- src/navability/entities/Factor.jl | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/navability/entities/Factor.jl b/src/navability/entities/Factor.jl index 968f437..5f193c4 100644 --- a/src/navability/entities/Factor.jl +++ b/src/navability/entities/Factor.jl @@ -138,11 +138,12 @@ function ScatterAlignPose2Data( bw2::AbstractVector{<:Real}=Float64[]; mkd1 = ManifoldKernelDensity(; varType, pts=cloud1, bw=bw1 ), mkd2 = ManifoldKernelDensity(; varType, pts=cloud2, bw=bw2 ), + kw_sap::NamedTuple=(;), kwargs... ) # - fnc = ScatterAlignPose2InferenceType(; cloud1=mkd1, cloud2=mkd2) + fnc = ScatterAlignPose2InferenceType(; cloud1=mkd1, cloud2=mkd2, kw_sap...) data = FactorData(; fnc, certainhypo = [1, 2], kwargs...) return data end From 7aa8ab44148ad92fcc0a14bc44e733ee5ef9c08c Mon Sep 17 00:00:00 2001 From: Johannes Terblanche Date: Tue, 3 May 2022 10:16:07 +0200 Subject: [PATCH 10/15] Macro for Z inferency types --- src/navability/entities/InferenceTypes.jl | 48 ++++++++--------------- 1 file changed, 17 insertions(+), 31 deletions(-) diff --git a/src/navability/entities/InferenceTypes.jl b/src/navability/entities/InferenceTypes.jl index 47c5a77..5460fa8 100644 --- a/src/navability/entities/InferenceTypes.jl +++ b/src/navability/entities/InferenceTypes.jl @@ -8,7 +8,23 @@ functions inside of factors. """ abstract type InferenceType end -#TODO maybe generate all ZInferenceTypes with a macro +macro nvaZInferenceType(inferencetype) + return esc(quote + Base.@__doc__ struct $inferencetype <: NVA.InferenceType + Z::Distribution + end + $inferencetype(;Z) = $inferencetype(Z) + end) +end + +@nvaZInferenceType Prior +@nvaZInferenceType LinearRelative +@nvaZInferenceType PriorPose2 +@nvaZInferenceType Pose2Pose2 +@nvaZInferenceType PriorPoint2 +@nvaZInferenceType Point2Point2 +@nvaZInferenceType Point2Point2Range + """ $(TYPEDEF) ZInferenceType is used by many factors as a common inference @@ -21,36 +37,6 @@ Base.@kwdef struct ZInferenceType <: InferenceType Z::Distribution end -Base.@kwdef struct LinearRelative <: InferenceType - Z::Distribution -end - -Base.@kwdef struct Prior <: InferenceType - Z::Distribution -end - -Base.@kwdef struct PriorPose2 <: InferenceType - Z::Distribution -end - -Base.@kwdef struct Pose2Pose2 <: InferenceType - Z::Distribution -end - -Base.@kwdef struct PriorPoint2 <: InferenceType - Z::Distribution -end - -Base.@kwdef struct Point2Point2 <: InferenceType - Z::Distribution -end - -Base.@kwdef struct Point2Point2Range <: InferenceType - Z::Distribution -end - - - """ $(TYPEDEF) Pose2Point2BearingRangeInferenceType is used to represent a bearing From d2e4c8c5b9dac9ec95ea55c674b8ded58e892e1d Mon Sep 17 00:00:00 2001 From: Johannes Terblanche Date: Tue, 3 May 2022 10:48:01 +0200 Subject: [PATCH 11/15] bump version to v0.5.0 --- Project.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Project.toml b/Project.toml index 4bdaf4c..768144e 100644 --- a/Project.toml +++ b/Project.toml @@ -3,7 +3,7 @@ uuid = "f3e6a059-199c-4ada-8143-fcefb97e6165" keywords = ["navability", "navigation", "slam", "sdk", "robotics", "robots"] desc = "NavAbility SDK: Access NavAbility Cloud factor graph features. Note that this SDK and the related API are still in development. Please let us know if you have any issues at info@navability.io." authors = ["NavAbility "] -version = "0.4.4" +version = "0.5.0" [deps] Dates = "ade2ca70-3891-5945-98fb-dc099432e06a" From e4ff76e3ffae9497a2edb64a7b8ef96b1ed6e44e Mon Sep 17 00:00:00 2001 From: dehann Date: Sun, 8 May 2022 15:12:18 -0700 Subject: [PATCH 12/15] add optional auth step --- src/navability/entities/NavAbilityClient.jl | 23 +++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/src/navability/entities/NavAbilityClient.jl b/src/navability/entities/NavAbilityClient.jl index af48caa..5d62baf 100644 --- a/src/navability/entities/NavAbilityClient.jl +++ b/src/navability/entities/NavAbilityClient.jl @@ -17,12 +17,31 @@ struct NavAbilityClient mutate::Function end -function NavAbilityWebsocketClient(apiUrl::String="wss://api.navability.io/graphql")::NavAbilityClient +function NavAbilityWebsocketClient( apiUrl::String="wss://api.navability.io/graphql")::NavAbilityClient throw("Not implemented") end -function NavAbilityHttpsClient(apiUrl::String="https://api.navability.io")::NavAbilityClient +function NavAbilityHttpsClient( + apiUrl::String="https://api.navability.io"; + authorize::Bool=false + )::NavAbilityClient + # dianaClient = GraphQLClient(apiUrl) + + # auth + if authorize + # FIXME, use Base.getpass instead of readline once VSCode supports getpass. + # st = Base.getpass("Copy-paste auth token") + # seekstart(st) + # tok = read(st, String) + # Base.shred!(st) + println(" > VSCode ONLY WORKAROUND, input issue, see https://github.com/julia-vscode/julia-vscode/issues/785") + println(" > Workaround: first press 0 then enter, and then paste the token and hit enter a second time.") + println("Copy-paste auth token: ") + tok = readline(stdin) + dianaClient.serverAuth("Bearer "*tok) + end + function query(options::QueryOptions) # NOTE, the query client library used is synchronous, locally converted to async for package consistency @async dianaClient.Query(options.query, operationName=options.name, vars=options.variables) From b510b2c3611f0b425523ad6e4b4f6a938efbae97 Mon Sep 17 00:00:00 2001 From: dehann Date: Sun, 8 May 2022 15:12:31 -0700 Subject: [PATCH 13/15] status bugfix --- src/navability/services/Status.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/navability/services/Status.jl b/src/navability/services/Status.jl index ac1dfd0..224680e 100644 --- a/src/navability/services/Status.jl +++ b/src/navability/services/Status.jl @@ -17,7 +17,7 @@ function getStatusMessagesEvent(navAbilityClient::NavAbilityClient, id::String) )) |> fetch rootData = JSON.parse(response.Data) if haskey(rootData, "errors") - throw("Error: $(data["errors"])") + throw("Error: $(rootData["errors"])") end data = get(rootData,"data",nothing) if data === nothing return "Error" end @@ -47,7 +47,7 @@ function getStatusLatestEvent(navAbilityClient::NavAbilityClient, id::String) )) |> fetch rootData = JSON.parse(response.Data) if haskey(rootData, "errors") - throw("Error: $(data["errors"])") + throw("Error: $(rootData["errors"])") end data = get(rootData,"data",nothing) if data === nothing return "Error" end From fde36648b480912ea6a9cf365761d8fd8fcf0275 Mon Sep 17 00:00:00 2001 From: dehann Date: Sun, 8 May 2022 23:10:52 -0700 Subject: [PATCH 14/15] basic data upload, download, addData, list (no export) --- Project.toml | 4 + src/NavAbilitySDK.jl | 5 + src/navability/graphql/DataBlobs.jl | 98 ++++++++++ src/navability/services/DataBlobs.jl | 268 +++++++++++++++++++++++++++ 4 files changed, 375 insertions(+) create mode 100644 src/navability/graphql/DataBlobs.jl create mode 100644 src/navability/services/DataBlobs.jl diff --git a/Project.toml b/Project.toml index 4bdaf4c..a08ac6f 100644 --- a/Project.toml +++ b/Project.toml @@ -9,6 +9,8 @@ version = "0.4.4" Dates = "ade2ca70-3891-5945-98fb-dc099432e06a" Diana = "070d9d8b-17a7-5814-83fa-42438ba5c6e0" DocStringExtensions = "ffbed154-4ef7-542d-bbb7-c09d3a79fcae" +Downloads = "f43a241f-c20a-4ad4-852c-f6b1247861c6" +HTTP = "cd3eb016-35fb-5094-929b-558a96fad6f3" JSON = "682c06a0-de6a-54ab-a142-c8b1cf79cde6" LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" @@ -17,6 +19,8 @@ UUIDs = "cf7118a7-6976-5b1a-9a39-7adc72f591a4" [compat] Diana = "0.2" DocStringExtensions = "0.8" +Downloads = "1" +HTTP = "0.9" JSON = "0.21" julia = "1.6" diff --git a/src/NavAbilitySDK.jl b/src/NavAbilitySDK.jl index 71dbac9..92461f4 100644 --- a/src/NavAbilitySDK.jl +++ b/src/NavAbilitySDK.jl @@ -5,6 +5,8 @@ using DocStringExtensions using LinearAlgebra using JSON using UUIDs +using Downloads +using HTTP # for overloading with visualization helpers import Base: show @@ -18,6 +20,7 @@ export uuid4 include("./navability/graphql/Factor.jl") include("./navability/graphql/Status.jl") include("./navability/graphql/Variable.jl") +include("./navability/graphql/DataBlobs.jl") include("./navability/graphql/QueriesDeprecated.jl") export QUERY_VARIABLE_LABELS @@ -53,6 +56,7 @@ include("./navability/services/Factor.jl") include("./navability/services/Solve.jl") include("./navability/services/Status.jl") include("./navability/services/Utils.jl") +include("./navability/services/DataBlobs.jl") export getVariable, getVariables, listVariables, ls export addVariable, addPackedVariable export getFactor, getFactors, listFactors, lsf @@ -62,4 +66,5 @@ export getStatusMessages, getStatusLatest, getStatusesLatest export waitForCompletion export GraphVizApp, MapVizApp + end diff --git a/src/navability/graphql/DataBlobs.jl b/src/navability/graphql/DataBlobs.jl new file mode 100644 index 0000000..e08a216 --- /dev/null +++ b/src/navability/graphql/DataBlobs.jl @@ -0,0 +1,98 @@ + + +GQL_CREATEDOWNLOAD = """ +mutation sdk_url_createdownload (\$userId: String!, \$fileId: ID!) { + url: createDownload( + userId: \$userId + fileId: \$fileId + ) +} +""" + + +GQL_CREATEUPLOAD = """ +mutation sdk_url_createupload(\$filename: String!, \$filesize: Int!, \$parts: Int!) { + createUpload( + file: { + filename: \$filename, + filesize: \$filesize + }, + parts: \$parts + ) { + uploadId + parts { + partNumber + url + } + file { + id + } + } +} +""" + + +GQL_COMPLETEUPLOAD_SINGLE = """ +mutation completeUpload(\$fileId: ID!, \$uploadId: ID!, \$eTag: String) { + completeUpload ( + fileId: \$fileId, + completedUpload: { + uploadId: \$uploadId, + parts: [ + { + partNumber: 1, + eTag: \$eTag + } + ] + } + ) +} +""" + + +GQL_ADDDATAENTRY = """ +mutation sdk_adddataentry(\$userId: ResourceId!, \$robotId: ResourceId!, \$sessionId: ResourceId!, \$variableLabel: String!, \$dataId: UUID!, \$dataLabel: String!, \$mimeType: String) { + addDataEntry ( + dataEntry: { + client: { + userId: \$userId, + robotId: \$robotId, + sessionId: \$sessionId + }, + blobStoreEntry: { + id: \$dataId, + label: \$dataLabel + mimetype: \$mimeType + }, + nodeLabel: \$variableLabel + } + ) +} +""" + + +GQL_LISTDATAVARIABLE = """ +query sdk_listdatavariable(\$userId: ID!, \$robotId: ID!, \$sessionId: ID!, \$variableLabel: ID!) { + users ( + where: {id: \$userId} + ) { + robots ( + where: {id: \$robotId} + ) { + sessions ( + where: {id: \$sessionId} + ) { + variables ( + where: {label: \$variableLabel} + ) { + data { + id + label + mimeType + } + } + } + } + } +} +""" \ No newline at end of file diff --git a/src/navability/services/DataBlobs.jl b/src/navability/services/DataBlobs.jl new file mode 100644 index 0000000..7eb0ed7 --- /dev/null +++ b/src/navability/services/DataBlobs.jl @@ -0,0 +1,268 @@ + + +""" +$(SIGNATURES) +Request URLs for data blob download. + +Args: + navAbilityClient (NavAbilityClient): The NavAbility client. + userId (String): The userId with access to the data. + fileId (String): The unique file identifier of the data blob. +""" +function createDownloadEvent( + navAbilityClient::NavAbilityClient, + userId::AbstractString, + fileId::AbstractString + ) + # + response = navAbilityClient.mutate(MutationOptions( + "sdk_url_createdownload", + GQL_CREATEDOWNLOAD, + Dict( + "userId" => userId, + "fileId" => fileId + ) + )) |> fetch + rootData = JSON.parse(response.Data) + if haskey(rootData, "errors") + throw("Error: $(rootData["errors"])") + end + data = get(rootData,"data",nothing) + if data === nothing return "Error" end + urlMsg = get(data,"url","Error") + # TODO: What about marshalling? + return urlMsg +end + +createDownload(w...) = @async createDownloadEvent(w...) + +## + + +function getDataEvent( + client::NavAbilityClient, + userId::AbstractString, + fileId::AbstractString + ) + # + url = createDownload(client, userId, fileId) |> fetch + io = PipeBuffer() + Downloads.download(url, io) + io +end + +getData(w...) = @async getDataEvent(w...) + + +## ========================================================================= +## Upload +## ========================================================================= + + +""" +$(SIGNATURES) +Request URLs for data blob upload. + +Args: + navAbilityClient (NavAbilityClient): The NavAbility client. + filename (String): file/blob name. + filesize (Int): total number of bytes to upload. + parts (Int): Split upload into multiple blob parts, FIXME currently only supports parts=1. +""" +function createUploadEvent( + navAbilityClient::NavAbilityClient, + filename::AbstractString, + filesize::Int, + parts::Int=1 + ) + # + response = navAbilityClient.mutate(MutationOptions( + "sdk_url_createupload", + GQL_CREATEUPLOAD, + Dict( + "filename" => filename, + "filesize" => filesize, + "parts" => parts + ) + )) |> fetch + rootData = JSON.parse(response.Data) + if haskey(rootData, "errors") + throw("Error: $(rootData["errors"])") + end + data = get(rootData,"data",nothing) + if data === nothing return "Error" end + uploadResp = get(data,"createUpload","Error") + # TODO: What about marshalling? + return uploadResp +end + +createUpload(w...) = @async createUploadEvent(w...) + + +## Complete the upload + + +function completeUploadSingleEvent( + navAbilityClient::NavAbilityClient, + fileId::AbstractString, + uploadId::AbstractString, + eTag::AbstractString, + ) + response = navAbilityClient.mutate(MutationOptions( + "completeUpload", + GQL_COMPLETEUPLOAD_SINGLE, + Dict( + "fileId" => fileId, + "uploadId" => uploadId, + "eTag" => eTag + ) + )) |> fetch + rootData = JSON.parse(response.Data) + if haskey(rootData, "errors") + throw("Error: $(rootData["errors"])") + end + data = get(rootData,"data",nothing) + if data === nothing return "Error" end + uploadResp = get(data,"completeUpload","Error") + return uploadResp +end + +completeUploadSingle(w...) = @async completeUploadSingleEvent(w...) + + +## + + +function addDataEvent( + client::NavAbilityClient, + blobname::AbstractString, + blob::AbstractVector{UInt8} + ) + # + io = IOBuffer(blob) + + filesize = io.size + np = 1 + # create the upload url destination + d = NVA.createUploadEvent(client, blobname, filesize, np) + + url = d["parts"][1]["url"] + uploadId = d["uploadId"] + fileId = d["file"]["id"] + + # custom header for pushing the file up + headers = [ + "Content-Length" => filesize, + "Accept" => "application/json, text/plain, */*", + "Accept-Encoding" => "gzip, deflate, br", + "Sec-Fetch-Dest" => "empty", + "Sec-Fetch-Mode" => "cors", + "Sec-Fetch-Site" => "cross-site", + "Sec-GPC" => 1, + "Connection" => "keep-alive" + ] + # + + # fid = open(filepath,"r") + resp = HTTP.put(url, headers, io) + # close(fid) + + # Extract eTag + eTag = match(r"[a-zA-Z0-9]+",resp["eTag"]).match + + # close out the upload + res = NVA.completeUploadSingleEvent(client, fileId, uploadId, eTag) + + res == "Accepted" ? nothing : @error("Unable to upload blob, $res") + + fileId +end + + +addData(w...) = @async addDataEvent(w...) + + +## + + +function addDataEntryEvent( + navAbilityClient::NavAbilityClient, + userId::AbstractString, + robotId::AbstractString, + sessionId::AbstractString, + variableLabel::AbstractString, + dataId::AbstractString, + dataLabel::AbstractString, + mimeType::AbstractString="", + ) + response = navAbilityClient.mutate(MutationOptions( + "sdk_adddataentry", + GQL_ADDDATAENTRY, + Dict( + "userId" => userId, + "robotId" => robotId, + "sessionId" => sessionId, + "variableLabel" => variableLabel, + "dataId" => dataId, + "dataLabel" => dataLabel, + "mimeType" => mimeType, + ) + )) |> fetch + rootData = JSON.parse(response.Data) + if haskey(rootData, "errors") + throw("Error: $(rootData["errors"])") + end + data = get(rootData,"data",nothing) + if data === nothing return "Error" end + addentryresp = get(data,"addDataEntry","Error") + return addentryresp +end + +addDataEntry(w...) = @async addDataEntryEvent(w...) + + +## + + +function listDataVariableEvent( + navAbilityClient::NavAbilityClient, + userId::AbstractString, + robotId::AbstractString, + sessionId::AbstractString, + variableLabel::AbstractString + ) + # + response = navAbilityClient.mutate(MutationOptions( + "sdk_listdatavariable", + GQL_LISTDATAVARIABLE, + Dict( + "userId" => userId, + "robotId" => robotId, + "sessionId" => sessionId, + "variableLabel" => variableLabel + ) + )) |> fetch + rootData = JSON.parse(response.Data) + if haskey(rootData, "errors") + throw("Error: $(rootData["errors"])") + end + data = get(rootData,"data",nothing) + if data === nothing return "Error" end + + listdata = data["users"][1]["robots"][1]["sessions"][1]["variables"][1]["data"] + ret = [] + for d in listdata + tupk = Tuple(Symbol.(keys(d))) + nt = NamedTuple{tupk}( values(d) ) + push!(ret, + nt + ) + end + + return ret +end + +listDataVariable(w...) = @async listDataVariableEvent(w...) + + +## \ No newline at end of file From 8f6d6cf73b58ac0c36aac31563c972fac70802c4 Mon Sep 17 00:00:00 2001 From: Johannes Terblanche Date: Mon, 9 May 2022 18:28:05 +0200 Subject: [PATCH 15/15] Better addVariablekwargs and Update InferenceTypes --- Project.toml | 2 +- src/navability/entities/InferenceTypes.jl | 11 ++++++++--- src/navability/services/StandardAPI.jl | 17 +++++++++++++---- 3 files changed, 22 insertions(+), 8 deletions(-) diff --git a/Project.toml b/Project.toml index 768144e..2737c87 100644 --- a/Project.toml +++ b/Project.toml @@ -3,7 +3,7 @@ uuid = "f3e6a059-199c-4ada-8143-fcefb97e6165" keywords = ["navability", "navigation", "slam", "sdk", "robotics", "robots"] desc = "NavAbility SDK: Access NavAbility Cloud factor graph features. Note that this SDK and the related API are still in development. Please let us know if you have any issues at info@navability.io." authors = ["NavAbility "] -version = "0.5.0" +version = "0.4.5" [deps] Dates = "ade2ca70-3891-5945-98fb-dc099432e06a" diff --git a/src/navability/entities/InferenceTypes.jl b/src/navability/entities/InferenceTypes.jl index c369113..57c5032 100644 --- a/src/navability/entities/InferenceTypes.jl +++ b/src/navability/entities/InferenceTypes.jl @@ -42,16 +42,18 @@ $(TYPEDEF) Pose2Point2BearingRangeInferenceType is used to represent a bearing + range measurement. """ -Base.@kwdef struct Pose2Point2BearingRangeInferenceType <: InferenceType +Base.@kwdef struct Pose2Point2BearingRange <: InferenceType bearstr::Distribution rangstr::Distribution end +const Pose2Point2BearingRangeInferenceType = Pose2Point2BearingRange + """ $(TYPEDEF) InferenceType for Pose2AprilTag4CornersData. """ -Base.@kwdef struct Pose2AprilTag4CornersInferenceType <: InferenceType +Base.@kwdef struct Pose2AprilTag4Corners <: InferenceType corners::Vector{Float64} homography::Vector{Float64} K::Vector{Float64} @@ -60,8 +62,9 @@ Base.@kwdef struct Pose2AprilTag4CornersInferenceType <: InferenceType _type::String = "/application/JuliaLang/PackedPose2AprilTag4Corners" end +const Pose2AprilTag4CornersInferenceType = Pose2AprilTag4Corners -Base.@kwdef struct ScatterAlignPose2InferenceType <: InferenceType +Base.@kwdef struct ScatterAlignPose2 <: InferenceType """ This SDK only supports MKD clouds at this time. Note CJL also supports HeatmapGridDensity, TODO """ cloud1::ManifoldKernelDensity cloud2::ManifoldKernelDensity @@ -84,6 +87,8 @@ Base.@kwdef struct ScatterAlignPose2InferenceType <: InferenceType _type::String = "Caesar.PackedScatterAlignPose2" end +const ScatterAlignPose2InferenceType = ScatterAlignPose2 + """ $(TYPEDEF) InferenceType for MixtureData. diff --git a/src/navability/services/StandardAPI.jl b/src/navability/services/StandardAPI.jl index 3bc9d45..ee31d18 100644 --- a/src/navability/services/StandardAPI.jl +++ b/src/navability/services/StandardAPI.jl @@ -32,10 +32,17 @@ addVariable(client, context, "x0", NVA.Pose2) """ function addVariable(client, context, - lbl::Union{<:AbstractString,Symbol}, - varType::Union{<:AbstractString,Symbol}) + label::Union{<:AbstractString,Symbol}, + varType::Union{<:AbstractString,Symbol}; + tags::Vector{String}=String[], + timestamp::String = string(now(Dates.UTC))*"Z") + # TODO + # solvable::Int=1 + # nanosecondtime, + # smalldata, # - v = Variable(string(lbl), Symbol(varType)) + union!(tags, ["VARIABLE"]) + v = Variable(string(label), Symbol(varType), tags, timestamp) return addVariable(client, context, v) end @@ -58,7 +65,7 @@ function addFactor(client, multihypo::Vector{Float64}=Float64[], nullhypo::Float64=0.0, solvable::Int=1, - tags::Vector{String}=["FACTOR"], + tags::Vector{String}=String[], # timestamp::Union{DateTime,ZonedDateTime}=now(localzone()), #TODO why timestamp difference from IIF timestamp::String = string(now(Dates.UTC))*"Z", inflation::Real=3.0, @@ -75,6 +82,8 @@ function addFactor(client, factordata = FactorData(;fnc, multihypo, nullhypo, inflation) fncType = getFncTypeName(fnc) + + union!(tags, ["FACTOR"]) # create factor factor = Factor( namestring,