@@ -224,73 +224,6 @@ def symbolic_attitude(dt: float, params: dict | None = None) -> SymbolicModel:
224224 return SymbolicModel (dynamics = dynamics , cost = cost , dt = dt )
225225
226226
227- def symbolic_thrust (mass : float , J : NDArray , dt : float ) -> SymbolicModel :
228- """Create symbolic (CasADi) models for dynamics, observation, and cost of a quadcopter.
229-
230- This model is based on the analytical model of Luis, Carlos, and Jérôme Le Ny. "Design of a
231- trajectory tracking controller for a nanoquadcopter." arXiv preprint arXiv:1608.05786 (2016).
232-
233- Returns:
234- The CasADi symbolic model of the environment.
235- """
236- # Define states.
237- z = MX .sym ("z" )
238- z_dot = MX .sym ("z_dot" )
239-
240- # Set up the dynamics model for a 3D quadrotor.
241- nx , nu = 12 , 4
242- Ixx , Iyy , Izz = J .diagonal ()
243- J = cs .blockcat ([[Ixx , 0.0 , 0.0 ], [0.0 , Iyy , 0.0 ], [0.0 , 0.0 , Izz ]])
244- Jinv = cs .blockcat ([[1.0 / Ixx , 0.0 , 0.0 ], [0.0 , 1.0 / Iyy , 0.0 ], [0.0 , 0.0 , 1.0 / Izz ]])
245- gamma = KM / KF
246- # System state variables
247- x , y = MX .sym ("x" ), MX .sym ("y" )
248- x_dot , y_dot = MX .sym ("x_dot" ), MX .sym ("y_dot" )
249- phi , theta , psi = MX .sym ("phi" ), MX .sym ("theta" ), MX .sym ("psi" )
250- p , q , r = MX .sym ("p" ), MX .sym ("q" ), MX .sym ("r" )
251- # Rotation matrix transforming a vector in the body frame to the world frame. PyBullet Euler
252- # angles use the SDFormat for rotation matrices.
253- Rob = csRotXYZ (phi , theta , psi )
254- # Define state variables.
255- X = cs .vertcat (x , y , z , phi , theta , psi , x_dot , y_dot , z_dot , p , q , r )
256- # Define inputs.
257- f1 , f2 , f3 , f4 = MX .sym ("f1" ), MX .sym ("f2" ), MX .sym ("f3" ), MX .sym ("f4" )
258- U = cs .vertcat (f1 , f2 , f3 , f4 )
259-
260- # Defining the dynamics function.
261- # We are using the velocity of the base wrt to the world frame expressed in the world frame.
262- # Note that the reference expresses this in the body frame.
263- pos_ddot = Rob @ cs .vertcat (0 , 0 , f1 + f2 + f3 + f4 ) / mass - cs .vertcat (0 , 0 , GRAVITY )
264- pos_dot = cs .vertcat (x_dot , y_dot , z_dot )
265- # We use the spin directions (signs) from the mix matrix used in the simulation.
266- sx , sy , sz = SIGN_MIX_MATRIX [..., 0 ], SIGN_MIX_MATRIX [..., 1 ], SIGN_MIX_MATRIX [..., 2 ]
267- Mb = cs .vertcat (
268- ARM_LEN / cs .sqrt (2.0 ) * (sx [0 ] * f1 + sx [1 ] * f2 + sx [2 ] * f3 + sx [3 ] * f4 ),
269- ARM_LEN / cs .sqrt (2.0 ) * (sy [0 ] * f1 + sy [1 ] * f2 + sy [2 ] * f3 + sy [3 ] * f4 ),
270- gamma * (sz [0 ] * f1 + sz [1 ] * f2 + sz [2 ] * f3 + sz [3 ] * f4 ),
271- )
272- rate_dot = Jinv @ (Mb - (cs .skew (cs .vertcat (p , q , r )) @ J @ cs .vertcat (p , q , r )))
273- ang_dot = cs .blockcat (
274- [
275- [1 , cs .sin (phi ) * cs .tan (theta ), cs .cos (phi ) * cs .tan (theta )],
276- [0 , cs .cos (phi ), - cs .sin (phi )],
277- [0 , cs .sin (phi ) / cs .cos (theta ), cs .cos (phi ) / cs .cos (theta )],
278- ]
279- ) @ cs .vertcat (p , q , r )
280- X_dot = cs .vertcat (pos_dot , ang_dot , pos_ddot , rate_dot )
281-
282- Y = cs .vertcat (x , x_dot , y , y_dot , z , z_dot , phi , theta , psi , p , q , r )
283-
284- # Define cost (quadratic form).
285- Q , R = MX .sym ("Q" , nx , nx ), MX .sym ("R" , nu , nu )
286- Xr , Ur = MX .sym ("Xr" , nx , 1 ), MX .sym ("Ur" , nu , 1 )
287- cost_func = 0.5 * (X - Xr ).T @ Q @ (X - Xr ) + 0.5 * (U - Ur ).T @ R @ (U - Ur )
288- # Define dynamics and cost dictionaries.
289- dynamics = {"dyn_eqn" : X_dot , "obs_eqn" : Y , "vars" : {"X" : X , "U" : U }}
290- cost = {"cost_func" : cost_func , "vars" : {"X" : X , "U" : U , "Xr" : Xr , "Ur" : Ur , "Q" : Q , "R" : R }}
291- return SymbolicModel (dynamics = dynamics , cost = cost , dt = dt )
292-
293-
294227def symbolic_from_sim (sim : Sim ) -> SymbolicModel :
295228 """Create a symbolic model from a Sim instance.
296229
@@ -308,8 +241,7 @@ def symbolic_from_sim(sim: Sim) -> SymbolicModel:
308241 case Control .attitude :
309242 return symbolic_attitude (1 / sim .control_freq )
310243 case Control .force_torque :
311- mass , J = sim .default_data .params .mass [0 , 0 ], sim .default_data .params .J [0 , 0 ]
312- return symbolic_force_torque (mass , J , 1 / sim .control_freq )
244+ raise NotImplementedError ("Symbolic model for force torque control is not implemented" )
313245 case _:
314246 raise ValueError (f"Unsupported control type for symbolic model: { sim .control } " )
315247
0 commit comments