Paparazzi UAS v7.1_unstable
Paparazzi is a free software Unmanned Aircraft System.
Loading...
Searching...
No Matches
simple_quad_sim.py
Go to the documentation of this file.
1import pybullet as p
2import pybullet_data
3import numpy as np
4import time
5import os
6
7
8PPRZ_HOME = os.getenv("PAPARAZZI_HOME", os.getcwd())
9PYBULLET_CONF_PATH = os.path.join(PPRZ_HOME, "conf/simulator/pybullet")
10
11
12class BulletFDM():
13 def __init__(self, dt=0.02, GUI=True, debug=False, urdf="robobee.urdf"):
14 print(f"Hello from PyBullet ! dt={dt}, GUI={GUI} debug={debug}")
15
16 pprz_src = os.getenv("PAPARAZZI_SRC")
17 print(f"pprz_src = {pprz_src}")
18
19 # self.last_time_print = 0
20
21 # dt : Time step
22 self.dt=dt
23 if GUI:
25 else:
27 p.configureDebugVisualizer(p.COV_ENABLE_GUI,0) # remove useless graphical elements from GUI
28
29 # Add path for pybullet assests e.g : plane and grid...
31
32 self.planeId = p.loadURDF("plane.urdf")
33 self.textureId = p.loadTexture("checker_grid.jpg")
34
35 self.vehicle_start_pos = [0, 0, 0.2]
37
38 vehicule_urdf = os.path.join(PYBULLET_CONF_PATH, urdf)
40
41 # Bullet physics uses ENU frame
42 p.setGravity(0, 0, -9.81, physicsClientId=self.physicsClient)
43 # Real time simulation should be off in order to apply external force and moments !
44 p.setRealTimeSimulation(0, physicsClientId=self.physicsClient)
45 # dt : Time step
46 p.setTimeStep(self.dt, physicsClientId=self.physicsClient)
47 # Orient the camera if needed
48 p.resetDebugVisualizerCamera( cameraDistance=3.5, cameraYaw=-80, cameraPitch=-40, cameraTargetPosition=[0.0, 0.0, 0.0])
49 # Vehicle properties
50 self.KF = 0.01 ; self.KM = 0.001
51 # Initialte velocity and acceleration vectors
52 self.vel = np.zeros(3)
53 self.accel = np.zeros(3)
54 # Initialte angular velocity and acceleration vectors
55 self.ang_vel = np.zeros(3)
57
58 # State
59 self.observation = {}
60
61 # For debug purposes
62 if debug:
63 p.setGravity(0, 0, 0, physicsClientId=self.physicsClient)
64 self.roll_Id = p.addUserDebugParameter("roll_cmd", -0.01, 0.01, 0)
65 self.pitch_Id = p.addUserDebugParameter("pitch_cmd", -0.01, 0.01, 0)
66 self.yaw_Id = p.addUserDebugParameter("yaw_cmd", -0.01, 0.01, 0)
67
69 ''' rpm = [ quadrotor prop rpms ]'''
70 forces = np.array(rpm**2)*self.KF
71 torques = np.array(rpm**2)*self.KM
72
73 f_noise = np.random.normal(0, 0.01, len(rpm))
74 m_noise = np.random.normal(0, 0.001,len(rpm))
75
76 # f_noise = np.zeros(4)
77 # m_noise = np.zeros(4)
78
79 forces += f_noise
80 torques += m_noise
81
82 z_torque = (torques[0] - torques[1] + torques[2] - torques[3])
83 for i in range(4): #FIXME : decide according to commands length
85 i,
86 forceObj=[f_noise[0], f_noise[1], forces[i]],
87 posObj=[0, 0, 0],
88 flags=p.LINK_FRAME,
89 physicsClientId=self.physicsClient
90 )
92 -1, # FIXME : this is not correct , use center of mass !!!
93 torqueObj=[m_noise[0], m_noise[1], z_torque],
94 flags=p.LINK_FRAME,
95 physicsClientId=self.physicsClient
96 )
97
98 def step(self,commands):
99
100 if not isinstance(commands, np.ndarray):
101 commands = np.array(commands)
102
103 # little hack to scale commands. It should probably be in the URDF file.
104 commands *= 30
105
106 # t = time.time()
107 # if (t - self.last_time_print) > 0.5:
108 # self.last_time_print = t
109 # print(f"{commands[0]:.2f} {commands[1]:.2f} {commands[2]:.2f} {commands[3]:.2f}")
110
111 self.apply_force_and_moments(commands)
112 p.stepSimulation(physicsClientId=self.physicsClient)
113 return self.get_observation()
114
115 def step_debug(self,commands):
116 # commands are not used...
117 roll_cmd = p.readUserDebugParameter(self.roll_Id)
118 pitch_cmd = p.readUserDebugParameter(self.pitch_Id)
119 yaw_cmd = p.readUserDebugParameter(self.yaw_Id)
120
121 # p.applyExternalForce(self.vehicle,
122 # -1,
123 # forceObj=[0, 0, 9 + yaw_cmd*100],
124 # posObj=[0, 0, 0],
125 # flags=p.LINK_FRAME,
126 # physicsClientId=self.physicsClient
127 # )
128
130 -1, # FIXME : this is not correct , use center of mass !!!
131 torqueObj=[roll_cmd, pitch_cmd, yaw_cmd],
132 flags=p.LINK_FRAME,
133 physicsClientId=self.physicsClient
134 )
135
136 p.stepSimulation(physicsClientId=self.physicsClient)
137 return self.get_observation()
138
140 # Get observation
141 v_pos, v_quat = p.getBasePositionAndOrientation(self.vehicle)
142 v_rpy = p.getEulerFromQuaternion(v_quat)
143 v_vel, v_ang_v = p.getBaseVelocity(self.vehicle)
144
145 self.accel = (np.array(v_vel) - self.vel)/self.dt
146 self.vel = np.array(v_vel)
147 self.ang_accel = (np.array(v_ang_v) - self.ang_vel)/self.dt
148 self.ang_vel = np.array(v_ang_v)
150 body_ang_vel = R.T.dot(self.ang_vel)
151 body_ang_accel = R.T.dot(self.ang_accel)
152
153 self.observation = {'pos':v_pos,
154 'quat':v_quat,
155 'rpy':v_rpy,
156 'vel':tuple(self.vel),
157 'ang_v':tuple(body_ang_vel),
158 'accel':tuple(self.accel),
159 'ang_accel':tuple(body_ang_accel)
160 }
161 return self.observation
162
163 def reset(self):
164 # Reset the simulation and the state
165 # p.resetSimulation(physicsClientId=self.physicsClient) # FIXME : this is not the correct way to reset the simulation
167 p.resetBaseVelocity(self.vehicle, [0, 0, 0], [0, 0, 0])
168
169 return self.get_observation()
170
171
172
173if __name__ == "__main__":
174 from time import sleep
175 debug = True
176 m = BulletFDM(GUI=True, debug=debug)
177
178 # An example simulation loop with random commands generation
179 while 1:
180 for i in range(200):
181 # commands = np.array([10., 10., 10., 10.]) # fixed rpms
182 commands = np.random.normal(13., 0.5, 4) # random rpms
183 if debug:
184 m.step_debug(commands)
185 else:
186 m.step(commands)
187 sleep(0.05) # FIXME : checck the computation time and sleep to sync realtime...
188 m.reset()
static uint8_t reset[3]
__init__(self, dt=0.02, GUI=True, debug=False, urdf="robobee.urdf")
uint16_t foo
Definition main_demo5.c:58
uint8_t step
Definition max7456.c:140