Validation

Run all models with the same step inputs to visually validate that the drones do what we think they should do.

More of a sanity check for me than anything.

[1]:
%matplotlib notebook
from notebook_quick_setup import *
Beginning notebook setup...
        Added /home/jhewers/Documents/projects/jdrones/src to path
        Imported gymnasium version 0.27.1
pybullet build time: Feb  2 2023 13:13:41
/home/jhewers/.local/lib/python3.10/site-packages/scipy/__init__.py:146: UserWarning: A NumPy version >=1.16.5 and <1.23.0 is required for this version of SciPy (detected version 1.23.5
  warnings.warn(f"A NumPy version >={np_minversion} and <{np_maxversion}"
        Imported jdrones version unknown
        Imported scipy==1.7.3, numpy==1.23.5, pandas==1.3.5
        Imported functools, collections and itertools
        Imported tqdm (standard and trange)
        Imported seaborn==0.11.2, matplotlib==3.5.1
End of notebook setup
[2]:
dt = 1 / 240
seed = 1337
[3]:
initial_state = State()
initial_state.pos = (0, 0, 1)
pb3_env = gymnasium.make("PyBulletDroneEnv-v0", dt=dt, initial_state=initial_state)

nl_env = gymnasium.make(
    "NonLinearDynamicModelDroneEnv-v0", dt=dt, initial_state=initial_state
)


class LinEnvUpdateWrapper(gymnasium.ActionWrapper):
    @staticmethod
    def action(action):
        return np.square(action)


l_env = gymnasium.make(
    "LinearDynamicModelDroneEnv-v0", dt=dt, initial_state=initial_state
)
l_env = LinEnvUpdateWrapper(l_env)
[4]:
def output_to_df(output):
    dfs = [States(v).to_df(tag=k, dt=dt) for k, v in output.items()]
    return pd.concat(dfs).reset_index()


def run(env, u):
    log = collections.deque()
    obs, _ = env.reset()
    for ui in u:
        log.append(np.copy(obs))
        obs, _, term, trunc, _ = env.step(ui)
        if term or trunc:
            break
    return np.array(log)


def run_envs(u):
    return output_to_df(
        dict(
            PB3=run(pb3_env, u),
            NL=run(nl_env, u),
            L=run(l_env, u),
        )
    )


def plot_data(df):
    fig, ax = plt.subplots(3, figsize=(8, 12))
    ax = ax.flatten()
    for i, vars in enumerate(["'x','y','z'", "'phi','theta','psi'", "'vx','vy','vz'"]):
        sns.lineplot(
            data=df.query(f"variable in ({vars})"),
            x="t",
            y="value",
            hue="variable",
            style="tag",
            ax=ax[i],
        )
        ax[i].legend()

    fig.tight_layout()
    plt.show()

    fig, ax = plt.subplots(12, figsize=(8, 15))
    ax = ax.flatten()
    for i, var in enumerate(("x", "y", "z", "phi", "theta", "psi", "vx", "vy", "vz", "p","q","r")):
        sns.lineplot(
            data=df.query(f"variable in ('{var}')"),
            x="t",
            y="value",
            hue="variable",
            style="tag",
            ax=ax[i],
            legend=False,
        )
        ax[i].set_ylabel(var)
    fig.tight_layout()
    plt.show()

Zero Inputs

[5]:
T = 0.4
u = np.zeros((int(T/dt),4))
out = run_envs(u)
plot_data(out)

Positive Inputs

[6]:
T = 0.5
u = np.ones((int(T/dt),4))*20
out = run_envs(u)
plot_data(out)

Hover Input

[7]:
T = 0.4
u = np.ones((int(T/dt),4))*np.sqrt(9.81*1.4/(0.1*4))
out = run_envs(u)
plot_data(out)

Roll Input

[8]:
T = 0.1
u = np.array((1,0.9,1,1.1))*np.sqrt(9.81*1.4/(0.1*4))
out = run_envs(np.tile(u, (int(T/dt),1)))
plot_data(out)

Pitch Input

[9]:
T = 0.1
u = np.tile(np.array((0.9999,1,1.0001,1))*np.sqrt(9.81*1.4/(0.1*4)),(int(T/dt),1))
out = run_envs(u)
plot_data(out)

Yaw Input

[10]:
T = 0.4
u = np.tile(np.array((1,0,1,0))*np.sqrt(9.81*1.4/(0.1*2)),(int(T/dt),1))
out = run_envs(u)
plot_data(out)