@@ -73,11 +73,13 @@ function solve_with_ipopt(problem::Problem, robot::Robot;
7373
7474 use_m₁ = true # nonlinear equality: dynamics
7575 use_m₂ = true # nonlinear equality: ee xyz-position
76+ use_m₃ = true # nonlinear equality: ee rotation
7677
7778 m₁ = ! use_m₁ ? 0 : (robot. n_q + robot. n_v) * (problem. num_knots - 1 ) # equations of motion
7879 m₂ = ! use_m₂ ? 0 : 3 * length (problem. ee_pos) # xyz-position (3 NL equality)
80+ m₃ = ! use_m₃ ? 0 : body_orientation_constraints_per_knot (problem) |> sum
7981
80- m = m₁ + m₂ # total number of constraints
82+ m = m₁ + m₂ + m₃ # total number of constraints
8183
8284 g_L, g_U = Float64[], Float64[]
8385
@@ -93,7 +95,28 @@ function solve_with_ipopt(problem::Problem, robot::Robot;
9395 append! (g_U, vec (con_ee))
9496 end
9597
96- @assert length (g_L) == length (g_U)
98+ body_name = " panda_link7" # TODO ... hard-coded for now.
99+ # We want to iterate only through the constrained knots for this robot body/link.
100+ knots = filter (1 : problem. num_knots) do knotᵢ
101+ knotᵢ ∈ keys (problem. constraints_body_orientation) &&
102+ body_name ∈ keys (problem. constraints_body_orientation[knotᵢ])
103+ end
104+
105+ jacdata = JacobianData ((out, x) -> body_orientation! (out, robot, x), rand (3 ), rand (robot. n_q))
106+
107+ if use_m₃
108+ # These are the target values for the equalities of Knitro.
109+ con_vals = mapreduce (hcat, knots; init= Matrix {Float64} (undef, 3 , 0 )) do k
110+ dₖ = problem. constraints_body_orientation[k]
111+ mrp = MRP (dₖ[body_name])
112+ [mrp. x, mrp. y, mrp. z]
113+ end
114+
115+ append! (g_L, con_vals)
116+ append! (g_U, con_vals)
117+ end
118+
119+ @assert length (g_L) == length (g_U) == m
97120 @assert eltype (g_L) == eltype (g_U) == Float64
98121
99122 # dimension of each mesh point
@@ -122,14 +145,25 @@ function solve_with_ipopt(problem::Problem, robot::Robot;
122145 end
123146
124147 if use_m₂
125- length_c = 3
148+ length_c = size (problem . jacdata_ee_position . jac, 1 ) # length of constraint (per knot)
126149 for (i, k) = enumerate (sort (collect (keys (problem. ee_pos))))
127150 ind_vars = range (1 + (k - 1 ) * nₓ, length= robot. n_q) # indices of the decision variables
128151 offset_con = (i - 1 ) * length_c + (m₁)
129152 ind_cons = (1 : length_c) .+ offset_con
130153 @views ee_position! (g[ind_cons], robot, x[ind_vars]) # constraint evaluation at that point
131154 end
132155 end
156+
157+ if use_m₃
158+ length_c = size (jacdata. jac, 1 ) # length of constraint (per knot)
159+ offset_con = m₁ + m₂
160+ for i = knots .- 1
161+ ind_cons = (1 : length_c) .+ offset_con # Indices of the respective constraints
162+ ind_vars = range (1 + i * nₓ, length= robot. n_q) # Indices of the decision variables
163+ @views body_orientation! (g[ind_cons], robot, x[ind_vars]) # Constraint evaluation at that point
164+ offset_con += length_c
165+ end
166+ end
133167 end
134168
135169 jacIndexConsCB = Cint[]
@@ -167,6 +201,22 @@ function solve_with_ipopt(problem::Problem, robot::Robot;
167201 @assert length (jacIndexConsCB) == length (jacIndexVarsCB)
168202 end
169203
204+ if use_m₃
205+ ind_offset = m₁ + m₂
206+ for k = knots
207+ inds = rowvals (jacdata. jac) .+ ind_offset
208+ ind_offset += size (jacdata. jac, 1 )
209+ append! (jacIndexConsCB, inds)
210+ end
211+
212+ for k = knots
213+ vals = vcat ([fill (j + (k - 1 ) * nₓ, length (nzrange (jacdata. jac, j)))
214+ for j = 1 : size (jacdata. jac, 2 )]. .. )
215+ append! (jacIndexVarsCB, vals)
216+ end
217+
218+ @assert length (jacIndexConsCB) == length (jacIndexVarsCB)
219+ end
170220
171221 function eval_jac_g (x, rows, cols, values:: Union{Nothing,Vector{Float64}} )
172222 if isnothing (values)
@@ -186,22 +236,36 @@ function solve_with_ipopt(problem::Problem, robot::Robot;
186236 # Evaluate the Jacobian at that point
187237 jacdata_dyn (x[ind_vars])
188238
189- # Pass the Jacobian to Knitro
190- offset_jac = i * jacdata_dyn. jac_length
191- ind_jac = (1 : jacdata_dyn. jac_length) .+ offset_jac
239+ # Pass the Jacobian to Ipopt
240+ ind_jac = (1 : jacdata_dyn. jac_length) .+ offset_prev
192241 values[ind_jac] = nonzeros (jacdata_dyn. jac)
242+ offset_prev += jacdata_dyn. jac_length
193243 end
194- offset_prev += (problem. num_knots - 1 ) * jacdata_dyn. jac_length
195244 end
196245
197246 if use_m₂
198247 # End-effector constraints
199248 for (i, k) = enumerate (sort (collect (keys (problem. ee_pos))))
200249 ind_qᵢ = range (1 + (k - 1 ) * nₓ, length= robot. n_q) # indices of the decision variables
201250 problem. jacdata_ee_position (x[ind_qᵢ]) # jacobian evaluation at that point
202- offset_jac = (i - 1 ) * problem. jacdata_ee_position. jac_length + offset_prev
203- ind_jac = (1 : problem. jacdata_ee_position. jac_length) .+ offset_jac
204- values[ind_jac] = nonzeros (problem. jacdata_ee_position. jac) # pass jacobian to Knitro
251+
252+ # Pass the Jacobian to Ipopt
253+ ind_jac = (1 : problem. jacdata_ee_position. jac_length) .+ offset_prev
254+ values[ind_jac] = nonzeros (problem. jacdata_ee_position. jac)
255+ offset_prev += problem. jacdata_ee_position. jac_length
256+ end
257+ end
258+
259+ if use_m₃
260+ # End-effector constraints (rotation)
261+ for k = knots
262+ ind_qᵢ = range (1 + (k - 1 ) * nₓ, length= robot. n_q) # Indices of the decision variables
263+ jacdata (x[ind_qᵢ]) # Evaluate the Jacobian at that point
264+
265+ # Pass the Jacobian to Ipopt
266+ ind_jac = (1 : jacdata. jac_length) .+ offset_prev
267+ values[ind_jac] = nonzeros (jacdata. jac)
268+ offset_prev += jacdata. jac_length
205269 end
206270 end
207271 end
@@ -244,6 +308,7 @@ function solve_with_ipopt(problem::Problem, robot::Robot;
244308 nele_jac = 0
245309 nele_jac += ! use_m₁ ? 0 : jacdata_dyn. jac_length * (problem. num_knots - 1 )
246310 nele_jac += ! use_m₂ ? 0 : problem. jacdata_ee_position. jac_length * length (problem. ee_pos)
311+ nele_jac += ! use_m₃ ? 0 : jacdata. jac_length * length (knots)
247312
248313 prob = Ipopt. CreateIpoptProblem (n, vec (x_L), vec (x_U), m, g_L, g_U, nele_jac, 0 ,
249314 eval_f, eval_g, eval_grad_f, eval_jac_g, nothing )
0 commit comments