diff --git a/Go2Py/assets/checkpoints/walk_these_ways/videos/00158.mp4 b/Go2Py/assets/checkpoints/walk_these_ways/videos/00158.mp4 deleted file mode 100644 index 015c9f5..0000000 Binary files a/Go2Py/assets/checkpoints/walk_these_ways/videos/00158.mp4 and /dev/null differ diff --git a/Go2Py/assets/checkpoints/walk_these_ways/videos/00209.mp4 b/Go2Py/assets/checkpoints/walk_these_ways/videos/00209.mp4 deleted file mode 100644 index db5f1a2..0000000 Binary files a/Go2Py/assets/checkpoints/walk_these_ways/videos/00209.mp4 and /dev/null differ diff --git a/Go2Py/assets/checkpoints/walk_these_ways/videos/00339.mp4 b/Go2Py/assets/checkpoints/walk_these_ways/videos/00339.mp4 deleted file mode 100644 index a5d9297..0000000 Binary files a/Go2Py/assets/checkpoints/walk_these_ways/videos/00339.mp4 and /dev/null differ diff --git a/Go2Py/assets/checkpoints/walk_these_ways/videos/00406.mp4 b/Go2Py/assets/checkpoints/walk_these_ways/videos/00406.mp4 deleted file mode 100644 index 8017d8d..0000000 Binary files a/Go2Py/assets/checkpoints/walk_these_ways/videos/00406.mp4 and /dev/null differ diff --git a/Go2Py/assets/checkpoints/walk_these_ways/videos/00551.mp4 b/Go2Py/assets/checkpoints/walk_these_ways/videos/00551.mp4 deleted file mode 100644 index 15e9055..0000000 Binary files a/Go2Py/assets/checkpoints/walk_these_ways/videos/00551.mp4 and /dev/null differ diff --git a/Go2Py/assets/checkpoints/walk_these_ways/videos/00671.mp4 b/Go2Py/assets/checkpoints/walk_these_ways/videos/00671.mp4 deleted file mode 100644 index c53aa61..0000000 Binary files a/Go2Py/assets/checkpoints/walk_these_ways/videos/00671.mp4 and /dev/null differ diff --git a/Go2Py/assets/checkpoints/walk_these_ways/videos/00732.mp4 b/Go2Py/assets/checkpoints/walk_these_ways/videos/00732.mp4 deleted file mode 100644 index 901cbeb..0000000 Binary files a/Go2Py/assets/checkpoints/walk_these_ways/videos/00732.mp4 and /dev/null differ diff --git a/Go2Py/assets/checkpoints/walk_these_ways/videos/00857.mp4 b/Go2Py/assets/checkpoints/walk_these_ways/videos/00857.mp4 deleted file mode 100644 index 9c66e43..0000000 Binary files a/Go2Py/assets/checkpoints/walk_these_ways/videos/00857.mp4 and /dev/null differ diff --git a/Go2Py/assets/checkpoints/walk_these_ways/videos/00944.mp4 b/Go2Py/assets/checkpoints/walk_these_ways/videos/00944.mp4 deleted file mode 100644 index 5e3f6f0..0000000 Binary files a/Go2Py/assets/checkpoints/walk_these_ways/videos/00944.mp4 and /dev/null differ diff --git a/Go2Py/assets/checkpoints/walk_these_ways/videos/01070.mp4 b/Go2Py/assets/checkpoints/walk_these_ways/videos/01070.mp4 deleted file mode 100644 index 1ecfbcf..0000000 Binary files a/Go2Py/assets/checkpoints/walk_these_ways/videos/01070.mp4 and /dev/null differ diff --git a/Go2Py/assets/checkpoints/walk_these_ways/videos/01153.mp4 b/Go2Py/assets/checkpoints/walk_these_ways/videos/01153.mp4 deleted file mode 100644 index 6819ecf..0000000 Binary files a/Go2Py/assets/checkpoints/walk_these_ways/videos/01153.mp4 and /dev/null differ diff --git a/Go2Py/assets/checkpoints/walk_these_ways/videos/01278.mp4 b/Go2Py/assets/checkpoints/walk_these_ways/videos/01278.mp4 deleted file mode 100644 index 371d316..0000000 Binary files a/Go2Py/assets/checkpoints/walk_these_ways/videos/01278.mp4 and /dev/null differ diff --git a/Go2Py/assets/checkpoints/walk_these_ways/videos/01333.mp4 b/Go2Py/assets/checkpoints/walk_these_ways/videos/01333.mp4 deleted file mode 100644 index b66f0bb..0000000 Binary files a/Go2Py/assets/checkpoints/walk_these_ways/videos/01333.mp4 and /dev/null differ diff --git a/Go2Py/assets/checkpoints/walk_these_ways/videos/01477.mp4 b/Go2Py/assets/checkpoints/walk_these_ways/videos/01477.mp4 deleted file mode 100644 index 56c1d8d..0000000 Binary files a/Go2Py/assets/checkpoints/walk_these_ways/videos/01477.mp4 and /dev/null differ diff --git a/Go2Py/assets/checkpoints/walk_these_ways/videos/01561.mp4 b/Go2Py/assets/checkpoints/walk_these_ways/videos/01561.mp4 deleted file mode 100644 index 6fa4398..0000000 Binary files a/Go2Py/assets/checkpoints/walk_these_ways/videos/01561.mp4 and /dev/null differ diff --git a/Go2Py/assets/checkpoints/walk_these_ways/videos/01658.mp4 b/Go2Py/assets/checkpoints/walk_these_ways/videos/01658.mp4 deleted file mode 100644 index bea0624..0000000 Binary files a/Go2Py/assets/checkpoints/walk_these_ways/videos/01658.mp4 and /dev/null differ diff --git a/Go2Py/assets/checkpoints/walk_these_ways/videos/01783.mp4 b/Go2Py/assets/checkpoints/walk_these_ways/videos/01783.mp4 deleted file mode 100644 index bceb93b..0000000 Binary files a/Go2Py/assets/checkpoints/walk_these_ways/videos/01783.mp4 and /dev/null differ diff --git a/Go2Py/assets/checkpoints/walk_these_ways/videos/01867.mp4 b/Go2Py/assets/checkpoints/walk_these_ways/videos/01867.mp4 deleted file mode 100644 index 50c83f0..0000000 Binary files a/Go2Py/assets/checkpoints/walk_these_ways/videos/01867.mp4 and /dev/null differ diff --git a/Go2Py/assets/checkpoints/walk_these_ways/videos/01950.mp4 b/Go2Py/assets/checkpoints/walk_these_ways/videos/01950.mp4 deleted file mode 100644 index 1434e8d..0000000 Binary files a/Go2Py/assets/checkpoints/walk_these_ways/videos/01950.mp4 and /dev/null differ diff --git a/Go2Py/assets/checkpoints/walk_these_ways/videos/02076.mp4 b/Go2Py/assets/checkpoints/walk_these_ways/videos/02076.mp4 deleted file mode 100644 index db9f3fd..0000000 Binary files a/Go2Py/assets/checkpoints/walk_these_ways/videos/02076.mp4 and /dev/null differ diff --git a/Go2Py/assets/checkpoints/walk_these_ways/videos/02159.mp4 b/Go2Py/assets/checkpoints/walk_these_ways/videos/02159.mp4 deleted file mode 100644 index 0a4d6c4..0000000 Binary files a/Go2Py/assets/checkpoints/walk_these_ways/videos/02159.mp4 and /dev/null differ diff --git a/Go2Py/assets/checkpoints/walk_these_ways/videos/02229.mp4 b/Go2Py/assets/checkpoints/walk_these_ways/videos/02229.mp4 deleted file mode 100644 index 5f8cbc1..0000000 Binary files a/Go2Py/assets/checkpoints/walk_these_ways/videos/02229.mp4 and /dev/null differ diff --git a/Go2Py/assets/checkpoints/walk_these_ways/videos/02354.mp4 b/Go2Py/assets/checkpoints/walk_these_ways/videos/02354.mp4 deleted file mode 100644 index 4fc2074..0000000 Binary files a/Go2Py/assets/checkpoints/walk_these_ways/videos/02354.mp4 and /dev/null differ diff --git a/Go2Py/assets/checkpoints/walk_these_ways/videos/02450.mp4 b/Go2Py/assets/checkpoints/walk_these_ways/videos/02450.mp4 deleted file mode 100644 index dd85645..0000000 Binary files a/Go2Py/assets/checkpoints/walk_these_ways/videos/02450.mp4 and /dev/null differ diff --git a/Go2Py/assets/checkpoints/walk_these_ways/videos/02575.mp4 b/Go2Py/assets/checkpoints/walk_these_ways/videos/02575.mp4 deleted file mode 100644 index 4d68823..0000000 Binary files a/Go2Py/assets/checkpoints/walk_these_ways/videos/02575.mp4 and /dev/null differ diff --git a/Go2Py/assets/checkpoints/walk_these_ways/videos/02659.mp4 b/Go2Py/assets/checkpoints/walk_these_ways/videos/02659.mp4 deleted file mode 100644 index a053c96..0000000 Binary files a/Go2Py/assets/checkpoints/walk_these_ways/videos/02659.mp4 and /dev/null differ diff --git a/Go2Py/assets/checkpoints/walk_these_ways/videos/02784.mp4 b/Go2Py/assets/checkpoints/walk_these_ways/videos/02784.mp4 deleted file mode 100644 index ac3d634..0000000 Binary files a/Go2Py/assets/checkpoints/walk_these_ways/videos/02784.mp4 and /dev/null differ diff --git a/Go2Py/assets/checkpoints/walk_these_ways/videos/02867.mp4 b/Go2Py/assets/checkpoints/walk_these_ways/videos/02867.mp4 deleted file mode 100644 index add2880..0000000 Binary files a/Go2Py/assets/checkpoints/walk_these_ways/videos/02867.mp4 and /dev/null differ diff --git a/Go2Py/assets/checkpoints/walk_these_ways/videos/02951.mp4 b/Go2Py/assets/checkpoints/walk_these_ways/videos/02951.mp4 deleted file mode 100644 index 63c323a..0000000 Binary files a/Go2Py/assets/checkpoints/walk_these_ways/videos/02951.mp4 and /dev/null differ diff --git a/Go2Py/assets/checkpoints/walk_these_ways/videos/03076.mp4 b/Go2Py/assets/checkpoints/walk_these_ways/videos/03076.mp4 deleted file mode 100644 index 67ecfcb..0000000 Binary files a/Go2Py/assets/checkpoints/walk_these_ways/videos/03076.mp4 and /dev/null differ diff --git a/Go2Py/assets/checkpoints/walk_these_ways/videos/03160.mp4 b/Go2Py/assets/checkpoints/walk_these_ways/videos/03160.mp4 deleted file mode 100644 index 0dd7277..0000000 Binary files a/Go2Py/assets/checkpoints/walk_these_ways/videos/03160.mp4 and /dev/null differ diff --git a/Go2Py/robot/model.py b/Go2Py/robot/model.py index 2385f26..a1f94ed 100644 --- a/Go2Py/robot/model.py +++ b/Go2Py/robot/model.py @@ -231,7 +231,7 @@ class Go2Model: def getGroundReactionForce(self, tau_est, body_acceleration=None): if body_acceleration is None: - grf = {key:np.linalg.pinv(self.ef_J_[key][:3,6:].T)@(tau_est.squeeze() - self.nle_[6:]) for key in self.ef_J_.keys()} + grf = {key:np.linalg.pinv(self.ef_Jw_[key][:3,6:].T)@(tau_est.squeeze() - self.nle_[6:]) for key in self.ef_Jw_.keys()} else: raise NotImplementedError("Ground reaction force with body dynamics is not implemented") return grf \ No newline at end of file diff --git a/Makefile b/Makefile index a43de35..7d4b055 100644 --- a/Makefile +++ b/Makefile @@ -1,3 +1,6 @@ +realsense: + @cd deploy/docker && docker build --tag go2py_realsense:latest -f Dockerfile.realsense . + hesai: @cd deploy && docker build --no-cache --tag go2py_hesai:latest -f docker/Dockerfile.hesai . diff --git a/deploy/docker/Dockerfile.realsense b/deploy/docker/Dockerfile.realsense new file mode 100644 index 0000000..97743a6 --- /dev/null +++ b/deploy/docker/Dockerfile.realsense @@ -0,0 +1,45 @@ +# FROM isaac_ros_dev-aarch64 +FROM ros:humble +ENV DEBIAN_FRONTEND=noninteractive +SHELL ["/bin/bash", "-c"] +# uodate and install dependencies +RUN apt-get update && apt-get install -y \ + ros-humble-rmw-cyclonedds-cpp ros-humble-rosidl-generator-dds-idl \ + # ros-humble-realsense2-camera \ + # ros-humble-pointcloud-to-laserscan \ + libyaml-cpp-dev \ + libboost-all-dev\ + build-essential \ + cmake \ + git \ + && rm -rf /var/lib/apt/lists/* + +# Cheange the ROS2 RMW to CycloneDDS as instructed by Unitree +RUN cd / && git clone https://github.com/unitreerobotics/unitree_ros2 && cd /unitree_ros2/cyclonedds_ws/src && \ +git clone https://github.com/ros2/rmw_cyclonedds -b humble && git clone https://github.com/eclipse-cyclonedds/cyclonedds -b releases/0.10.x &&\ +cd .. && colcon build --packages-select cyclonedds && source /opt/ros/humble/setup.bash && colcon build + +COPY scripts/build-librealsense.sh /opt/realsense/build-librealsense.sh +COPY scripts/install-realsense-dependencies.sh /opt/realsense/install-realsense-dependencies.sh + +RUN chmod +x /opt/realsense/install-realsense-dependencies.sh && /opt/realsense/install-realsense-dependencies.sh +RUN chmod +x /opt/realsense/build-librealsense.sh && /opt/realsense/build-librealsense.sh --no_cuda + +# Copy hotplug script which will get invoked whenever a devices plugged or un-plugged +RUN mkdir -p /opt/realsense/ +COPY scripts/hotplug-realsense.sh /opt/realsense/hotplug-realsense.sh + +# Copy custom udev rules file +COPY udev_rules/99-realsense-libusb-custom.rules /etc/udev/rules.d/99-realsense-libusb-custom.rules + + +# copy the go2py ros2 nodes +# COPY ros2_nodes/lidar_node /hesai_ws/src/lidar_node +# RUN cd /hesai_ws && source /opt/ros/humble/setup.bash && colcon build --symlink-install + +# Copy the script to start the nodes +# COPY docker/scripts /root/scripts +# COPY launch_files /root/launch +# set the entrypoint to bash +ENTRYPOINT ["/bin/bash"] +# ENTRYPOINT ["/bin/bash", "/root/scripts/hesai_start.sh"] \ No newline at end of file diff --git a/deploy/docker/scripts/build-librealsense.sh b/deploy/docker/scripts/build-librealsense.sh new file mode 100644 index 0000000..67fab42 --- /dev/null +++ b/deploy/docker/scripts/build-librealsense.sh @@ -0,0 +1,188 @@ +#!/bin/bash +# Builds the Intel Realsense library librealsense on a Jetson Nano Development Kit +# Copyright (c) 2016-21 Jetsonhacks +# MIT License + +LIBREALSENSE_DIRECTORY=${HOME}/librealsense +INSTALL_DIR=$PWD +NVCC_PATH=/usr/local/cuda/bin/nvcc + +USE_CUDA=true + +function usage () +{ + echo "Usage: ./build-librealsense.sh [-n | -no_cuda] [-v | -version ] [-j | --jobs ] [-h | --help] " + echo "-n | --no_cuda Build with no CUDA (Defaults to with CUDA)" + echo "-v | --version Version of librealsense to build + (defaults to latest release)" + echo "-j | --jobs Number of concurrent jobs (Default 1 on <= 4GB RAM + #of cores-1 otherwise)" + echo "-h | --help This message" + exit 2 +} + +PARSED_ARGUMENTS=$(getopt -a -n build-librealsense.sh -o nv:j:h --longoptions version:,no_cuda,jobs:,help -- "$@" ) +VALID_ARGUMENTS=$? + +if [ "$VALID_ARGUMENTS" != "0" ]; then + echo "" + usage +fi + +eval set -- "$PARSED_ARGUMENTS" + +LIBREALSENSE_VERSION="" +USE_CUDA=true +NUM_PROCS="" + +while : +do + case "$1" in + -n | --build_no_cuda) USE_CUDA=false ; shift ;; + -v | --version ) LIBREALSENSE_VERSION="$2" ; shift 2 ;; + -j | --jobs) NUM_PROCS="$2" ; + shift 2 ; + re_isanum='^[0-9]+$' + if ! [[ $NUM_PROCS =~ $re_isanum ]] ; then + echo "Number of jobs must be a positive, whole number" + usage + else + if [ $NUM_PROCS -eq "0" ]; then + echo "Number of jobs must be a positive, whole number" + fi + fi ; + ;; + -h | --help ) usage ; shift ;; + # -- means the end of arguments + --) shift; break ;; + esac +done + +# From lukechilds gist discussion: https://gist.github.com/lukechilds/a83e1d7127b78fef38c2914c4ececc3c +# We use wget instead of curl here +# Sample usage: +# VERSION_STRINGS=$(get_latest_release IntelRealSense/librealsense) + +function get_latest_release () { + # redirect wget to standard out and grep out the tag_name + wget -qO- https://api.github.com/repos/$1/releases/latest | + grep -Po '"tag_name": "\K.*?(?=")' +} + +if [[ $LIBREALSENSE_VERSION == "" ]] ; then + echo "Getting latest librealsense version number" + LIBREALSENSE_VERSION=$(get_latest_release IntelRealSense/librealsense) +fi + +echo "Build with CUDA: "$USE_CUDA +echo "Librealsense Version: $LIBREALSENSE_VERSION" + +red=`tput setaf 1` +green=`tput setaf 2` +reset=`tput sgr0` +# e.g. echo "${red}The red tail hawk ${green}loves the green grass${reset}" + +if [ ! -d "$LIBREALSENSE_DIRECTORY" ] ; then + # clone librealsense + cd ${HOME} + echo "${green}Cloning librealsense${reset}" + git clone https://github.com/IntelRealSense/librealsense.git +fi + +# Is the version of librealsense current enough? +cd $LIBREALSENSE_DIRECTORY +VERSION_TAG=$(git tag -l $LIBREALSENSE_VERSION) +if [ ! $VERSION_TAG ] ; then + echo "" + tput setaf 1 + echo "==== librealsense Version Mismatch! =============" + tput sgr0 + echo "" + echo "The installed version of librealsense is not current enough for these scripts." + echo "This script needs librealsense tag version: "$LIBREALSENSE_VERSION "but it is not available." + echo "Please upgrade librealsense or remove the librealsense folder before attempting to install again." + echo "" + exit 1 +fi + +# Checkout version the last tested version of librealsense +git checkout $LIBREALSENSE_VERSION + +# Install the dependencies +cd $INSTALL_DIR + +cd $LIBREALSENSE_DIRECTORY +git checkout $LIBREALSENSE_VERSION + +# Now compile librealsense and install +mkdir build +cd build +# Build examples, including graphical ones +echo "${green}Configuring Make system${reset}" +# Build with CUDA (default), the CUDA flag is USE_CUDA, ie -DUSE_CUDA=true +export CUDACXX=$NVCC_PATH +export PATH=${PATH}:/usr/local/cuda/bin +export LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:/usr/local/cuda/lib64 + +/usr/bin/cmake ../ -DBUILD_EXAMPLES=true -DFORCE_RSUSB_BACKEND=true -DBUILD_WITH_CUDA="$USE_CUDA" -DCMAKE_BUILD_TYPE=release -DBUILD_PYTHON_BINDINGS=bool:true + +# The library will be installed in /usr/local/lib, header files in /usr/local/include +# The demos, tutorials and tests will located in /usr/local/bin. +echo "${green}Building librealsense, headers, tools and demos${reset}" + +# If user didn't set # of jobs and we have > 4GB memory then +# set # of jobs to # of cores-1, otherwise 1 +if [[ $NUM_PROCS == "" ]] ; then + TOTAL_MEMORY=$(free | awk '/Mem\:/ { print $2 }') + if [ $TOTAL_MEMORY -gt 4051048 ] ; then + NUM_CPU=$(nproc) + NUM_PROCS=$(($NUM_CPU - 1)) + else + NUM_PROCS=1 + fi +fi + +time make -j$NUM_PROCS +if [ $? -eq 0 ] ; then + echo "librealsense make successful" +else + # Try to make again; Sometimes there are issues with the build + # because of lack of resources or concurrency issues + echo "librealsense did not build " >&2 + echo "Retrying ... " + # Single thread this time + time make + if [ $? -eq 0 ] ; then + echo "librealsense make successful" + else + # Try to make again + echo "librealsense did not successfully build" >&2 + echo "Please fix issues and retry build" + exit 1 + fi +fi +echo "${green}Installing librealsense, headers, tools and demos${reset}" +sudo make install + +if grep -Fxq 'export PYTHONPATH=$PYTHONPATH:/usr/local/lib' ~/.bashrc ; then + echo "PYTHONPATH already exists in .bashrc file" +else + echo 'export PYTHONPATH=$PYTHONPATH:/usr/local/lib' >> ~/.bashrc + echo "PYTHONPATH added to ~/.bashrc. Pyhon wrapper is now available for importing pyrealsense2" +fi + +cd $LIBREALSENSE_DIRECTORY +echo "${green}Applying udev rules${reset}" +# Copy over the udev rules so that camera can be run from user space +sudo cp config/99-realsense-libusb.rules /etc/udev/rules.d/ +sudo udevadm control --reload-rules && udevadm trigger + +echo "${green}Library Installed${reset}" +echo " " +echo " -----------------------------------------" +echo "The library is installed in /usr/local/lib" +echo "The header files are in /usr/local/include" +echo "The demos and tools are located in /usr/local/bin" +echo " " +echo " -----------------------------------------" +echo " " diff --git a/deploy/docker/scripts/hotplug-realsense.sh b/deploy/docker/scripts/hotplug-realsense.sh new file mode 100755 index 0000000..7d515e5 --- /dev/null +++ b/deploy/docker/scripts/hotplug-realsense.sh @@ -0,0 +1,79 @@ +#!/usr/bin/env bash + +# Copyright (c) 2022, NVIDIA CORPORATION. All rights reserved. +# +# NVIDIA CORPORATION and its licensors retain all intellectual property +# and proprietary rights in and to this software, related documentation +# and any modifications thereto. Any use, reproduction, disclosure or +# distribution of this software and related documentation without an express +# license agreement from NVIDIA CORPORATION is strictly prohibited. + + +# This script is triggered when a corresponding udev rule is matched with action +function usage() { + echo "Usage: hotplug-realsense.sh -a -d [options]" + echo "-a | --action Action determines whether the device has been added or removed. Valid values are 'add' or 'remove'." + echo "-d | --dev-path Device path that will be used to mount the device." + echo "-M | --major-version The kernel major number for the device. This will be used when action=add." + echo "-m | --minor-version The kernel minor number for the device. This will be used when action=add." + echo "-p | --parent-path Parent node path of the device pointed by the -d flag." + echo "-h | --help Display this message." +} + +function check_mandatory_param() { +VAR=$1 +MSG=$2 +if [[ -z ${VAR} ]] ; then + echo "${MSG}" + usage + exit 1 +fi +} + +function timestamp() { + echo [$EPOCHREALTIME] [$(date)] +} + +ARGUMENTS=$(getopt -n hotplug-realsense.sh -o a:d:M:m:p:h -l action:,dev-path:,major-version:,minor-version:,parent-path:,help -- "$@" ) + +if [[ $? -ne 0 ]]; then + usage +fi + +eval set -- "$ARGUMENTS" + +while [ : ]; do + case "$1" in + -a | --action) + ACTION=$2 ; shift 2 ;; + -d | --dev-path) + DEV_PATH=$2 ; shift 2 ;; + -M | --major-version) + MAJOR_VERSION=$2 ; shift 2 ;; + -m | --minor-version) + MINOR_VERSION=$2 ; shift 2 ;; + -p | --parent-path) + PARENT_PATH=/dev/$2 ; shift 2 ;; + -h | --help) + usage ; shift ;; + --) shift; break ;; + esac +done + +check_mandatory_param ${ACTION:-""} "Please provide valid value for action" +check_mandatory_param ${DEV_PATH:-""} "Please provide valid value for device path" + +if [[ "${ACTION}" == "add" ]]; then + check_mandatory_param ${MAJOR_VERSION:-""} "Please provide valid value for major number" + check_mandatory_param ${MINOR_VERSION:-""} "Please provide valid value for minor number" + sudo mknod -m a=rw ${DEV_PATH} c ${MAJOR_VERSION} ${MINOR_VERSION} + sudo chown root:plugdev ${DEV_PATH} + echo $(timestamp) "Added ${DEV_PATH} with major version: ${MAJOR_VERSION} and minor version: ${MINOR_VERSION} to docker" >> /tmp/docker_usb.log +elif [[ "$ACTION" == "remove" ]]; then + sudo rm ${DEV_PATH} ${PARENT_PATH} + echo $(timestamp) "Removed ${DEV_PATH} ${PARENT_PATH} from docker" >> /tmp/docker_usb.log +else + echo "Cannot recognize action=${ACTION}" + usage + exit 1 +fi diff --git a/deploy/docker/scripts/install-realsense-dependencies.sh b/deploy/docker/scripts/install-realsense-dependencies.sh new file mode 100644 index 0000000..db81a0c --- /dev/null +++ b/deploy/docker/scripts/install-realsense-dependencies.sh @@ -0,0 +1,24 @@ +#!/bin/bash +# install-realsense-dependencies.sh +# Install dependencies for the Intel Realsense library librealsense2 on a Jetson Nano Developer Kit +# Copyright (c) 2016-19 Jetsonhacks +# MIT License + +red=`tput setaf 1` +green=`tput setaf 2` +reset=`tput sgr0` +# e.g. echo "${red}red text ${green}green text${reset}" +echo "${green}Adding Universe repository and updating${reset}" +apt-add-repository universe +apt-get update +echo "${green}Adding dependencies, graphics libraries and tools${reset}" +apt-get install libssl-dev libusb-1.0-0-dev pkg-config -y + +# Graphics libraries - for SDK's OpenGL-enabled examples +apt-get install libgtk-3-dev libglfw3-dev libgl1-mesa-dev libglu1-mesa-dev -y + +# QtCreator for development; not required for librealsense core library +apt-get install qtcreator -y + +# Add Python 3 support +apt-get install -y python3 python3-dev diff --git a/deploy/docker/udev_rules/99-realsense-libusb-custom.rules b/deploy/docker/udev_rules/99-realsense-libusb-custom.rules new file mode 100644 index 0000000..9279e0d --- /dev/null +++ b/deploy/docker/udev_rules/99-realsense-libusb-custom.rules @@ -0,0 +1,11 @@ +##Version=0.1## +# Device rules for Intel RealSense devices (D435 D435i D455) +# For D435 +ACTION=="add" SUBSYSTEMS=="usb", ATTRS{idVendor}=="8086", ATTRS{idProduct}=="0b07", MODE:="0666", GROUP:="plugdev", RUN+="/opt/realsense/hotplug-realsense.sh -a add -d '%N' -M '%M' -m '%m'" +ACTION=="remove" SUBSYSTEMS=="usb", ATTRS{idVendor}=="8086", ATTRS{idProduct}=="0b07", MODE:="0666", GROUP:="plugdev", RUN+="/opt/realsense/hotplug-realsense.sh -a remove -d '%N' -p '%P'" +# For D435i +ACTION=="add" SUBSYSTEMS=="usb", ATTRS{idVendor}=="8086", ATTRS{idProduct}=="0b3a", MODE:="0666", GROUP:="plugdev", RUN+="/opt/realsense/hotplug-realsense.sh -a add -d '%N' -M '%M' -m '%m'" +ACTION=="remove" SUBSYSTEMS=="usb", ATTRS{idVendor}=="8086", ATTRS{idProduct}=="0b3a", MODE:="0666", GROUP:="plugdev", RUN+="/opt/realsense/hotplug-realsense.sh -a remove -d '%N' -p '%P'" +# For D455 +ACTION=="add" SUBSYSTEMS=="usb", ATTRS{idVendor}=="8086", ATTRS{idProduct}=="0b5c", MODE:="0666", GROUP:="plugdev", RUN+="/opt/realsense/hotplug-realsense.sh -a add -d '%N' -M '%M' -m '%m'" +ACTION=="remove" SUBSYSTEMS=="usb", ATTRS{idVendor}=="8086", ATTRS{idProduct}=="0b5c", MODE:="0666", GROUP:="plugdev", RUN+="/opt/realsense/hotplug-realsense.sh -a remove -d '%N' -p '%P'" diff --git a/docker/scripts/install-zed-aarch64.sh b/docker/scripts/install-zed-aarch64.sh new file mode 100644 index 0000000..6b3d5f6 --- /dev/null +++ b/docker/scripts/install-zed-aarch64.sh @@ -0,0 +1,20 @@ +# Based on https://github.com/stereolabs/zed-docker + +# Download dependencies for zed SDK installation RUN file +sudo apt-get update -y || true +sudo apt-get install --no-install-recommends lsb-release wget less zstd udev sudo apt-transport-https -y + +# Download zed SDK installation RUN file to /tmp directory +cd /tmp + +wget -q --no-check-certificate -O ZED_SDK_Linux.run https://stereolabs.sfo2.digitaloceanspaces.com/zedsdk/QA/JP5.1.2/ZED_SDK_Tegra_L4T35.4_v4.0.6.zstd.run +chmod +x ZED_SDK_Linux.run ; ./ZED_SDK_Linux.run silent skip_od_module skip_python skip_drivers + +# Symlink required to use the streaming features on Jetson inside a container, based on +# https://github.com/stereolabs/zed-docker/blob/fd514606174d8bb09f21a229f1099205b284ecb6/4.X/l4t/devel/Dockerfile#L27C5-L27C95 +sudo ln -sf /usr/lib/aarch64-linux-gnu/tegra/libv4l2.so.0 /usr/lib/aarch64-linux-gnu/libv4l2.so + +# Cleanup +sudo rm -rf /usr/local/zed/resources/* +rm -rf ZED_SDK_Linux.run +sudo rm -rf /var/lib/apt/lists/* \ No newline at end of file diff --git a/docker/scripts/install-zed-x86_64.sh b/docker/scripts/install-zed-x86_64.sh new file mode 100644 index 0000000..198aa79 --- /dev/null +++ b/docker/scripts/install-zed-x86_64.sh @@ -0,0 +1,28 @@ +# Based on https://github.com/stereolabs/zed-docker + +# Extract ubuntu release year from /etc/lsb-release +# Expects "/etc/lsb-release" to contain a line similar to "DISTRIB_RELEASE=20.04" +export UBUNTU_RELEASE_YEAR="$(grep -o -P 'DISTRIB_RELEASE=.{0,2}' /etc/lsb-release | cut -d= -f2)" + +# Extract cuda major and minor version from nvcc --version +# Expects "nvcc --version" to contain a line similar to "release 11.8" +export CUDA_MAJOR="$(nvcc --version | grep -o -P ' release .{0,4}' | cut -d. -f1 | cut -d ' ' -f3)" +export CUDA_MINOR="$(nvcc --version | grep -o -P ' release .{0,4}' | cut -d. -f2)" + + +# Download dependencies for zed SDK installation RUN file +sudo apt-get update -y || true +sudo apt-get install --no-install-recommends lsb-release wget less udev sudo zstd build-essential cmake libpng-dev libgomp1 -y + +# Download zed SDK installation RUN file to /tmp directory +cd /tmp +wget -q -O ZED_SDK_Linux_Ubuntu${UBUNTU_RELEASE_YEAR}.run https://download.stereolabs.com/zedsdk/${ZED_SDK_MAJOR}.${ZED_SDK_MINOR}/cu${CUDA_MAJOR}${CUDA_MINOR%.*}/ubuntu${UBUNTU_RELEASE_YEAR} +chmod +x ZED_SDK_Linux_Ubuntu${UBUNTU_RELEASE_YEAR}.run ; ./ZED_SDK_Linux_Ubuntu${UBUNTU_RELEASE_YEAR}.run -- silent skip_od_module skip_python skip_cuda + +# Symlink required for zed SDK, based on +# https://github.com/stereolabs/zed-docker/blob/fd514606174d8bb09f21a229f1099205b284ecb6/4.X/ubuntu/devel/Dockerfile#L24 +sudo ln -sf /lib/x86_64-linux-gnu/libusb-1.0.so.0 /usr/lib/x86_64-linux-gnu/libusb-1.0.so + +# Cleanup +rm ZED_SDK_Linux_Ubuntu${UBUNTU_RELEASE_YEAR}.run +sudo rm -rf /var/lib/apt/lists/* \ No newline at end of file diff --git a/docker/scripts/workspace-entrypoint.sh b/docker/scripts/workspace-entrypoint.sh index e89cd70..466cd88 100755 --- a/docker/scripts/workspace-entrypoint.sh +++ b/docker/scripts/workspace-entrypoint.sh @@ -12,11 +12,10 @@ echo "source /opt/ros/${ROS_DISTRO}/setup.bash" >> ~/.bashrc source /opt/ros/${ROS_DISTRO}/setup.bash -# sudo apt-get update -# rosdep update +sudo apt-get update +rosdep update # Restart udev daemon sudo service udev restart -export RMW_IMPLEMENTATION=rmw_cyclonedds_cpp $@ diff --git a/examples/lowlevel_dds_interface.ipynb b/examples/00-robot-interface-dds.ipynb similarity index 79% rename from examples/lowlevel_dds_interface.ipynb rename to examples/00-robot-interface-dds.ipynb index 18b8c76..2c66643 100644 --- a/examples/lowlevel_dds_interface.ipynb +++ b/examples/00-robot-interface-dds.ipynb @@ -1,5 +1,12 @@ { "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Lowlevel Control" + ] + }, { "cell_type": "code", "execution_count": 1, @@ -24,9 +31,30 @@ "cell_type": "code", "execution_count": 3, "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "text/plain": [ + "{'q': array([-0.04851204, 1.25695562, -2.80253339, 0.05441612, 1.24787235,\n", + " -2.78187132, -0.34375334, 1.27221012, -2.80291271, 0.32734287,\n", + " 1.27893162, -2.81329131]),\n", + " 'dq': array([ 0.03875524, 0.0155021 , 0.0323522 , 0.07363495, 0.02712867,\n", + " -0.0161761 , 0.01937762, 0.03487971, 0.00808805, -0.03487971,\n", + " 0. , 0.02628616]),\n", + " 'ddq': array([0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.]),\n", + " 'tau_est': array([-0.04947656, 0.04947656, -0.04741504, -0.04947656, -0.04947656,\n", + " 0. , 0. , 0.04947656, -0.04741504, 0.04947656,\n", + " -0.07421485, 0.04741504]),\n", + " 'temperature': array([34., 30., 29., 32., 30., 30., 36., 31., 29., 37., 31., 30.])}" + ] + }, + "execution_count": 3, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ - "q = robot.getJointStates()['q']" + "robot.getJointStates()" ] }, { @@ -40,59 +68,26 @@ "for i in range(1000000):\n", " # q = np.zeros(12) \n", " dq = np.zeros(12)\n", - " kp = np.ones(12)*20\n", - " kd = np.ones(12)*0.3\n", + " kp = np.ones(12)*0.0\n", + " kd = np.ones(12)*0.0\n", " tau = np.zeros(12)\n", - " tau[0] = -0.0\n", + " tau[0] = 0.0\n", " robot.setCommands(q, dq, kp, kd, tau)\n", " time.sleep(0.01) " ] }, { - "cell_type": "code", - "execution_count": null, + "cell_type": "markdown", "metadata": {}, - "outputs": [], "source": [ - "import time\n", - "dataset = []\n", - "for i in range(10000):\n", - " sample = robot.getJointStates()\n", - " dataset.append(sample['q'])\n", - " time.sleep(0.01)" + "# Highlevel Control" ] }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "from scipy.spatial.transform import Rotation" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "Rotation.from_matrix(np.eye(3)).as_quat()" - ] - }, - { - "cell_type": "code", - "execution_count": 1, + "execution_count": 4, "metadata": {}, "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "pygame 2.5.2 (SDL 2.28.2, Python 3.8.18)\n", - "Hello from the pygame community. https://www.pygame.org/contribute.html\n" - ] - }, { "ename": "NotImplementedError", "evalue": "DDS interface for the highlevel commands is not implemented yet. Please use our ROS2 interface.", @@ -100,7 +95,7 @@ "traceback": [ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[0;31mNotImplementedError\u001b[0m Traceback (most recent call last)", - "Cell \u001b[0;32mIn[1], line 3\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[38;5;28;01mfrom\u001b[39;00m \u001b[38;5;21;01mGo2Py\u001b[39;00m\u001b[38;5;21;01m.\u001b[39;00m\u001b[38;5;21;01mrobot\u001b[39;00m\u001b[38;5;21;01m.\u001b[39;00m\u001b[38;5;21;01minterface\u001b[39;00m\u001b[38;5;21;01m.\u001b[39;00m\u001b[38;5;21;01mdds\u001b[39;00m \u001b[38;5;28;01mimport\u001b[39;00m GO2Real\n\u001b[1;32m 2\u001b[0m \u001b[38;5;28;01mimport\u001b[39;00m \u001b[38;5;21;01mtime\u001b[39;00m\n\u001b[0;32m----> 3\u001b[0m robot \u001b[38;5;241m=\u001b[39m \u001b[43mGO2Real\u001b[49m\u001b[43m(\u001b[49m\u001b[43mmode\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[38;5;124;43mhighlevel\u001b[39;49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[43m)\u001b[49m\n", + "Cell \u001b[0;32mIn[4], line 3\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[38;5;28;01mfrom\u001b[39;00m \u001b[38;5;21;01mGo2Py\u001b[39;00m\u001b[38;5;21;01m.\u001b[39;00m\u001b[38;5;21;01mrobot\u001b[39;00m\u001b[38;5;21;01m.\u001b[39;00m\u001b[38;5;21;01minterface\u001b[39;00m\u001b[38;5;21;01m.\u001b[39;00m\u001b[38;5;21;01mdds\u001b[39;00m \u001b[38;5;28;01mimport\u001b[39;00m GO2Real\n\u001b[1;32m 2\u001b[0m \u001b[38;5;28;01mimport\u001b[39;00m \u001b[38;5;21;01mtime\u001b[39;00m\n\u001b[0;32m----> 3\u001b[0m robot \u001b[38;5;241m=\u001b[39m \u001b[43mGO2Real\u001b[49m\u001b[43m(\u001b[49m\u001b[43mmode\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[38;5;124;43mhighlevel\u001b[39;49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[43m)\u001b[49m\n", "File \u001b[0;32m~/projects/rooholla/locomotion/Go2Py/Go2Py/robot/interface/dds.py:35\u001b[0m, in \u001b[0;36mGO2Real.__init__\u001b[0;34m(self, mode, vx_max, vy_max, ωz_max)\u001b[0m\n\u001b[1;32m 33\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mmode \u001b[38;5;241m=\u001b[39m mode\n\u001b[1;32m 34\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mmode \u001b[38;5;241m==\u001b[39m \u001b[38;5;124m'\u001b[39m\u001b[38;5;124mhighlevel\u001b[39m\u001b[38;5;124m'\u001b[39m:\n\u001b[0;32m---> 35\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mNotImplementedError\u001b[39;00m(\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mDDS interface for the highlevel commands is not implemented yet. Please use our ROS2 interface.\u001b[39m\u001b[38;5;124m'\u001b[39m)\n\u001b[1;32m 36\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39msimulated \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;01mFalse\u001b[39;00m\n\u001b[1;32m 37\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mprestanding_q \u001b[38;5;241m=\u001b[39m np\u001b[38;5;241m.\u001b[39marray([ \u001b[38;5;241m0.0\u001b[39m, \u001b[38;5;241m1.26186061\u001b[39m, \u001b[38;5;241m-\u001b[39m\u001b[38;5;241m2.5\u001b[39m,\n\u001b[1;32m 38\u001b[0m \u001b[38;5;241m0.0\u001b[39m, \u001b[38;5;241m1.25883281\u001b[39m, \u001b[38;5;241m-\u001b[39m\u001b[38;5;241m2.5\u001b[39m,\n\u001b[1;32m 39\u001b[0m \u001b[38;5;241m0.0\u001b[39m, \u001b[38;5;241m1.27193761\u001b[39m, \u001b[38;5;241m-\u001b[39m\u001b[38;5;241m2.6\u001b[39m, \n\u001b[1;32m 40\u001b[0m \u001b[38;5;241m0.0\u001b[39m, \u001b[38;5;241m1.27148342\u001b[39m, \u001b[38;5;241m-\u001b[39m\u001b[38;5;241m2.6\u001b[39m])\n", "\u001b[0;31mNotImplementedError\u001b[0m: DDS interface for the highlevel commands is not implemented yet. Please use our ROS2 interface." ] @@ -111,13 +106,6 @@ "import time\n", "robot = GO2Real(mode='highlevel')" ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] } ], "metadata": { diff --git a/examples/lowlevel_ros2_interface.ipynb b/examples/01-robot-interface-ros2.ipynb similarity index 93% rename from examples/lowlevel_ros2_interface.ipynb rename to examples/01-robot-interface-ros2.ipynb index 65f4566..423e064 100644 --- a/examples/lowlevel_ros2_interface.ipynb +++ b/examples/01-robot-interface-ros2.ipynb @@ -4,7 +4,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "# Lowlevel Interface Test" + "# Lowlevel Control" ] }, { @@ -16,7 +16,7 @@ "from Go2Py.robot.interface.ros2 import GO2Real, ros2_init, ROS2ExecutorManager\n", "import time\n", "ros2_init()\n", - "robot = GO2Real(mode='highlevel')\n", + "robot = GO2Real(mode='lowlevel')\n", "ros2_exec_manager = ROS2ExecutorManager()\n", "ros2_exec_manager.add_node(robot)\n", "ros2_exec_manager.start()" @@ -104,7 +104,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "# Highlevel Interface Test" + "# Highlevel Control" ] }, { @@ -130,13 +130,6 @@ "source": [ "robot.getJointStates()" ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] } ], "metadata": { diff --git a/examples/fsm_sim.ipynb b/examples/02-mujoco-sim.ipynb similarity index 65% rename from examples/fsm_sim.ipynb rename to examples/02-mujoco-sim.ipynb index de27767..c0bea9b 100644 --- a/examples/fsm_sim.ipynb +++ b/examples/02-mujoco-sim.ipynb @@ -2,45 +2,47 @@ "cells": [ { "cell_type": "code", - "execution_count": 1, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ "from Go2Py.sim.mujoco import Go2Sim\n", - "from Go2Py.robot.fsm import FSM\n", - "from Go2Py.robot.remote import KeyboardRemote\n", - "from Go2Py.robot.safety import SafetyHypervisor\n", "import numpy as np" ] }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [], - "source": [ - "robot = Go2Sim()\n", - "remote = KeyboardRemote()\n", - "safety_hypervisor = SafetyHypervisor(robot)" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [], - "source": [ - "robot.sitDownReset()\n", - "fsm = FSM(robot, remote, safety_hypervisor)" - ] - }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ - "fsm.close()" + "robot = Go2Sim()\n", + "robot.standUpReset()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "robot.getJointStates()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import mujoco\n", + "import time\n", + "robot.standUpReset()\n", + "for i in range(100000):\n", + " state = robot.getJointStates()\n", + " tau = 20*np.eye(12)@(robot.q0 - state['q']).reshape(12,1)\n", + " robot.setCommands(np.zeros(12), np.zeros(12), np.zeros(12), np.zeros(12), tau)\n", + " robot.step()" ] } ], diff --git a/examples/03-robot-dynamic-model.ipynb b/examples/03-robot-dynamic-model.ipynb new file mode 100644 index 0000000..be6095e --- /dev/null +++ b/examples/03-robot-dynamic-model.ipynb @@ -0,0 +1,86 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Simulated" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "from Go2Py.sim.mujoco import Go2Sim\n", + "from Go2Py.robot.model import Go2Model\n", + "from Go2Py.estimation.contact import HysteresisContactDetector\n", + "import pinocchio as pin \n", + "import numpy as np\n", + "import time" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [], + "source": [ + "model = Go2Model()\n", + "robot = Go2Sim()" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "dict_keys(['M', 'Minv', 'nle', 'g', 'J_w', 'J_b'])\n" + ] + } + ], + "source": [ + "# Get robot robot states\n", + "state = robot.getJointStates()\n", + "\n", + "# The pose and velocity generally is fed from an external state estimator,\n", + "# here we just set it to identity\n", + "T = np.eye(4)\n", + "vel = np.zeros(6)\n", + "\n", + "# Compute the dynamics\n", + "model.updateAllPose(state['q'], state['dq'], T, vel)\n", + "\n", + "# Get dynamic and kinematic models\n", + "info = model.getInfo()\n", + "print(info.keys())" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.8.18" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/examples/mujoco_test.ipynb b/examples/04-lowlevel-control-fsm.ipynb similarity index 55% rename from examples/mujoco_test.ipynb rename to examples/04-lowlevel-control-fsm.ipynb index fc1bffa..6ab4d4d 100644 --- a/examples/mujoco_test.ipynb +++ b/examples/04-lowlevel-control-fsm.ipynb @@ -1,5 +1,12 @@ { "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Test in Simulation" + ] + }, { "cell_type": "code", "execution_count": null, @@ -7,7 +14,9 @@ "outputs": [], "source": [ "from Go2Py.sim.mujoco import Go2Sim\n", - "import numpy as np" + "from Go2Py.robot.fsm import FSM\n", + "from Go2Py.robot.remote import KeyboardRemote\n", + "from Go2Py.robot.safety import SafetyHypervisor" ] }, { @@ -17,7 +26,8 @@ "outputs": [], "source": [ "robot = Go2Sim()\n", - "robot.standUpReset()" + "remote = KeyboardRemote()\n", + "safety_hypervisor = SafetyHypervisor(robot)" ] }, { @@ -26,15 +36,37 @@ "metadata": {}, "outputs": [], "source": [ - "import mujoco\n", + "robot.sitDownReset()\n", + "fsm = FSM(robot, remote, safety_hypervisor)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "fsm.close()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Test on Real Robot" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from Go2Py.robot.interface.dds import GO2Real\n", "import time\n", - "q,dq = robot.getJointStates()\n", - "robot.standUpReset()\n", - "for i in range(100000):\n", - " state = robot.getJointStates()\n", - " tau = 20*np.eye(12)@(robot.q0 - state['q']).reshape(12,1)\n", - " robot.setCommands(np.zeros(12), np.zeros(12), np.zeros(12), np.zeros(12), tau)\n", - " robot.step()" + "from Go2Py.robot.fsm import FSM\n", + "from Go2Py.robot.remote import KeyboardRemote\n", + "from Go2Py.robot.safety import SafetyHypervisor" ] }, { @@ -43,8 +75,9 @@ "metadata": {}, "outputs": [], "source": [ - "n = robot.model.nv\n", - "full_M = np.zeros((n, n))" + "robot = GO2Real(mode='lowlevel')\n", + "remote = KeyboardRemote()\n", + "safety_hypervisor = SafetyHypervisor(robot)" ] }, { @@ -53,11 +86,7 @@ "metadata": {}, "outputs": [], "source": [ - "import mujoco\n", - "nv = robot.model.nv\n", - "M = np.zeros((nv, nv))\n", - "mujoco.mj_fullM(robot.model, M, robot.data.qM)\n", - "nle = robot.data.qfrc_bias.reshape(nv,1)" + "fsm = FSM(robot, remote, safety)" ] }, { @@ -66,21 +95,7 @@ "metadata": {}, "outputs": [], "source": [ - "id = mujoco.mj_name2id(robot.model, mujoco.mjtObj.mjOBJ_SITE,'FR_foot')\n", - "nv = robot.model.nv\n", - "jacp = np.zeros((3, nv))\n", - "jacr = np.zeros((3, nv))\n", - "mujoco.mj_jacSite(robot.model, robot.data, jacp, jacr, id)\n", - "jacp" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "robot.getSiteJacobian('FR_foot')" + "fsm.close()" ] } ], @@ -100,7 +115,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.9.18" + "version": "3.8.18" } }, "nbformat": 4, diff --git a/examples/walk_these_ways_real.ipynb b/examples/05-walk-these-ways-RL-controller.ipynb similarity index 64% rename from examples/walk_these_ways_real.ipynb rename to examples/05-walk-these-ways-RL-controller.ipynb index 3c5b3b2..01ad28f 100644 --- a/examples/walk_these_ways_real.ipynb +++ b/examples/05-walk-these-ways-RL-controller.ipynb @@ -2,31 +2,7 @@ "cells": [ { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "from Go2Py.robot.interface.dds import GO2Real\n", - "import numpy as np\n", - "robot = GO2Real(mode='lowlevel')" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "from Go2Py.robot.fsm import FSM\n", - "from Go2Py.robot.remote import KeyboardRemote\n", - "from Go2Py.robot.safety import SafetyHypervisor\n", - "from Go2Py.control.walk_these_ways import *\n", - "import numpy as np" - ] - }, - { - "cell_type": "code", - "execution_count": null, + "execution_count": 1, "metadata": {}, "outputs": [], "source": [ @@ -60,7 +36,7 @@ " omega = -robot.getRemoteState().rx*2.2\n", " self.command_profile.x_vel_cmd = vx*1.5\n", " self.command_profile.y_vel_cmd = vy*1.5\n", - " self.command_profile.yaw_vel_cmd = omega\n" + " self.command_profile.yaw_vel_cmd = omega" ] }, { @@ -110,6 +86,113 @@ " " ] }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Test In Simulation" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from Go2Py.robot.fsm import FSM\n", + "from Go2Py.robot.remote import KeyboardRemote\n", + "from Go2Py.robot.safety import SafetyHypervisor\n", + "from Go2Py.sim.mujoco import Go2Sim\n", + "from Go2Py.control.walk_these_ways import *" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "robot = Go2Sim()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "remote = KeyboardRemote()\n", + "robot.standUpReset()\n", + "safety_hypervisor = SafetyHypervisor(robot)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "controller.command_profile.pitch_cmd=0.0\n", + "controller.command_profile.body_height_cmd=0.0\n", + "controller.command_profile.footswing_height_cmd=0.08\n", + "controller.command_profile.roll_cmd=0.0\n", + "controller.command_profile.stance_width_cmd=0.2\n", + "controller.command_profile.x_vel_cmd=-0.2\n", + "controller.command_profile.y_vel_cmd=0.01\n", + "controller.command_profile.setGaitType(\"trotting\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "checkpoint = \"../Go2Py/assets/checkpoints/walk_these_ways/\"\n", + "controller = walkTheseWaysController(robot, remote, checkpoint)\n", + "fsm = FSM(robot, remote, safety_hypervisor, user_controller_callback=controller.update)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "fsm.close()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Test on Real Robot" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from Go2Py.robot.fsm import FSM\n", + "from Go2Py.robot.remote import KeyboardRemote\n", + "from Go2Py.robot.safety import SafetyHypervisor\n", + "from Go2Py.sim.mujoco import Go2Sim\n", + "from Go2Py.control.walk_these_ways import *" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from Go2Py.robot.interface.dds import GO2Real\n", + "import numpy as np\n", + "robot = GO2Real(mode='lowlevel')" + ] + }, { "cell_type": "code", "execution_count": null, @@ -126,13 +209,9 @@ "metadata": {}, "outputs": [], "source": [ - "checkpoint = \"/home/rstaion/projects/rooholla/locomotion/Go2Py/Go2Py/assets/checkpoints/walk_these_ways/\"\n", - "# checkpoint = \"/home/rstaion/projects/rooholla/walk-these-ways/runs/gait-conditioned-agility/pretrain-v0/train/025417.456545\"\n", - "\n", + "checkpoint = \"../Go2Py/assets/checkpoints/walk_these_ways/\"\n", "controller = walkTheseWaysController(robot, remote, checkpoint)\n", - "fsm = FSM(robot, remote, safety_hypervisor, user_controller_callback=controller.update)\n", - "safety_hypervisor = SafetyHypervisor(robot)\n", - "fsm.control_dT = 1./56." + "safety_hypervisor = SafetyHypervisor(robot)" ] }, { @@ -140,7 +219,18 @@ "execution_count": null, "metadata": {}, "outputs": [], - "source": [] + "source": [ + "fsm = FSM(robot, remote, safety_hypervisor, user_controller_callback=controller.update)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "fsm.close()" + ] } ], "metadata": { diff --git a/examples/actuator_net.ipynb b/examples/actuator_net.ipynb deleted file mode 100644 index a196cec..0000000 --- a/examples/actuator_net.ipynb +++ /dev/null @@ -1,160 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "execution_count": 4, - "metadata": {}, - "outputs": [], - "source": [ - "from Go2Py.robot.fsm import FSM\n", - "from Go2Py.robot.model import Go2Model\n", - "from Go2Py.sim.mujoco import Go2Sim\n", - "import numpy as np" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [], - "source": [ - "robot = Go2Sim()" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "[0.3868 0. 0. ]\n", - "0.3868\n", - "0.093\n", - "0.09550000000000002\n", - "0.213\n", - "0.213\n" - ] - } - ], - "source": [ - "model = Go2Model()" - ] - }, - { - "cell_type": "code", - "execution_count": 26, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "The task space position of the robot feet are:\n", - "{'base_link': array([0. , 0. , 0.34]), 'FR_foot': array([ 0.19400515, -0.142 , 0.0372495 ]), 'FL_foot': array([0.19811581, 0.142 , 0.03813916]), 'RR_foot': array([-0.19303592, -0.142 , 0.03357947]), 'RL_foot': array([-0.1897387, 0.142 , 0.0330523])}\n" - ] - } - ], - "source": [ - "T0 = np.eye(4) \n", - "T0[2,-1]=0.34\n", - "q0 = robot.standing_q\n", - "x0 = model.forwardKinematics(T0, q0)\n", - "x0 = {key:x[0:3,-1] for key,x in zip(x0.keys(),x0.values())}\n", - "print('The task space position of the robot feet are:')\n", - "print(x0)\n", - "x0 = np.hstack([x0[key] for key in ['FR_foot', 'FL_foot', 'RR_foot', 'RL_foot']])\n" - ] - }, - { - "cell_type": "code", - "execution_count": 28, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "array([ 0.00000000e+00, -2.22044605e-16, 2.22044605e-16, 0.00000000e+00,\n", - " 2.22044605e-16, -4.44089210e-16, 0.00000000e+00, 1.11022302e-16,\n", - " 0.00000000e+00, 0.00000000e+00, -1.11022302e-16, 0.00000000e+00])" - ] - }, - "execution_count": 28, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "model.inverseKinematics(T0,x0)-q0" - ] - }, - { - "cell_type": "code", - "execution_count": 52, - "metadata": {}, - "outputs": [], - "source": [ - "dT = 1/50.\n", - "amplitudes = [0.01*(i+1) for i in range(8)]\n", - "frequencies = [0.5*(i+1) for i in range(40)]\n", - "durations = []\n", - "\n", - "for f in frequencies:\n", - " durations.append(len(amplitudes)*[int(f+1)*(2*np.pi/f)])\n", - "durations = np.array(durations).reshape(-1).tolist()" - ] - }, - { - "cell_type": "code", - "execution_count": 55, - "metadata": {}, - "outputs": [], - "source": [ - "x = []\n", - "for i,a in enumerate(amplitudes):\n", - " for j,f in enumerate(frequencies):\n", - " for N in range(int(durations[i*j]//dT)):\n", - " t = N/durations[i*j]\n", - " x_s = a*np.cos(2*np.pi*f*t)\n", - " y_s = a*np.sin(2*np.pi*f*t)\n", - " x.append(x_s)\n", - "\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "import matplotlib.pyplot as = [] # List of Pose\n", - "\n", - "\n", - "(plan, fraction) = move_group.compute_cartesian_path, eef_step = 0.01, jump_threshold = 0.0)" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.8.10" - } - }, - "nbformat": 4, - "nbformat_minor": 2 -} diff --git a/examples/compliance_test.ipynb b/examples/compliance_test.ipynb deleted file mode 100644 index 4ea0895..0000000 --- a/examples/compliance_test.ipynb +++ /dev/null @@ -1,460 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "pygame 2.5.2 (SDL 2.28.2, Python 3.8.18)\n", - "Hello from the pygame community. https://www.pygame.org/contribute.html\n" - ] - } - ], - "source": [ - "from Go2Py.robot.interface.ros2 import GO2Real, ros2_init, ROS2ExecutorManager\n", - "import time\n", - "ros2_init()\n", - "robot = GO2Real(mode='lowlevel')\n", - "ros2_exec_manager = ROS2ExecutorManager()\n", - "ros2_exec_manager.add_node(robot)\n", - "ros2_exec_manager.start()" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [], - "source": [ - "from Go2Py.robot.model import Go2Model\n", - "model = Go2Model()" - ] - }, - { - "cell_type": "code", - "execution_count": 48, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "{'q': array([ 0.19625151, 0.62121832, -1.45901692, -0.8040427 , 0.15673077,\n", - " -1.30231106, 0.76652366, 0.2306025 , -1.40467536, -0.80055571,\n", - " 0.02943856, -1.08567142]),\n", - " 'dq': array([ 0.10076362, 0. , -0.00202201, 0.03875524, -0.01162657,\n", - " -0.0161761 , 0.01937762, 0.00775105, 0.00808805, 0.05425733,\n", - " 0. , -0.03639622]),\n", - " 'ddq': array([0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.]),\n", - " 'tau_est': array([-0.14842969, 0.04947656, -0.23707521, -0.14842969, -0.12369141,\n", - " 0.28449023, 0. , 0. , -0.04741504, 0.02473828,\n", - " -0.02473828, 0.04741504]),\n", - " 'temperature': array([35., 31., 30., 32., 30., 29., 35., 30., 29., 35., 30., 29.])}" - ] - }, - "execution_count": 48, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "robot.getJointStates()" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": {}, - "outputs": [], - "source": [ - "\n", - "import socket\n", - "import struct\n", - "import threading\n", - "import time\n", - "class AtiFTSensor:\n", - " def __init__(self):\n", - " self.initialized_ = False\n", - " self.going_ = False\n", - " self.streaming_ = False\n", - " self.F_bias_ = [0.0] * 3\n", - " self.T_bias_ = [0.0] * 3\n", - " self.F_ = [0.0] * 3\n", - " self.T_ = [0.0] * 3\n", - " self.rdt_sequence_ = 0\n", - " self.ft_sequence_ = 0\n", - " self.status_ = 0\n", - " self.count_per_force_ = 1000000.0\n", - " self.count_per_torque_ = 1000000.0\n", - " self.force_torque_ = [0.0] * 6\n", - " self.mutex_ = threading.Lock()\n", - " self.socket_ = None\n", - " self.local_address_ = ('', 49152)\n", - " self.remote_address_ = ('192.168.4.1', 49152)\n", - "\n", - " def initialize(self):\n", - " if self.initialized_:\n", - " print(\"warning already initialized\")\n", - " return True\n", - " print(\"initializing\")\n", - " \n", - " try:\n", - " self.socket_ = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)\n", - " self.socket_.bind(self.local_address_)\n", - " self.socket_.connect(self.remote_address_)\n", - " except socket.error as e:\n", - " print(f\"Error: {e}\")\n", - " return False\n", - "\n", - " print(\"created sockets\")\n", - " self.initialized_ = True\n", - " return self.initialized_\n", - "\n", - " def read_ft(self):\n", - " msg = struct.pack('>HHH', 0x1234, 0x0002, 0)\n", - " self.socket_.send(msg)\n", - "\n", - " internal_going = True\n", - "\n", - " while internal_going:\n", - " data = self.socket_.recv(36) # Assuming message size is 48 bytes\n", - " if len(data) != 36:\n", - " print(f\"Received message of unexpected length {len(data)}\")\n", - "\n", - " self.mutex_.acquire()\n", - " # print(data)\n", - " # breakpoint()\n", - " (self.rdt_sequence_, self.ft_sequence_, self.status_, \n", - " self.Fx, self.Fy, self.Fz, \n", - " self.Tx, self.Ty, self.Tz) = struct.unpack('>3I6i', data)\n", - " \n", - " \n", - " self.F_[0] = self.Fx / self.count_per_force_ - self.F_bias_[0]\n", - " self.F_[1] = self.Fy / self.count_per_force_ - self.F_bias_[1]\n", - " self.F_[2] = self.Fz / self.count_per_force_ - self.F_bias_[2]\n", - " self.T_[0] = self.Tx / self.count_per_torque_ - self.T_bias_[0]\n", - " self.T_[1] = self.Ty / self.count_per_torque_ - self.T_bias_[1]\n", - " self.T_[2] = self.Tz / self.count_per_torque_ - self.T_bias_[2]\n", - "\n", - " if self.streaming_:\n", - " # Implement streaming logic here\n", - " pass\n", - "\n", - " internal_going = self.going_\n", - " self.mutex_.release()\n", - "\n", - " def set_bias(self, force=None, torque=None):\n", - " self.mutex_.acquire()\n", - " for i in range(3):\n", - " if force is None:\n", - " self.F_bias_[i] = self.F_[i]\n", - " else:\n", - " self.F_bias_[i] = force[i]\n", - "\n", - " if torque is None:\n", - " self.T_bias_[i] = self.T_[i]\n", - " else:\n", - " self.T_bias_[i] = torque[i]\n", - " self.mutex_.release()\n", - "\n", - " def reset_bias(self):\n", - " self.mutex_.acquire()\n", - " self.F_bias_ = [0.0] * 3\n", - " self.T_bias_ = [0.0] * 3\n", - " self.mutex_.release()\n", - "\n", - " def get_status(self):\n", - " self.mutex_.acquire()\n", - " status = (self.rdt_sequence_, self.ft_sequence_, self.status_)\n", - " self.mutex_.release()\n", - " return status\n", - "\n", - " def get_ft(self):\n", - " self.mutex_.acquire()\n", - " ft = (self.F_[:], self.T_[:])\n", - " self.mutex_.release()\n", - " return ft\n", - "\n", - " def get_ft_vector(self):\n", - " self.mutex_.acquire()\n", - " ft_vector = self.F_ + self.T_\n", - " self.mutex_.release()\n", - " return ft_vector\n", - "\n", - " def stop(self):\n", - " if self.initialized_:\n", - " self.mutex_.acquire()\n", - " self.going_ = False\n", - " self.mutex_.release()\n", - " self.socket_.close()\n", - " self.initialized_ = False\n", - "\n", - " def stream(self, stream):\n", - " self.mutex_.acquire()\n", - " self.streaming_ = stream\n", - " self.mutex_.release()\n", - "\n", - " def __del__(self):\n", - " self.stop()\n" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "initializing\n", - "created sockets\n" - ] - }, - { - "data": { - "text/plain": [ - "True" - ] - }, - "execution_count": 5, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "sensor = AtiFTSensor()\n", - "sensor.initialize()" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "5.372439" - ] - }, - "execution_count": 6, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "sensor.read_ft() \n", - "f, t = sensor.get_ft() # R\n", - "f[2]" - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "metadata": {}, - "outputs": [], - "source": [ - "fz_bias = 0.0\n", - "for i in range(300):\n", - " time.sleep(0.01)\n", - " sensor.read_ft() \n", - " f, t = sensor.get_ft()\n", - " fz_bias += f[2]\n", - "\n", - "fz_bias /=1000" - ] - }, - { - "cell_type": "code", - "execution_count": 72, - "metadata": {}, - "outputs": [ - { - "ename": "KeyboardInterrupt", - "evalue": "", - "output_type": "error", - "traceback": [ - "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", - "\u001b[0;31mKeyboardInterrupt\u001b[0m Traceback (most recent call last)", - "Cell \u001b[0;32mIn[72], line 21\u001b[0m\n\u001b[1;32m 19\u001b[0m T \u001b[38;5;241m=\u001b[39m np\u001b[38;5;241m.\u001b[39meye(\u001b[38;5;241m4\u001b[39m)\n\u001b[1;32m 20\u001b[0m T[\u001b[38;5;241m0\u001b[39m:\u001b[38;5;241m3\u001b[39m,\u001b[38;5;241m0\u001b[39m:\u001b[38;5;241m3\u001b[39m]\u001b[38;5;241m=\u001b[39mR\n\u001b[0;32m---> 21\u001b[0m \u001b[43mmodel\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mupdateAllPose\u001b[49m\u001b[43m(\u001b[49m\u001b[43mstate\u001b[49m\u001b[43m[\u001b[49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[38;5;124;43mq\u001b[39;49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[43m]\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mstate\u001b[49m\u001b[43m[\u001b[49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[38;5;124;43mdq\u001b[39;49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[43m]\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mT\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mnp\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mzeros\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;241;43m6\u001b[39;49m\u001b[43m)\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 22\u001b[0m info \u001b[38;5;241m=\u001b[39m model\u001b[38;5;241m.\u001b[39mgetInfo()\n\u001b[1;32m 23\u001b[0m FR_nle \u001b[38;5;241m=\u001b[39m info[\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mnle\u001b[39m\u001b[38;5;124m'\u001b[39m][\u001b[38;5;241m6\u001b[39m:][\u001b[38;5;241m0\u001b[39m:\u001b[38;5;241m3\u001b[39m]\n", - "File \u001b[0;32m~/projects/rooholla/locomotion/Go2Py/Go2Py/robot/model.py:213\u001b[0m, in \u001b[0;36mGo2Model.updateAllPose\u001b[0;34m(self, q, dq, T, v)\u001b[0m\n\u001b[1;32m 211\u001b[0m q_ \u001b[38;5;241m=\u001b[39m np\u001b[38;5;241m.\u001b[39mhstack([pin\u001b[38;5;241m.\u001b[39mSE3ToXYZQUATtuple(pin\u001b[38;5;241m.\u001b[39mSE3(T)), q[\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mq_reordering_idx]])\n\u001b[1;32m 212\u001b[0m dq_ \u001b[38;5;241m=\u001b[39m np\u001b[38;5;241m.\u001b[39mhstack([v, dq[\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mq_reordering_idx]])\n\u001b[0;32m--> 213\u001b[0m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mupdateKinematics\u001b[49m\u001b[43m(\u001b[49m\u001b[43mq_\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 214\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mupdateDynamics(q_, dq_)\n", - "File \u001b[0;32m~/projects/rooholla/locomotion/Go2Py/Go2Py/robot/model.py:153\u001b[0m, in \u001b[0;36mGo2Model.updateKinematics\u001b[0;34m(self, q)\u001b[0m\n\u001b[1;32m 151\u001b[0m Jb \u001b[38;5;241m=\u001b[39m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mrobot\u001b[38;5;241m.\u001b[39mgetFrameJacobian(\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mrobot\u001b[38;5;241m.\u001b[39mmodel\u001b[38;5;241m.\u001b[39mgetFrameId(ef_frame), pin\u001b[38;5;241m.\u001b[39mReferenceFrame\u001b[38;5;241m.\u001b[39mLOCAL)\n\u001b[1;32m 152\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mef_Jw_[ef_frame]\u001b[38;5;241m=\u001b[39mJw[:, \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mdq_reordering_idx]\n\u001b[0;32m--> 153\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mef_Jb_[ef_frame]\u001b[38;5;241m=\u001b[39m\u001b[43mJb\u001b[49m\u001b[43m[\u001b[49m\u001b[43m:\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mdq_reordering_idx\u001b[49m\u001b[43m]\u001b[49m\n", - "\u001b[0;31mKeyboardInterrupt\u001b[0m: " - ] - } - ], - "source": [ - "import numpy as np\n", - "import pinocchio as pin\n", - "import time\n", - "vel = []\n", - "data_force = []\n", - "data_error = []\n", - "x0 = 0.23\n", - "z0 = -0.33\n", - "q = 12*[0.0] \n", - "dq = 12*[0.0] \n", - "kp = 12*[0.0] \n", - "kd = 12*[0.0] \n", - "tau = 12*[0.0] \n", - "for i in range(1000000):\n", - " state = robot.getJointStates()\n", - " Quat = robot.getIMU()['quat']\n", - " R = pin.Quaternion(np.hstack([Quat[1:],Quat[0]])).matrix()\n", - " R=np.eye(3)\n", - " T = np.eye(4)\n", - " T[0:3,0:3]=R\n", - " model.updateAllPose(state['q'], state['dq'], T, np.zeros(6))\n", - " info = model.getInfo()\n", - " FR_nle = info['nle'][6:][0:3]\n", - " FR_position = model.forwardKinematics(T, state['q'])['FR_foot'][0:3,-1]\n", - " FR_J = info['J_w']['FR_foot'][0:3, 6:][:,0:3]\n", - " FR_vel = FR_J@state['dq'][0:3].reshape(3,1)\n", - " \n", - " z_des = z0 \n", - " x_des = x0\n", - " task_kp = 650.0\n", - " fz = task_kp*(z_des - FR_position[2])\n", - " fx = 200*(x_des - FR_position[0]) + 4.5*(0-FR_vel[0])\n", - " Fx = np.array([fx[0],\n", - " 0,\n", - " fz]).reshape(3,1)\n", - " \n", - " tau_cmd = FR_J.T@Fx\n", - " data_error.append(z_des - FR_position[2])\n", - " sensor.read_ft() \n", - " f, t = sensor.get_ft() # R\n", - " data_force.append(f[2]-fz_bias)\n", - " \n", - "\n", - " kp[0] = 50.0\n", - " kd[0] = 2.0\n", - " # print(tau_cmd[1], x_des - FR_position[0], FR_vel[0])\n", - " # vel.append(FR_vel[0])\n", - " tau[1] = FR_nle[1]+tau_cmd[1].squeeze()\n", - " tau[2] = FR_nle[2]+tau_cmd[2].squeeze()\n", - " # tau[1] = 15.0* (0.7856252789497375-state['q'][1]) + 0.5* (0.-state['dq'][1])\n", - " robot.setCommands(q, dq, kp, kd, tau)\n", - " time.sleep(0.0007) " - ] - }, - { - "cell_type": "code", - "execution_count": 73, - "metadata": {}, - "outputs": [], - "source": [ - "import matplotlib.pyplot as plt\n", - "import numpy as np\n", - "\n", - "data_error = np.array(data_error)\n", - "data_force = np.array(data_force)" - ] - }, - { - "cell_type": "code", - "execution_count": 74, - "metadata": {}, - "outputs": [], - "source": [ - "import pickle\n", - "with open(f'go2_impact_test2_{task_kp}.pkl', 'wb') as f:\n", - " pickle.dump({\n", - " 'P':kp,\n", - " 'z_error':data_error,\n", - " 'ATI_Fz':data_force\n", - " }, f)" - ] - }, - { - "cell_type": "code", - "execution_count": 75, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "[]" - ] - }, - "execution_count": 75, - "metadata": {}, - "output_type": "execute_result" - }, - { - "data": { - "image/png": "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", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "plt.plot(data_force)" - ] - }, - { - "cell_type": "code", - "execution_count": 77, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "Text(0.5, 0, 'Error(meters)')" - ] - }, - "execution_count": 77, - "metadata": {}, - "output_type": "execute_result" - }, - { - "data": { - "image/png": "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", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "start = 0\n", - "end = -1\n", - "plt.plot(data_error[start:end], data_force[start:end])\n", - "plt.grid(True)\n", - "plt.ylabel('Fz (N)')\n", - "plt.xlabel('Error(meters)')" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.8.18" - } - }, - "nbformat": 4, - "nbformat_minor": 4 -} diff --git a/examples/contact_detection.ipynb b/examples/contact_detection.ipynb deleted file mode 100644 index 968c4c9..0000000 --- a/examples/contact_detection.ipynb +++ /dev/null @@ -1,254 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Simulated" - ] - }, - { - "cell_type": "code", - "execution_count": 349, - "metadata": {}, - "outputs": [], - "source": [ - "from Go2Py.sim.mujoco import Go2Sim\n", - "from Go2Py.robot.model import Go2Model\n", - "from Go2Py.estimation.contact import HysteresisContactDetector\n", - "import pinocchio as pin \n", - "import numpy as np\n", - "import time" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "model = Go2Model()\n", - "robot = Go2Sim()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "contactFilter = HysteresisContactDetector(12, 35)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "dataset = []\n", - "dataset_measured = []\n", - "dataset_contact_states = []\n", - "for _ in range(5000):\n", - " time.sleep(0.001)\n", - " state = robot.getJointStates()\n", - " quat = robot.getIMU()['quat']\n", - " quat = np.hstack([quat[1:], quat[0]])\n", - " R = pin.Quaternion(quat).matrix()\n", - " T = np.eye(4)\n", - " T[0:3,0:3] = R\n", - " vel = np.zeros(6)\n", - " model.update(state['q'], state['dq'],T,vel)\n", - " F = model.getGroundReactionForce(state['tau_est'])\n", - " contact_forces = np.array([-F[key][-1] for key in F.keys()])\n", - " contactFilter.update(contact_forces)\n", - " contact_state = contactFilter.getContactStates()\n", - " dataset_contact_states.append(contact_state.copy())\n", - " dataset.append(model.getGroundReactionForce(state['tau_est'])['FR_foot'])\n", - " dataset_measured.append(robot.getFootContacts())\n", - "dataset_measured = np.vstack(dataset_measured)\n", - "\n", - "dataset = np.vstack(dataset)\n", - "dataset_contact_states = np.vstack(dataset_contact_states)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Real Robot" - ] - }, - { - "cell_type": "code", - "execution_count": 297, - "metadata": {}, - "outputs": [], - "source": [ - "from Go2Py.robot.interface.dds import GO2Real\n", - "from Go2Py.robot.model import Go2Model\n", - "import time\n", - "from Go2Py.sim.mujoco import Go2Sim\n", - "from Go2Py.robot.fsm import FSM\n", - "import numpy as np\n", - "import pinocchio as pin" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [], - "source": [ - "robot = GO2Real(mode='lowlevel')\n", - "model = Go2Model()" - ] - }, - { - "cell_type": "code", - "execution_count": 293, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "{'q': array([ 0.07208335, 0.71541172, -1.52541149, -0.04195726, 0.77687514,\n", - " -1.53210962, 0.10532299, 0.72009933, -1.50478077, -0.04001439,\n", - " 0.66759801, -1.4734081 ]),\n", - " 'dq': array([ 0.02325314, -0.01162657, 0.0161761 , 0.0155021 , 0.0658839 ,\n", - " 0.01011006, 0.01162657, -0.00775105, -0.00404402, 0.01937762,\n", - " 0.0658839 , -0.06066037]),\n", - " 'ddq': array([0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.]),\n", - " 'tau_est': array([ 2.49856639, 0.66793358, 7.06484079, -2.22644544, 0.02473828,\n", - " 6.44844532, 1.68220317, 0.5442422 , 6.44844532, -2.54804301,\n", - " 1.06374609, 6.25878525]),\n", - " 'temperature': array([30., 28., 27., 28., 28., 27., 28., 28., 27., 30., 28., 27.])}" - ] - }, - "execution_count": 293, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "state = robot.getJointStates()\n", - "state" - ] - }, - { - "cell_type": "code", - "execution_count": 323, - "metadata": {}, - "outputs": [], - "source": [ - "contactFilter = HysteresisContactDetector(12, 35)" - ] - }, - { - "cell_type": "code", - "execution_count": 348, - "metadata": {}, - "outputs": [], - "source": [ - "dataset = []\n", - "dataset_measured = []\n", - "dataset_contact_states = []\n", - "for _ in range(5000):\n", - " # time.sleep(0.001)\n", - " state = robot.getJointStates()\n", - " quat = robot.getIMU()['quat']\n", - " quat = np.hstack([quat[1:], quat[0]])\n", - " R = pin.Quaternion(quat).matrix()\n", - " T = np.eye(4)\n", - " T[0:3,0:3] = R\n", - " vel = np.zeros(6)\n", - " model.update(state['q'], state['dq'],T,vel)\n", - " F = model.getGroundReactionForce(state['tau_est'])\n", - " contact_forces = np.array([-F[key][-1] for key in F.keys()])\n", - " contactFilter.update(contact_forces)\n", - " contact_state = contactFilter.getContactStates()\n", - " dataset_contact_states.append(contact_state.copy())\n", - " dataset.append(model.getGroundReactionForce(state['tau_est'])['FR_foot'])\n", - " dataset_measured.append(robot.getFootContacts())\n", - "dataset_measured = np.vstack(dataset_measured)\n", - "dataset = np.vstack(dataset)\n", - "dataset_contact_states = np.vstack(dataset_contact_states)" - ] - }, - { - "cell_type": "code", - "execution_count": 325, - "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "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Z7OFCxey6upq9u6777LU1FT2zjvvWFVNW5kzZw7buHEjq66uZlVVVaysrIzl5+eza9euCWmefvpplpeXx7Zv384OHjzI7rjjDjZ9+nThemdnJxs/fjwrLS1lhw4dYuXl5WzgwIFs1apVQppvv/2WpaWlseXLl7Njx46xN998k7lcLrZ161ZL62sn//znP9knn3zCTpw4wWpra9kLL7zAPB4Pq66uZoyRno1m//79bMSIEWzixIls2bJlwnnSszGsWbOGjRs3jl24cEH4d/HiReE673omQ0WGadOmsSVLlgi/g8EgGzp0KFu7dq2NUiUOkYZKKBRiOTk57NVXXxXONTc3M5/Px959913GGGPHjh1jANiBAweENJ9++ilzOBysvr6eMcbYH/7wB5aVlcXa29uFNM8//zwrLCw0uUZ80tTUxACw3bt3M8a6dOrxeNj7778vpKmpqWEA2J49exhjXQal0+lkDQ0NQpr169ez9PR0Qa+/+tWv2Lhx4yRlLViwgM2ZM8fsKnFNVlYW+/Of/0x6NpjW1lY2evRoVlFRwe655x7BUCE9G8eaNWvYpEmTZK8lgp5p6CeCjo4OVFZWorS0VDjndDpRWlqKPXv22ChZ4nL69Gk0NDRIdJqRkYHi4mJBp3v27EFmZiamTp0qpCktLYXT6cS+ffuENHfffTe8Xq+QZs6cOaitrcXVq1ctqg0/tLS0AAD69+8PAKisrEQgEJDoecyYMcjPz5foecKECcjOzhbSzJkzB36/H0ePHhXSiPPoTtNbn/9gMIjNmzfj+vXrKCkpIT0bzJIlSzB//vwoXZCejeXkyZMYOnQoRo4ciYULF+Ls2bMAEkPPZKhEcOnSJQSDQckfBACys7PR0NBgk1SJTbfe1HTa0NCAwYMHS6673W70799fkkYuD3EZvYVQKIRnn30Wd955J8aPHw+gSwderxeZmZmStJF61tKhUhq/34+2tjYzqsMlR44cQd++feHz+fD0009jy5YtGDt2LOnZQDZv3oyvv/4aa9eujbpGejaO4uJibNq0CVu3bsX69etx+vRpzJgxA62trQmh54TfPZkgeiNLlixBdXU1vvjiC7tFSVoKCwtRVVWFlpYWfPDBB3jsscewe/duu8VKGs6dO4dly5ahoqICKSkpdouT1MybN084njhxIoqLizF8+HD8/e9/R2pqqo2S6YM8KhEMHDgQLpcrKuK5sbEROTk5NkmV2HTrTU2nOTk5aGpqklzv7OzElStXJGnk8hCX0RtYunQpPv74Y+zcuRO5ubnC+ZycHHR0dKC5uVmSPlLPWjpUSpOenp4QnZpReL1ejBo1CkVFRVi7di0mTZqEN954g/RsEJWVlWhqasKUKVPgdrvhdruxe/du/P73v4fb7UZ2djbp2SQyMzNx6623oq6uLiGeZzJUIvB6vSgqKsL27duFc6FQCNu3b0dJSYmNkiUuBQUFyMnJkejU7/dj3759gk5LSkrQ3NyMyspKIc2OHTsQCoVQXFwspPnss88QCASENBUVFSgsLERWVpZFtbEPxhiWLl2KLVu2YMeOHSgoKJBcLyoqgsfjkei5trYWZ8+elej5yJEjEqOwoqIC6enpGDt2rJBGnEd3mt7+/IdCIbS3t5OeDWLWrFk4cuQIqqqqhH9Tp07FwoULhWPSszlcu3YNp06dwpAhQxLjeY47HDcJ2bx5M/P5fGzTpk3s2LFj7KmnnmKZmZmSiGdCSmtrKzt06BA7dOgQA8Bef/11dujQIfbdd98xxrqmJ2dmZrJ//OMf7PDhw+zBBx+UnZ582223sX379rEvvviCjR49WjI9ubm5mWVnZ7NHH32UVVdXs82bN7O0tLReMz35mWeeYRkZGWzXrl2SaYY3btwQ0jz99NMsPz+f7dixgx08eJCVlJSwkpIS4Xr3NMPZs2ezqqoqtnXrVjZo0CDZaYbPPfccq6mpYW+99Vavm865cuVKtnv3bnb69Gl2+PBhtnLlSuZwONi2bdsYY6RnsxDP+mGM9GwUK1asYLt27WKnT59mX375JSstLWUDBw5kTU1NjDH+9UyGigJvvvkmy8/PZ16vl02bNo3t3bvXbpG4ZufOnQxA1L/HHnuMMdY1Rfk3v/kNy87OZj6fj82aNYvV1tZK8rh8+TJ7+OGHWd++fVl6ejp74oknWGtrqyTNN998w+666y7m8/nYsGHD2Lp166yqou3I6RcA27hxo5Cmra2N/fKXv2RZWVksLS2N/fSnP2UXLlyQ5HPmzBk2b948lpqaygYOHMhWrFjBAoGAJM3OnTvZ5MmTmdfrZSNHjpSU0Rt48skn2fDhw5nX62WDBg1is2bNEowUxkjPZhFpqJCejWHBggVsyJAhzOv1smHDhrEFCxawuro64TrvenYwxlj8fhmCIAiCIAjjoRgVgiAIgiC4hQwVgiAIgiC4hQwVgiAIgiC4hQwVgiAIgiC4hQwVgiAIgiC4hQwVgiAIgiC4hQwVgiAIgiC4hQwVgiAIgiC4hQwVgiAIgiC4hQwVgiAIgiC4hQwVgiAIgiC4hQwVgiAIgiC45f8D3Irk1m5lpTEAAAAASUVORK5CYII=", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "import matplotlib.pyplot as plt\n", - "plt.plot(-dataset[:,-1])\n", - "plt.plot(dataset_measured[:,0])\n", - "plt.legend(['estimated', 'sensor'])\n", - "plt.grid(True)" - ] - }, - { - "cell_type": "code", - "execution_count": 327, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "[]" - ] - }, - "execution_count": 327, - "metadata": {}, - "output_type": "execute_result" - }, - { - "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAAiMAAAGdCAYAAADAAnMpAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjcuMSwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/bCgiHAAAACXBIWXMAAA9hAAAPYQGoP6dpAABGl0lEQVR4nO3df3xU1Z3/8fckkATKb5HwKxqoVqQoKBQ2/qh1zYrWtetu+y1r/Spf2tqvFvarTddW2gp1223c7sra7VJptdTubhWtW2m7UiyNYquiVH6oIGJREPyRACKEXyaQnO8fIZO5mXvPPTOZ5N6ZvJ4+MJN7zz333DP3TD6ZzOechDHGCAAAICJFUTcAAAD0bgQjAAAgUgQjAAAgUgQjAAAgUgQjAAAgUgQjAAAgUgQjAAAgUgQjAAAgUn2iboCL1tZWvf322xo4cKASiUTUzQEAAA6MMTp48KBGjx6toqLg9z/yIhh5++23VVFREXUzAABAFnbt2qWxY8cG7s+LYGTgwIGS2i5m0KBBEbcGAAC4aGxsVEVFRfLneJC8CEba/zQzaNAgghEAAPJM2Ecs+AArAACIFMEIAACIFMEIAACIFMEIAACIFMEIAACIFMEIAACIFMEIAACIFMEIAACIFMEIAACIVMbByO9//3tdeeWVGj16tBKJhJYvXx56zOrVq3XuueeqtLRUp512mu67774smgoAAApRxsHI4cOHNXnyZC1evNip/Pbt23XFFVfo4osv1saNG3XzzTfr85//vB577LGMGwsAAApPxmvTXH755br88sudyy9ZskTjxo3TnXfeKUk688wz9dRTT+lf//VfNXPmzExPDwAACky3L5S3Zs0aVVdXe7bNnDlTN998c+AxTU1NampqSn7f2NjYXc3Le6/tOaQH/7hLx1pak9sOHD2m37xUr09OHaO+xW1vfm3fe1irt+7RdVWnqrjIvmBRTxk9uJ8+e8E4FRclVLelQU9t25vcN71ymC4/a5QkadNbB7R8w1tqMSa5P6GELps0UtPHDZMk1R94X/+xZoeOHmvxnOPSiSNV9cGTkt8/suFNvfjmgeT3g8r6as75lRrSv0StrUZLn96ut/Yfdb6GC08frj+fUC5JeuPdw7p/7U41H+94LsafPED/e8YpSiQS2nOwST99ZocONx+XJPXrW6xrq07VqMH9JEnvHmrbf7DpePL4sUP7a855lSoqSuixzfV69vV3k/ue3/GejrW0eq4vTJ+ihD49rUKnlw9US6vRT3yud9TgMn32/HFav3O/Vm6ql1FHvw8s7aPZ51XqpAGleufAUf3nmjeSfX7o/eP69Ytv62/OHavSPnwcDV6pY02Stu0+qIeefzP52pVQQh8/a6SmVbaN6d+89I7W7tjnqeMX69/SjHHDNGZov55tvEXqmDDG6KfP7NAb+454yqSO4+MtrVr69Ha9c+D9nLflzJGD9OmPVEiSmo+3naehMf08Hz39ZF08YYReqW/Uf697U8db28b4Z88fp4ph/XPeLhfdHozU19ervLzcs628vFyNjY06evSo+vVLv6lqa2t1++23d3fTCsKi376qR196x3fffz27M23bf6x5o7ublJGzxw7W9HHDNO/+DZ5A4r+efUMvTRihsr7F+vajL+vZ1/elHbt66249/vcfkyT9+KnXdc8ftqeV+d2WBv3hK38uqe2H/ZcefCGtzKB+ffW5C8Zpw6739O1Ht2TU/of+uEub/+EySdL3H9+mh9e9mVamavwwnTZioP7z2Tf0709s8+xrOt6q2/5yoiRp2R936d8e35Z2/LmnDNGHRw/W3z2wwRPotHul/mBGbd6+94junT1Nf9yxL/B6J40erG8s36TX9x5O21fat1hzLz5NP/7Ddt37VHqf3/9c+n0HSNLAsj76/IXjJUn//NhWPba5wbP/D3/ao1U1F+loc4v+37INOtZi0ur47csNadui1j4mNr/dqG/++mXfMlMqhmjqqUP13PZ9+s6KV7qtLRecPlyjh/TT06/t1R2/8T/Pw8+/qZdun6naFa/oyVf3JLdfOXl04QYj2Zg/f75qamqS3zc2NqqioiLCFsVX+2/Zfz5hhM4cNVCStPiJ15L75178wbRtqWWj8tDzb2rPwSYdaW6RMUoGIv/nvErd98wOHWsxOtbSqrK+xTrS3LbvirNHqfKk/tpzsEkPPf9m8tol6fCJMtMrh+kj44Zq3+FmPbB2l440dQQ47ecoLkrohovG64lX9ujldxp15MQ7EYdPlB0+oESzPmK/3440t+gnT+9InrdtW1s9F54+XGePHaz/eOYNHWw6nqy3/TznnDJEfYuLtHb7vuQxbedvezx57GBdcPpwLVu7S+8ebtaR5ha1tJpkIHL9heN0qKlFD6xt+6H/v6aO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aaeZq6++Orn/wIEDpry83FxzzTVm06ZN5oEHHjD9+vUzP/zhD3vqMiM3c+ZM85Of/MRs2rTJbNy40Xz84x83p5xyijl06FCyzA033GAqKipMXV2def75582f/dmfmfPOOy+5//jx42bSpEmmurrabNiwwaxYscIMHz7czJ8/P1nm9ddfN/379zc1NTXm5ZdfNt///vdNcXGxWblyZY9eb1R+9atfmUcffdS8+uqrZuvWreZrX/ua6du3r9m0aZMxhj7uDmvXrjWVlZXm7LPPNjfddFNyO32dGwsXLjQf/vCHzTvvvJP8t2fPnuT+uPdzrw1Gpk+fbubOnZv8vqWlxYwePdrU1tZG2Kr80DkYaW1tNSNHjjT//M//nNy2f/9+U1paah544AFjjDEvv/yykWT++Mc/Jsv85je/MYlEwrz11lvGGGN+8IMfmKFDh5qmpqZkma9+9avmjDPO6OYriq/du3cbSebJJ580xrT1a9++fc3Pf/7zZJktW7YYSWbNmjXGmLbAsaioyNTX1yfL3H333WbQoEHJvv3KV75iPvzhD3vONWvWLDNz5szuvqTYGjp0qLn33nvp425w8OBBc/rpp5tVq1aZiy66KBmM0Ne5s3DhQjN58mTfffnQz73yzzTNzc1at26dqqurk9uKiopUXV2tNWvWRNiy/LR9+3bV19d7+nPw4MGaMWNGsj/XrFmjIUOGaNq0acky1dXVKioq0nPPPZcs89GPflQlJSXJMjNnztTWrVv13nvv9dDVxMuBAwckScOGDZMkrVu3TseOHfP09YQJE3TKKad4+vqss85SeXl5sszMmTPV2NiozZs3J8uk1tFepjfe/y0tLVq2bJkOHz6sqqoq+rgbzJ07V1dccUVaf9DXufWnP/1Jo0eP1vjx43XNNddo586dkvKjn3tlMLJ37161tLR4Ol2SysvLVV9fH1Gr8ld7n9n6s76+XiNGjPDs79Onj4YNG+Yp41dH6jl6k9bWVt188806//zzNWnSJElt/VBSUqIhQ4Z4ynbu67B+DCrT2Nioo0ePdsflxM5LL72kAQMGqLS0VDfccIMeeeQRTZw4kT7OsWXLlmn9+vWqra1N20df586MGTN03333aeXKlbr77ru1fft2XXjhhTp48GBe9HNerNoL9EZz587Vpk2b9NRTT0XdlIJ0xhlnaOPGjTpw4IAefvhhzZ49W08++WTUzSoou3bt0k033aRVq1aprKws6uYUtMsvvzz5+Oyzz9aMGTN06qmn6qGHHlK/fv0ibJmbXvnOyPDhw1VcXJz2SeKGhgaNHDkyolblr/Y+s/XnyJEjtXv3bs/+48ePa9++fZ4yfnWknqO3mDdvnv7nf/5HTzzxhMaOHZvcPnLkSDU3N2v//v2e8p37Oqwfg8oMGjQoL164cqGkpESnnXaapk6dqtraWk2ePFnf+9736OMcWrdunXbv3q1zzz1Xffr0UZ8+ffTkk0/q3/7t39SnTx+Vl5fT191kyJAh+tCHPqRt27blxT3dK4ORkpISTZ06VXV1dcltra2tqqurU1VVVYQty0/jxo3TyJEjPf3Z2Nio5557LtmfVVVV2r9/v9atW5cs8/jjj6u1tVUzZsxIlvn973+vY8eOJcusWrVKZ5xxhoYOHdpDVxMtY4zmzZunRx55RI8//rjGjRvn2T916lT17dvX09dbt27Vzp07PX390ksveYK/VatWadCgQZo4cWKyTGod7WV68/3f2tqqpqYm+jiHLrnkEr300kvauHFj8t+0adN0zTXXJB/T193j0KFDeu211zRq1Kj8uKe7/BHYPLVs2TJTWlpq7rvvPvPyyy+bL3zhC2bIkCGeTxKjw8GDB82GDRvMhg0bjCSzaNEis2HDBvPGG28YY9pSe4cMGWJ++ctfmhdffNH81V/9lW9q7znnnGOee+4589RTT5nTTz/dk9q7f/9+U15ebq699lqzadMms2zZMtO/f/9eldp74403msGDB5vVq1d7UvSOHDmSLHPDDTeYU045xTz++OPm+eefN1VVVaaqqiq5vz1F79JLLzUbN240K1euNCeffLJvit4tt9xitmzZYhYvXtyrUiFvvfVW8+STT5rt27ebF1980dx6660mkUiY3/72t8YY+rg7pWbTGENf58qXv/xls3r1arN9+3bz9NNPm+rqajN8+HCze/duY0z8+7nXBiPGGPP973/fnHLKKaakpMRMnz7dPPvss1E3KbaeeOIJIynt3+zZs40xbem9t912mykvLzelpaXmkksuMVu3bvXU8e6775qrr77aDBgwwAwaNMjMmTPHHDx40FPmhRdeMBdccIEpLS01Y8aMMXfccUdPXWIs+PWxJPOTn/wkWebo0aPmi1/8ohk6dKjp37+/+eu//mvzzjvveOrZsWOHufzyy02/fv3M8OHDzZe//GVz7NgxT5knnnjCTJkyxZSUlJjx48d7zlHoPvvZz5pTTz3VlJSUmJNPPtlccsklyUDEGPq4O3UORujr3Jg1a5YZNWqUKSkpMWPGjDGzZs0y27ZtS+6Pez8njDGm6++vAAAAZKdXfmYEAADEB8EIAACIFMEIAACIFMEIAACIFMEIAACIFMEIAACIFMEIAACIFMEIAACIFMEIAACIFMEIAACIFMEIAACIFMEIAACI1P8HZhSLqN3O58wAAAAASUVORK5CYII=", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "plt.plot(dataset_contact_states[:,0])" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.8.18" - } - }, - "nbformat": 4, - "nbformat_minor": 2 -} diff --git a/examples/data/april16-seq1.pkl b/examples/data/april16-seq1.pkl deleted file mode 100644 index e11bb86..0000000 Binary files a/examples/data/april16-seq1.pkl and /dev/null differ diff --git a/examples/data/april16-seq2.pkl b/examples/data/april16-seq2.pkl deleted file mode 100644 index 987b010..0000000 Binary files a/examples/data/april16-seq2.pkl and /dev/null differ diff --git a/examples/data/compliance-test/go2_impact_test2_250.0.pkl b/examples/data/compliance-test/go2_impact_test2_250.0.pkl deleted file mode 100644 index 26a18ff..0000000 Binary files a/examples/data/compliance-test/go2_impact_test2_250.0.pkl and /dev/null differ diff --git a/examples/data/compliance-test/go2_impact_test2_350.0.pkl b/examples/data/compliance-test/go2_impact_test2_350.0.pkl deleted file mode 100644 index bcb1a1c..0000000 Binary files a/examples/data/compliance-test/go2_impact_test2_350.0.pkl and /dev/null differ diff --git a/examples/data/compliance-test/go2_impact_test2_450.0.pkl b/examples/data/compliance-test/go2_impact_test2_450.0.pkl deleted file mode 100644 index 59e8213..0000000 Binary files a/examples/data/compliance-test/go2_impact_test2_450.0.pkl and /dev/null differ diff --git a/examples/data/compliance-test/go2_impact_test2_550.0.pkl b/examples/data/compliance-test/go2_impact_test2_550.0.pkl deleted file mode 100644 index e982820..0000000 Binary files a/examples/data/compliance-test/go2_impact_test2_550.0.pkl and /dev/null differ diff --git a/examples/data/compliance-test/go2_impact_test2_650.0.pkl b/examples/data/compliance-test/go2_impact_test2_650.0.pkl deleted file mode 100644 index 732e919..0000000 Binary files a/examples/data/compliance-test/go2_impact_test2_650.0.pkl and /dev/null differ diff --git a/examples/data/compliance-test/go2_impact_test2_650.pkl b/examples/data/compliance-test/go2_impact_test2_650.pkl deleted file mode 100644 index 5d06e32..0000000 Binary files a/examples/data/compliance-test/go2_impact_test2_650.pkl and /dev/null differ diff --git a/examples/data/setting_with_bad_startup.pkl b/examples/data/setting_with_bad_startup.pkl deleted file mode 100644 index fcd4917..0000000 Binary files a/examples/data/setting_with_bad_startup.pkl and /dev/null differ diff --git a/examples/data/sit_down.pkl b/examples/data/sit_down.pkl deleted file mode 100644 index c023420..0000000 Binary files a/examples/data/sit_down.pkl and /dev/null differ diff --git a/examples/data/standup.pkl b/examples/data/standup.pkl deleted file mode 100644 index 2a3f4f3..0000000 Binary files a/examples/data/standup.pkl and /dev/null differ diff --git a/examples/dds_draft.ipynb b/examples/dds_draft.ipynb deleted file mode 100644 index ecca78d..0000000 --- a/examples/dds_draft.ipynb +++ /dev/null @@ -1,377 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "from cyclonedds.domain import DomainParticipant\n", - "from Go2Py.unitree_go.msg.dds_ import Go2pyLowCmd_\n", - "from cyclonedds.topic import Topic\n", - "from cyclonedds.pub import DataWriter" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "participant = DomainParticipant()\n", - "topic = Topic(participant, \"rt/go2/lowcmd\", Go2pyLowCmd_)\n", - "writer = DataWriter(participant, topic)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "import numpy as np\n", - "msg = Go2pyLowCmd_(np.zeros(12),\n", - "np.zeros(12),np.zeros(12),np.zeros(12),np.zeros(12))" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "import time\n", - "while True:\n", - " writer.write(msg)\n", - " time.sleep(0.001)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "from Go2Py.std_msgs.msg.dds_ import String_\n", - "participant = DomainParticipant()\n", - "topic = Topic(participant, \"rt/test\", String_)\n", - "writer = DataWriter(participant, topic)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "msg = String_(\"Hello\")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "import time\n", - "while True:\n", - " writer.write(msg)\n", - " time.sleep(0.001)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "from cyclonedds.domain import DomainParticipant\n", - "from cyclonedds.topic import Topic\n", - "from cyclonedds.sub import DataReader\n", - "from cyclonedds.util import duration\n", - "from Go2Py.unitree_go.msg.dds_ import LowState_" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "participant = DomainParticipant()\n", - "topic = Topic(participant, 'rt/lowstate', LowState_)\n", - "reader = DataReader(participant, topic)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "for msg in reader.take_iter(timeout=duration(milliseconds=100.)):\n", - " print(msg)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "reader.take(timeout=duration(milliseconds=100.))" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "import struct\n", - "import threading\n", - "import time\n", - "import numpy as np\n", - "import numpy.linalg as LA\n", - "from scipy.spatial.transform import Rotation as R\n", - "\n", - "from cyclonedds.domain import DomainParticipant\n", - "from Go2Py.unitree_go.msg.dds_ import Go2pyLowCmd_\n", - "from cyclonedds.topic import Topic\n", - "from cyclonedds.pub import DataWriter\n", - "\n", - "from cyclonedds.domain import DomainParticipant\n", - "from cyclonedds.topic import Topic\n", - "from cyclonedds.sub import DataReader\n", - "from cyclonedds.util import duration\n", - "from Go2Py.unitree_go.msg.dds_ import LowState_\n", - "from threading import Thread" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "class GO2Real():\n", - " def __init__(\n", - " self,\n", - " mode = 'lowlevel', # 'highlevel' or 'lowlevel'\n", - " vx_max=0.5,\n", - " vy_max=0.4,\n", - " ωz_max=0.5,\n", - " ):\n", - " assert mode in ['highlevel', 'lowlevel'], \"mode should be either 'highlevel' or 'lowlevel'\"\n", - " self.mode = mode\n", - " if self.mode == 'highlevel':\n", - " raise NotImplementedError('DDS interface for the highlevel commands is not implemented yet. Please use our ROS2 interface.')\n", - "\n", - " self.highcmd_topic_name = \"rt/go2/twist_cmd\"\n", - " self.lowcmd_topic_name = \"rt/go2/lowcmd\"\n", - " self.lowstate_topic_name = \"rt/lowstate\"\n", - "\n", - " self.participant = DomainParticipant()\n", - " self.lowstate_topic = Topic(self.participant, self.lowstate_topic_name, LowState_)\n", - " self.lowstate_reader = DataReader(self.participant, self.lowstate_topic)\n", - " \n", - " self.lowcmd_topic = Topic(self.participant, self.lowcmd_topic_name, Go2pyLowCmd_)\n", - " self.lowcmd_writer = DataWriter(self.participant, self.lowcmd_topic)\n", - "\n", - " self.state = None\n", - " self.setCommands = {'lowlevel':self.setCommandsLow}[self.mode]\n", - " self.lowstate_thread = Thread(target = self.lowstate_update)\n", - " self.running = True\n", - " self.lowstate_thread.start()\n", - "\n", - " def lowstate_update(self):\n", - " \"\"\"\n", - " Retrieve the state of the robot\n", - " \"\"\"\n", - " while self.running:\n", - " for msg in self.lowstate_reader.take_iter(timeout=duration(milliseconds=100.)):\n", - " self.state = msg\n", - "\n", - " def getIMU(self):\n", - " accel = self.state.imu_state.accelerometer\n", - " gyro = self.state.imu_state.gyroscope\n", - " quat = self.state.imu_state.quaternion\n", - " rpy = self.state.imu_state.rpy\n", - " temp = self.state.imu_state.temperature\n", - " return {'accel':accel, 'gyro':gyro, 'quat':quat, \"rpy\":rpy, 'temp':temp}\n", - "\n", - " def getFootContacts(self):\n", - " \"\"\"Returns the raw foot contact forces\"\"\"\n", - " footContacts = self.state.foot_force \n", - " return np.array(footContacts)\n", - "\n", - " def getJointStates(self):\n", - " \"\"\"Returns the joint angles (q) and velocities (dq) of the robot\"\"\"\n", - " motor_state = np.array([[self.state.motor_state[i].q,\n", - " robot.state.motor_state[i].dq,\n", - " robot.state.motor_state[i].ddq,\n", - " robot.state.motor_state[i].tau_est,\n", - " robot.state.motor_state[i].temperature] for i in range(12)])\n", - " return {'q':motor_state[:,0], \n", - " 'dq':motor_state[:,1],\n", - " 'ddq':motor_state[:,2],\n", - " 'tau_est':motor_state[:,3],\n", - " 'temperature':motor_state[:,4]}\n", - "\n", - " def getRemoteState(self):\n", - " \"\"\"A method to get the state of the wireless remote control. \n", - " Returns a xRockerBtn object: \n", - " - head: [head1, head2]\n", - " - keySwitch: xKeySwitch object\n", - " - lx: float\n", - " - rx: float\n", - " - ry: float\n", - " - L2: float\n", - " - ly: float\n", - " \"\"\"\n", - " wirelessRemote = self.state.wireless_remote[:24]\n", - " binary_data = bytes(wirelessRemote)\n", - "\n", - " format_str = \"<2BH5f\"\n", - " data = struct.unpack(format_str, binary_data)\n", - "\n", - " head = list(data[:2])\n", - " lx = data[3]\n", - " rx = data[4]\n", - " ry = data[5]\n", - " L2 = data[6]\n", - " ly = data[7]\n", - "\n", - " _btn = bin(data[2])[2:].zfill(16)\n", - " btn = [int(char) for char in _btn]\n", - " btn.reverse()\n", - "\n", - " keySwitch = xKeySwitch(*btn)\n", - " rockerBtn = xRockerBtn(head, keySwitch, lx, rx, ry, L2, ly)\n", - " return rockerBtn\n", - "\n", - " def getCommandFromRemote(self):\n", - " \"\"\"Do not use directly for control!!!\"\"\"\n", - " rockerBtn = self.getRemoteState()\n", - "\n", - " lx = rockerBtn.lx\n", - " ly = rockerBtn.ly\n", - " rx = rockerBtn.rx\n", - "\n", - " v_x = ly * self.vx_max\n", - " v_y = lx * self.vy_max\n", - " ω = rx * self.ωz_max\n", - " \n", - " return v_x, v_y, ω\n", - "\n", - " def getBatteryState(self):\n", - " \"\"\"Returns the battery percentage of the robot\"\"\"\n", - " batteryState = self.state.bms_state\n", - " return batteryState.soc\n", - "\n", - " def setCommandsHigh(self, v_x, v_y, ω_z, bodyHeight=0.0, footRaiseHeight=0.0, mode=2):\n", - " self.cmd_watchdog_timer = time.time()\n", - " _v_x, _v_y, _ω_z = self.clip_velocity(v_x, v_y, ω_z)\n", - " self.highcmd.header.stamp = self.get_clock().now().to_msg()\n", - " self.highcmd.header.frame_id = \"base_link\"\n", - " self.highcmd.twist.linear.x = _v_x\n", - " self.highcmd.twist.linear.y = _v_y\n", - " self.highcmd.twist.angular.z = _ω_z\n", - " self.highcmd_publisher.publish(self.highcmd)\n", - "\n", - " def setCommandsLow(self, q, dq, kp, kd, tau_ff):\n", - " assert q.size == dq.size == kp.size == kd.size == tau_ff.size == 12, \"q, dq, kp, kd, tau_ff should have size 12\"\n", - " lowcmd = Go2pyLowCmd_(\n", - " q,\n", - " dq, \n", - " kp,\n", - " kd,\n", - " tau_ff\n", - " )\n", - " self.lowcmd_writer.write(lowcmd)\n", - "\n", - " def close(self):\n", - " self.running = False\n", - "\n", - " def check_calf_collision(self, q):\n", - " self.pin_robot.update(q)\n", - " in_collision = self.pin_robot.check_calf_collision(q)\n", - " return in_collision\n", - "\n", - " def clip_velocity(self, v_x, v_y, ω_z):\n", - " _v = np.array([[v_x], [v_y]])\n", - " _scale = np.sqrt(_v.T @ self.P_v_max @ _v)[0, 0]\n", - "\n", - " if _scale > 1.0:\n", - " scale = 1.0 / _scale\n", - " else:\n", - " scale = 1.0\n", - "\n", - " return scale * v_x, scale * v_y, np.clip(ω_z, self.ωz_min, self.ωz_max)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "robot.getBatteryState()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "from Go2Py.robot.interface.dds import GO2Real\n", - "robot = GO2Real()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "robot.getIMU()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.8.18" - } - }, - "nbformat": 4, - "nbformat_minor": 2 -} diff --git a/examples/fsm_real.ipynb b/examples/fsm_real.ipynb deleted file mode 100644 index d1cdc6c..0000000 --- a/examples/fsm_real.ipynb +++ /dev/null @@ -1,69 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [], - "source": [ - "from Go2Py.robot.interface.dds import GO2Real\n", - "import time\n", - "from Go2Py.sim.mujoco import Go2Sim\n", - "from Go2Py.robot.fsm import FSM\n", - "from Go2Py.robot.remote import KeyboardRemote\n", - "from Go2Py.robot.safety import SafetyHypervisor\n", - "import numpy as np" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "robot = GO2Real(mode='lowlevel')\n", - "remote = KeyboardRemote()\n", - "safety_hypervisor = SafetyHypervisor(robot)" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "metadata": {}, - "outputs": [], - "source": [ - "fsm = FSM(robot, remote, safety)" - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "metadata": {}, - "outputs": [], - "source": [ - "fsm.close()" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "b1-env", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.8.18" - } - }, - "nbformat": 4, - "nbformat_minor": 2 -} diff --git a/examples/go2_rotation.pkl b/examples/go2_rotation.pkl deleted file mode 100644 index f3c5fea..0000000 Binary files a/examples/go2_rotation.pkl and /dev/null differ diff --git a/examples/go2_walking.pkl b/examples/go2_walking.pkl deleted file mode 100644 index 3f69b38..0000000 Binary files a/examples/go2_walking.pkl and /dev/null differ diff --git a/examples/highlevel_ros2_interface.ipynb b/examples/highlevel_ros2_interface.ipynb deleted file mode 100644 index 9e1bb46..0000000 --- a/examples/highlevel_ros2_interface.ipynb +++ /dev/null @@ -1,156 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Joystick Control\n", - "As the first step after successfully communicating with the robot's onboard controller, we use a USB joystick (a Logitech Extreme 3D Pro) to command the robot with desired $x$, $y$, and $\\Psi$ velocities.\n", - "\n", - "First, use the Pygame-based joystick class provided with B1Py to connect to the joystick:" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "pygame 2.5.2 (SDL 2.28.2, Python 3.8.18)\n", - "Hello from the pygame community. https://www.pygame.org/contribute.html\n" - ] - } - ], - "source": [ - "from Go2Py.joy import Logitech3DPro\n", - "# joy = Logitech3DPro(joy_id=0) " - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "***Note:*** Initially when you instantiate the joystick, the class performs an offset calibration to maker sure the neutral configuration of the device reads zero. It is important to leave the device untouched during the couple of seconds after calling the cell above. The prompts tells you when you can continue. \n", - "\n", - "Then as explained in [hardware interface documentation](unitree_locomotion_controller_interface.ipynb), instantiate and communication link to high-level controller on the robot. Note that the robot should be standing and ready to walk before we can control it. Furthermore, the the highlevel node in b1py_node ROS2 package (in `deploy/ros2_ws`) should be launched on the robot. " - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "pygame 2.5.2 (SDL 2.28.2, Python 3.8.10)\n", - "Hello from the pygame community. https://www.pygame.org/contribute.html\n" - ] - } - ], - "source": [ - "from Go2Py.robot.interface.ros2 import GO2Real, ros2_init, ROS2ExecutorManager\n", - "import time\n", - "ros2_init()\n", - "robot = GO2Real(mode='highlevel')\n", - "ros2_exec_manager = ROS2ExecutorManager()\n", - "ros2_exec_manager.add_node(robot)\n", - "ros2_exec_manager.start()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Finally, read the joystick values and send them to the robot in a loop:" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "Duration = 20\n", - "N = Duration//0.01\n", - "for i in range(500):\n", - " cmd = joy.readAnalog()\n", - " vx = cmd['x']\n", - " vy = cmd['y']\n", - " w = cmd['z'] / 2\n", - " body_height = cmd['aux'] / 10\n", - " robot.setCommands(vx,vy,w, bodyHeight=body_height)\n", - " time.sleep(0.01)" - ] - }, - { - "cell_type": "code", - "execution_count": 50, - "metadata": {}, - "outputs": [], - "source": [ - "odometry = []\n", - "imus = []\n", - "joints = []\n", - "foot_contacts = []\n", - "stamps = []\n", - "\n", - "for i in range(60*200):\n", - " time.sleep(1/200)\n", - " odom = robot.getOdometry()\n", - " contact = robot.getFootContacts()\n", - " joint = robot.getJointStates()\n", - " imu = robot.getIMU()\n", - " imus.append(imu)\n", - " joints.append(joint)\n", - " foot_contacts.append(contact)\n", - " stamps.append(time.time())\n", - " odometry.append(odom)\n" - ] - }, - { - "cell_type": "code", - "execution_count": 51, - "metadata": {}, - "outputs": [], - "source": [ - "import pickle\n", - "with open('data/april16-seq2.pkl', 'wb') as f:\n", - " pickle.dump(\n", - " {\n", - " 'imu':imus,\n", - " 'odometry':odometry,\n", - " 'joints':joints,\n", - " 'foot_contacts':foot_contacts,\n", - " 'stamps':stamps\n", - " }, f\n", - " )" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.8.10" - } - }, - "nbformat": 4, - "nbformat_minor": 4 -} diff --git a/examples/isaacgym_test.py b/examples/isaacgym_test.py deleted file mode 100644 index e7d0f26..0000000 --- a/examples/isaacgym_test.py +++ /dev/null @@ -1,206 +0,0 @@ -import isaacgym - -assert isaacgym -import matplotlib.pyplot as plt -import torch -from tqdm import trange - -from Go2Py.sim.gym.envs import * -from Go2Py.sim.gym.envs.base.legged_robot_config import Cfg -from Go2Py.sim.gym.envs.go2.go2_config import config_go2 -from Go2Py.sim.gym.envs.go2.velocity_tracking import VelocityTrackingEasyEnv - - -def run_env(render=False, headless=False): - # prepare environment - config_go2(Cfg) - - Cfg.commands.num_lin_vel_bins = 30 - Cfg.commands.num_ang_vel_bins = 30 - Cfg.curriculum_thresholds.tracking_ang_vel = 0.7 - Cfg.curriculum_thresholds.tracking_lin_vel = 0.8 - Cfg.curriculum_thresholds.tracking_contacts_shaped_vel = 0.9 - Cfg.curriculum_thresholds.tracking_contacts_shaped_force = 0.9 - - Cfg.commands.distributional_commands = True - - Cfg.env.priv_observe_motion = False - Cfg.env.priv_observe_gravity_transformed_motion = True - Cfg.domain_rand.randomize_friction_indep = False - Cfg.env.priv_observe_friction_indep = False - Cfg.domain_rand.randomize_friction = True - Cfg.env.priv_observe_friction = False - Cfg.domain_rand.friction_range = [0.0, 0.0] - Cfg.domain_rand.randomize_restitution = True - Cfg.env.priv_observe_restitution = False - Cfg.domain_rand.restitution_range = [0.0, 1.0] - Cfg.domain_rand.randomize_base_mass = True - Cfg.env.priv_observe_base_mass = False - Cfg.domain_rand.added_mass_range = [-1.0, 3.0] - Cfg.domain_rand.randomize_gravity = True - Cfg.domain_rand.gravity_range = [-1.0, 1.0] - Cfg.domain_rand.gravity_rand_interval_s = 2.0 - Cfg.domain_rand.gravity_impulse_duration = 0.5 - Cfg.env.priv_observe_gravity = True - Cfg.domain_rand.randomize_com_displacement = False - Cfg.domain_rand.com_displacement_range = [-0.15, 0.15] - Cfg.env.priv_observe_com_displacement = False - Cfg.domain_rand.randomize_ground_friction = True - Cfg.env.priv_observe_ground_friction = False - Cfg.env.priv_observe_ground_friction_per_foot = False - Cfg.domain_rand.ground_friction_range = [0.3, 2.0] - Cfg.domain_rand.randomize_motor_strength = True - Cfg.domain_rand.motor_strength_range = [0.9, 1.1] - Cfg.env.priv_observe_motor_strength = False - Cfg.domain_rand.randomize_motor_offset = True - Cfg.domain_rand.motor_offset_range = [-0.02, 0.02] - Cfg.env.priv_observe_motor_offset = False - Cfg.domain_rand.push_robots = False - Cfg.domain_rand.randomize_Kp_factor = False - Cfg.env.priv_observe_Kp_factor = False - Cfg.domain_rand.randomize_Kd_factor = False - Cfg.env.priv_observe_Kd_factor = False - Cfg.env.priv_observe_body_velocity = False - Cfg.env.priv_observe_body_height = False - Cfg.env.priv_observe_desired_contact_states = False - Cfg.env.priv_observe_contact_forces = False - Cfg.env.priv_observe_foot_displacement = False - - Cfg.env.num_privileged_obs = 3 - Cfg.env.num_observation_history = 30 - Cfg.reward_scales.feet_contact_forces = 0.0 - - Cfg.domain_rand.rand_interval_s = 4 - Cfg.commands.num_commands = 15 - Cfg.env.observe_two_prev_actions = True - Cfg.env.observe_yaw = True - Cfg.env.num_observations = 71 - Cfg.env.num_scalar_observations = 71 - Cfg.env.observe_gait_commands = True - Cfg.env.observe_timing_parameter = False - Cfg.env.observe_clock_inputs = True - - Cfg.domain_rand.tile_height_range = [-0.0, 0.0] - Cfg.domain_rand.tile_height_curriculum = False - Cfg.domain_rand.tile_height_update_interval = 1000, 3000 - Cfg.domain_rand.tile_height_curriculum_step = 0.01 - Cfg.terrain.border_size = 0.0 - - Cfg.commands.resampling_time = 10 - - Cfg.reward_scales.feet_slip = -0.04 - Cfg.reward_scales.action_smoothness_1 = -0.1 - Cfg.reward_scales.action_smoothness_2 = -0.1 - Cfg.reward_scales.dof_vel = -1e-4 - Cfg.reward_scales.dof_pos = -0.05 - Cfg.reward_scales.jump = 10.0 - Cfg.reward_scales.base_height = 0.0 - Cfg.rewards.base_height_target = 0.30 - Cfg.reward_scales.estimation_bonus = 0.0 - - Cfg.reward_scales.feet_impact_vel = -0.0 - - # rewards.footswing_height = 0.09 - Cfg.reward_scales.feet_clearance = -0.0 - Cfg.reward_scales.feet_clearance_cmd = -15. - - # reward_scales.feet_contact_forces = -0.01 - - Cfg.rewards.reward_container_name = "CoRLRewards" - Cfg.rewards.only_positive_rewards = False - Cfg.rewards.only_positive_rewards_ji22_style = True - Cfg.rewards.sigma_rew_neg = 0.02 - - Cfg.reward_scales.hop_symmetry = 0.0 - Cfg.rewards.kappa_gait_probs = 0.07 - Cfg.rewards.gait_force_sigma = 100. - Cfg.rewards.gait_vel_sigma = 10. - - Cfg.reward_scales.tracking_contacts_shaped_force = 4.0 - Cfg.reward_scales.tracking_contacts_shaped_vel = 4.0 - - Cfg.reward_scales.collision = -5.0 - - Cfg.commands.lin_vel_x = [-1.0, 1.0] - Cfg.commands.lin_vel_y = [-0.6, 0.6] - Cfg.commands.ang_vel_yaw = [-1.0, 1.0] - Cfg.commands.body_height_cmd = [-0.25, 0.15] - Cfg.commands.gait_frequency_cmd_range = [1.5, 4.0] - Cfg.commands.gait_phase_cmd_range = [0.0, 1.0] - Cfg.commands.gait_offset_cmd_range = [0.0, 1.0] - Cfg.commands.gait_bound_cmd_range = [0.0, 1.0] - Cfg.commands.gait_duration_cmd_range = [0.5, 0.5] - Cfg.commands.footswing_height_range = [0.03, 0.25] - - Cfg.reward_scales.lin_vel_z = -0.02 - Cfg.reward_scales.ang_vel_xy = -0.001 - Cfg.reward_scales.base_height = 0.0 - Cfg.reward_scales.feet_air_time = 0.0 - - Cfg.commands.limit_vel_x = [-5.0, 5.0] - Cfg.commands.limit_vel_y = [-0.6, 0.6] - Cfg.commands.limit_vel_yaw = [-5.0, 5.0] - Cfg.commands.limit_body_height = [-0.25, 0.15] - Cfg.commands.limit_gait_frequency = [1.5, 4.0] - Cfg.commands.limit_gait_phase = [0.0, 1.0] - Cfg.commands.limit_gait_offset = [0.0, 1.0] - Cfg.commands.limit_gait_bound = [0.0, 1.0] - Cfg.commands.limit_gait_duration = [0.5, 0.5] - Cfg.commands.limit_footswing_height = [0.03, 0.25] - - Cfg.commands.num_bins_vel_x = 21 - Cfg.commands.num_bins_vel_y = 1 - Cfg.commands.num_bins_vel_yaw = 21 - Cfg.commands.num_bins_body_height = 1 - Cfg.commands.num_bins_gait_frequency = 1 - Cfg.commands.num_bins_gait_phase = 1 - Cfg.commands.num_bins_gait_offset = 1 - Cfg.commands.num_bins_gait_bound = 1 - Cfg.commands.num_bins_gait_duration = 1 - Cfg.commands.num_bins_footswing_height = 1 - - Cfg.normalization.friction_range = [0, 1] - Cfg.normalization.ground_friction_range = [0, 1] - - Cfg.commands.exclusive_phase_offset = False - Cfg.commands.pacing_offset = False - Cfg.commands.binary_phases = True - Cfg.commands.gaitwise_curricula = True - - # 5 times per second - - Cfg.env.num_envs = 3 - Cfg.domain_rand.push_interval_s = 1 - Cfg.terrain.num_rows = 3 - Cfg.terrain.num_cols = 5 - Cfg.terrain.border_size = 0 - Cfg.domain_rand.randomize_friction = True - Cfg.domain_rand.friction_range = [1.0, 1.01] - Cfg.domain_rand.randomize_base_mass = True - Cfg.domain_rand.added_mass_range = [0., 6.] - Cfg.terrain.terrain_noise_magnitude = 0.0 - # Cfg.asset.fix_base_link = True - - Cfg.domain_rand.lag_timesteps = 6 - Cfg.domain_rand.randomize_lag_timesteps = True - Cfg.control.control_type = "P" - - env = VelocityTrackingEasyEnv(sim_device='cuda:0', headless=False, cfg=Cfg) - env.reset() - - if render and headless: - img = env.render(mode="rgb_array") - plt.imshow(img) - plt.show() - print("Show the first frame and exit.") - exit() - - for i in trange(1000, desc="Running"): - actions = 0. * torch.ones(env.num_envs, env.num_actions, device=env.device) - obs, rew, done, info = env.step(actions) - # breakpoint() - print("Done") - - -if __name__ == '__main__': - run_env(render=True, headless=False) \ No newline at end of file diff --git a/examples/joystick_test.ipynb b/examples/joystick_test.ipynb deleted file mode 100644 index c01a456..0000000 --- a/examples/joystick_test.ipynb +++ /dev/null @@ -1,73 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "from Go2Py.robot.interface.dds import GO2Real " - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "robot = GO2Real()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "import time\n", - "while True:\n", - " time.sleep(0.1)\n", - " print(robot.getRemoteState())" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "from Go2Py.robot.remote import UnitreeRemote" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "remote = UnitreeRemote(robot)" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "b1py", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.8.18" - } - }, - "nbformat": 4, - "nbformat_minor": 2 -} diff --git a/examples/legged_inertial_ekf.ipynb b/examples/legged_inertial_ekf.ipynb deleted file mode 100644 index 8b7a2f9..0000000 --- a/examples/legged_inertial_ekf.ipynb +++ /dev/null @@ -1,3005 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# EKF Derivations" - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [], - "source": [ - "import symforce\n", - "symforce.set_symbolic_api(\"sympy\")\n", - "symforce.set_log_level(\"warning\")\n", - "import symforce.symbolic as sf\n", - "from symforce import ops\n", - "from symforce.notebook_util import display" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [], - "source": [ - "# Accelerometer and gyroscope reading\n", - "gyro = sf.Vector3.symbolic('\\omega')\n", - "accel = sf.Vector3.symbolic('a')\n", - "# Accelerometer and gyroscope bias\n", - "b_a = sf.Vector3.symbolic('b_a')\n", - "b_g = sf.Vector3.symbolic('b_g')\n", - "# Gravity in world frame\n", - "gravity = sf.Vector3([0, 0, -9.8])\n", - "# Foot positions in world frame\n", - "s1 = sf.Vector3.symbolic('s_{FR}')\n", - "s2 = sf.Vector3.symbolic('s_{FL}')\n", - "s3 = sf.Vector3.symbolic('s_{RR}')\n", - "s4 = sf.Vector3.symbolic('s_{RL}')\n", - "# Integration time interval\n", - "dT = sf.Symbol('\\Delta t')\n", - "# Body orientation, position, and velocity \n", - "q = sf.Quaternion.symbolic('q')\n", - "p = sf.Vector3.symbolic('p')\n", - "v = sf.Vector3.symbolic('v')" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [ - { - "data": { - "text/latex": [ - "$\\displaystyle \\left[\\begin{matrix}q_{x}\\\\q_{y}\\\\q_{z}\\\\q_{w}\\\\p_{0}\\\\p_{1}\\\\p_{2}\\\\v_{0}\\\\v_{1}\\\\v_{2}\\\\b_{g0}\\\\b_{g1}\\\\b_{g2}\\\\b_{a0}\\\\b_{a1}\\\\b_{a2}\\\\s_{FR}0\\\\s_{FR}1\\\\s_{FR}2\\\\s_{FL}0\\\\s_{FL}1\\\\s_{FL}2\\\\s_{RR}0\\\\s_{RR}1\\\\s_{RR}2\\\\s_{RL}0\\\\s_{RL}1\\\\s_{RL}2\\end{matrix}\\right]$" - ], - "text/plain": [ - "⎡ qₓ ⎤\n", - "⎢ ⎥\n", - "⎢ q_y ⎥\n", - "⎢ ⎥\n", - "⎢ q_z ⎥\n", - "⎢ ⎥\n", - "⎢ q_w ⎥\n", - "⎢ ⎥\n", - "⎢ p₀ ⎥\n", - "⎢ ⎥\n", - "⎢ p₁ ⎥\n", - "⎢ ⎥\n", - "⎢ p₂ ⎥\n", - "⎢ ⎥\n", - "⎢ v₀ ⎥\n", - "⎢ ⎥\n", - "⎢ v₁ ⎥\n", - "⎢ ⎥\n", - "⎢ v₂ ⎥\n", - "⎢ ⎥\n", - "⎢ b_g0 ⎥\n", - "⎢ ⎥\n", - "⎢ b_g1 ⎥\n", - "⎢ ⎥\n", - "⎢ b_g2 ⎥\n", - "⎢ ⎥\n", - "⎢ bₐ₀ ⎥\n", - "⎢ ⎥\n", - "⎢ bₐ₁ ⎥\n", - "⎢ ⎥\n", - "⎢ bₐ₂ ⎥\n", - "⎢ ⎥\n", - "⎢s_{FR}0⎥\n", - "⎢ ⎥\n", - "⎢s_{FR}1⎥\n", - "⎢ ⎥\n", - "⎢s_{FR}2⎥\n", - "⎢ ⎥\n", - "⎢s_{FL}0⎥\n", - "⎢ ⎥\n", - "⎢s_{FL}1⎥\n", - "⎢ ⎥\n", - "⎢s_{FL}2⎥\n", - "⎢ ⎥\n", - "⎢s_{RR}0⎥\n", - "⎢ ⎥\n", - "⎢s_{RR}1⎥\n", - "⎢ ⎥\n", - "⎢s_{RR}2⎥\n", - "⎢ ⎥\n", - "⎢s_{RL}0⎥\n", - "⎢ ⎥\n", - "⎢s_{RL}1⎥\n", - "⎢ ⎥\n", - "⎣s_{RL}2⎦" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "state = sf.Matrix.block_matrix([[sf.Matrix([q.x, q.y, q.z, q.w])],\\\n", - " [p],\\\n", - " [v],\\\n", - " [b_g],\\\n", - " [b_a],\\\n", - " [s1],\\\n", - " [s2],\\\n", - " [s3],\\\n", - " [s4]])\n", - "state" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": {}, - "outputs": [ - { - "data": { - "text/latex": [ - "$\\displaystyle \\left[\\begin{matrix}\\omega0\\\\\\omega1\\\\\\omega2\\\\a_{0}\\\\a_{1}\\\\a_{2}\\end{matrix}\\right]$" - ], - "text/plain": [ - "⎡\\omega0⎤\n", - "⎢ ⎥\n", - "⎢\\omega1⎥\n", - "⎢ ⎥\n", - "⎢\\omega2⎥\n", - "⎢ ⎥\n", - "⎢ a₀ ⎥\n", - "⎢ ⎥\n", - "⎢ a₁ ⎥\n", - "⎢ ⎥\n", - "⎣ a₂ ⎦" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "u = sf.Matrix.block_matrix([[gyro], [accel]])\n", - "u" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": {}, - "outputs": [], - "source": [ - "# Process Model\n", - "f1 = q*sf.Quaternion(xyz=(gyro-b_g)*dT, w = 1)\n", - "# f1 = q*sf.Rot3.from_tangent((gyro-b_g)*dT, epsilon=epsilon).q\n", - "f1 = sf.Matrix([f1.x, f1.y, f1.z, f1.w])\n", - "f2 = p+dT*v\n", - "f3 = v+sf.Rot3(q).to_rotation_matrix()*(accel-b_a)-gravity\n", - "f4 = b_g\n", - "f5 = b_a\n", - "f6 = s1\n", - "f7 = s2\n", - "f8 = s3\n", - "f9 = s4" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "metadata": {}, - "outputs": [], - "source": [ - "f = sf.Matrix.block_matrix([[f1],\\\n", - " [f2],\\\n", - " [f3],\\\n", - " [f4],\\\n", - " [f5],\\\n", - " [f6],\\\n", - " [f7],\\\n", - " [f8],\\\n", - " [f9]])" - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "metadata": {}, - "outputs": [ - { - "data": { - "text/latex": [ - "$\\displaystyle \\left[\\begin{array}{cccccccccccccccccccccccccccc}1 & \\Delta t \\left(\\omega2 - b_{g2}\\right) & - \\Delta t \\left(\\omega1 - b_{g1}\\right) & \\Delta t \\left(\\omega0 - b_{g0}\\right) & 0 & 0 & 0 & 0 & 0 & 0 & - \\Delta t q_{w} & \\Delta t q_{z} & - \\Delta t q_{y} & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0\\\\- \\Delta t \\left(\\omega2 - b_{g2}\\right) & 1 & \\Delta t \\left(\\omega0 - b_{g0}\\right) & \\Delta t \\left(\\omega1 - b_{g1}\\right) & 0 & 0 & 0 & 0 & 0 & 0 & - \\Delta t q_{z} & - \\Delta t q_{w} & \\Delta t q_{x} & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0\\\\\\Delta t \\left(\\omega1 - b_{g1}\\right) & - \\Delta t \\left(\\omega0 - b_{g0}\\right) & 1 & \\Delta t \\left(\\omega2 - b_{g2}\\right) & 0 & 0 & 0 & 0 & 0 & 0 & \\Delta t q_{y} & - \\Delta t q_{x} & - \\Delta t q_{w} & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0\\\\- \\Delta t \\left(\\omega0 - b_{g0}\\right) & - \\Delta t \\left(\\omega1 - b_{g1}\\right) & - \\Delta t \\left(\\omega2 - b_{g2}\\right) & 1 & 0 & 0 & 0 & 0 & 0 & 0 & \\Delta t q_{x} & \\Delta t q_{y} & \\Delta t q_{z} & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0\\\\0 & 0 & 0 & 0 & 1 & 0 & 0 & \\Delta t & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0\\\\0 & 0 & 0 & 0 & 0 & 1 & 0 & 0 & \\Delta t & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0\\\\0 & 0 & 0 & 0 & 0 & 0 & 1 & 0 & 0 & \\Delta t & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0\\\\2 q_{y} \\left(a_{1} - b_{a1}\\right) + 2 q_{z} \\left(a_{2} - b_{a2}\\right) & 2 q_{w} \\left(a_{2} - b_{a2}\\right) + 2 q_{x} \\left(a_{1} - b_{a1}\\right) - 4 q_{y} \\left(a_{0} - b_{a0}\\right) & - 2 q_{w} \\left(a_{1} - b_{a1}\\right) + 2 q_{x} \\left(a_{2} - b_{a2}\\right) - 4 q_{z} \\left(a_{0} - b_{a0}\\right) & 2 q_{y} \\left(a_{2} - b_{a2}\\right) - 2 q_{z} \\left(a_{1} - b_{a1}\\right) & 0 & 0 & 0 & 1 & 0 & 0 & 0 & 0 & 0 & 2 q_{y}^{2} + 2 q_{z}^{2} - 1 & 2 q_{w} q_{z} - 2 q_{x} q_{y} & - 2 q_{w} q_{y} - 2 q_{x} q_{z} & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0\\\\- 2 q_{w} \\left(a_{2} - b_{a2}\\right) - 4 q_{x} \\left(a_{1} - b_{a1}\\right) + 2 q_{y} \\left(a_{0} - b_{a0}\\right) & 2 q_{x} \\left(a_{0} - b_{a0}\\right) + 2 q_{z} \\left(a_{2} - b_{a2}\\right) & 2 q_{w} \\left(a_{0} - b_{a0}\\right) + 2 q_{y} \\left(a_{2} - b_{a2}\\right) - 4 q_{z} \\left(a_{1} - b_{a1}\\right) & - 2 q_{x} \\left(a_{2} - b_{a2}\\right) + 2 q_{z} \\left(a_{0} - b_{a0}\\right) & 0 & 0 & 0 & 0 & 1 & 0 & 0 & 0 & 0 & - 2 q_{w} q_{z} - 2 q_{x} q_{y} & 2 q_{x}^{2} + 2 q_{z}^{2} - 1 & 2 q_{w} q_{x} - 2 q_{y} q_{z} & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0\\\\2 q_{w} \\left(a_{1} - b_{a1}\\right) - 4 q_{x} \\left(a_{2} - b_{a2}\\right) + 2 q_{z} \\left(a_{0} - b_{a0}\\right) & - 2 q_{w} \\left(a_{0} - b_{a0}\\right) - 4 q_{y} \\left(a_{2} - b_{a2}\\right) + 2 q_{z} \\left(a_{1} - b_{a1}\\right) & 2 q_{x} \\left(a_{0} - b_{a0}\\right) + 2 q_{y} \\left(a_{1} - b_{a1}\\right) & 2 q_{x} \\left(a_{1} - b_{a1}\\right) - 2 q_{y} \\left(a_{0} - b_{a0}\\right) & 0 & 0 & 0 & 0 & 0 & 1 & 0 & 0 & 0 & 2 q_{w} q_{y} - 2 q_{x} q_{z} & - 2 q_{w} q_{x} - 2 q_{y} q_{z} & 2 q_{x}^{2} + 2 q_{y}^{2} - 1 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0\\\\0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 1 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0\\\\0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 1 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0\\\\0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 1 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0\\\\0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 1 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0\\\\0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 1 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0\\\\0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 1 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0\\\\0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 1 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0\\\\0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 1 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0\\\\0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 1 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0\\\\0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 1 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0\\\\0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 1 & 0 & 0 & 0 & 0 & 0 & 0 & 0\\\\0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 1 & 0 & 0 & 0 & 0 & 0 & 0\\\\0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 1 & 0 & 0 & 0 & 0 & 0\\\\0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 1 & 0 & 0 & 0 & 0\\\\0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 1 & 0 & 0 & 0\\\\0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 1 & 0 & 0\\\\0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 1 & 0\\\\0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 1\\end{array}\\right]$" - ], - "text/plain": [ - "⎡ 1 \\Delta\n", - "⎢ \n", - "⎢ -\\Delta t⋅(\\omega2 - b_g2) \n", - "⎢ \n", - "⎢ \\Delta t⋅(\\omega1 - b_g1) -\\Delta\n", - "⎢ \n", - "⎢ -\\Delta t⋅(\\omega0 - b_g0) -\\Delta\n", - "⎢ \n", - "⎢ 0 \n", - "⎢ \n", - "⎢ 0 \n", - "⎢ \n", - "⎢ 0 \n", - "⎢ \n", - "⎢ \n", - "⎢ 2⋅q_y⋅(a₁ - bₐ₁) + 2⋅q_z⋅(a₂ - bₐ₂) 2⋅q_w⋅(a₂ - bₐ₂) + 2\n", - "⎢ \n", - "⎢ \n", - "⎢-2⋅q_w⋅(a₂ - bₐ₂) - 4⋅qₓ⋅(a₁ - bₐ₁) + 2⋅q_y⋅(a₀ - bₐ₀) 2⋅qₓ⋅(a₀ - \n", - "⎢ \n", - "⎢ \n", - "⎢2⋅q_w⋅(a₁ - bₐ₁) - 4⋅qₓ⋅(a₂ - bₐ₂) + 2⋅q_z⋅(a₀ - bₐ₀) -2⋅q_w⋅(a₀ - bₐ₀) - 4\n", - "⎢ \n", - "⎢ 0 \n", - "⎢ \n", - "⎢ 0 \n", - "⎢ \n", - "⎢ 0 \n", - "⎢ \n", - "⎢ 0 \n", - "⎢ \n", - "⎢ 0 \n", - "⎢ \n", - "⎢ 0 \n", - "⎢ \n", - "⎢ 0 \n", - "⎢ \n", - "⎢ 0 \n", - "⎢ \n", - "⎢ 0 \n", - "⎢ \n", - "⎢ 0 \n", - "⎢ \n", - "⎢ 0 \n", - "⎢ \n", - "⎢ 0 \n", - "⎢ \n", - "⎢ 0 \n", - "⎢ \n", - "⎢ 0 \n", - "⎢ \n", - "⎢ 0 \n", - "⎢ \n", - "⎢ 0 \n", - "⎢ \n", - "⎢ 0 \n", - "⎢ \n", - "⎣ 0 \n", - "\n", - " t⋅(\\omega2 - b_g2) -\\Delta t⋅(\\omega1 - b_g1) \n", - " \n", - " 1 \\Delta t⋅(\\omega0 - b_g0) \n", - " \n", - " t⋅(\\omega0 - b_g0) 1 \n", - " \n", - " t⋅(\\omega1 - b_g1) -\\Delta t⋅(\\omega2 - b_g2) \n", - " \n", - " 0 0 \n", - " \n", - " 0 0 \n", - " \n", - " 0 0 \n", - " \n", - " \n", - "⋅qₓ⋅(a₁ - bₐ₁) - 4⋅q_y⋅(a₀ - bₐ₀) -2⋅q_w⋅(a₁ - bₐ₁) + 2⋅qₓ⋅(a₂ - bₐ₂) - 4⋅q_\n", - " \n", - " \n", - "bₐ₀) + 2⋅q_z⋅(a₂ - bₐ₂) 2⋅q_w⋅(a₀ - bₐ₀) + 2⋅q_y⋅(a₂ - bₐ₂) - 4⋅q_\n", - " \n", - " \n", - "⋅q_y⋅(a₂ - bₐ₂) + 2⋅q_z⋅(a₁ - bₐ₁) 2⋅qₓ⋅(a₀ - bₐ₀) + 2⋅q_y⋅(a₁ - bₐ\n", - " \n", - " 0 0 \n", - " \n", - " 0 0 \n", - " \n", - " 0 0 \n", - " \n", - " 0 0 \n", - " \n", - " 0 0 \n", - " \n", - " 0 0 \n", - " \n", - " 0 0 \n", - " \n", - " 0 0 \n", - " \n", - " 0 0 \n", - " \n", - " 0 0 \n", - " \n", - " 0 0 \n", - " \n", - " 0 0 \n", - " \n", - " 0 0 \n", - " \n", - " 0 0 \n", - " \n", - " 0 0 \n", - " \n", - " 0 0 \n", - " \n", - " 0 0 \n", - " \n", - " 0 0 \n", - "\n", - " \\Delta t⋅(\\omega0 - b_g0) 0 0 0 0 0 \n", - " \n", - " \\Delta t⋅(\\omega1 - b_g1) 0 0 0 0 0 \n", - " \n", - " \\Delta t⋅(\\omega2 - b_g2) 0 0 0 0 0 \n", - " \n", - " 1 0 0 0 0 0 \n", - " \n", - " 0 1 0 0 \\Delta t 0 \n", - " \n", - " 0 0 1 0 0 \\Delta t\n", - " \n", - " 0 0 0 1 0 0 \n", - " \n", - " \n", - "z⋅(a₀ - bₐ₀) 2⋅q_y⋅(a₂ - bₐ₂) - 2⋅q_z⋅(a₁ - bₐ₁) 0 0 0 1 0 \n", - " \n", - " \n", - "z⋅(a₁ - bₐ₁) -2⋅qₓ⋅(a₂ - bₐ₂) + 2⋅q_z⋅(a₀ - bₐ₀) 0 0 0 0 1 \n", - " \n", - " \n", - "₁) 2⋅qₓ⋅(a₁ - bₐ₁) - 2⋅q_y⋅(a₀ - bₐ₀) 0 0 0 0 0 \n", - " \n", - " 0 0 0 0 0 0 \n", - " \n", - " 0 0 0 0 0 0 \n", - " \n", - " 0 0 0 0 0 0 \n", - " \n", - " 0 0 0 0 0 0 \n", - " \n", - " 0 0 0 0 0 0 \n", - " \n", - " 0 0 0 0 0 0 \n", - " \n", - " 0 0 0 0 0 0 \n", - " \n", - " 0 0 0 0 0 0 \n", - " \n", - " 0 0 0 0 0 0 \n", - " \n", - " 0 0 0 0 0 0 \n", - " \n", - " 0 0 0 0 0 0 \n", - " \n", - " 0 0 0 0 0 0 \n", - " \n", - " 0 0 0 0 0 0 \n", - " \n", - " 0 0 0 0 0 0 \n", - " \n", - " 0 0 0 0 0 0 \n", - " \n", - " 0 0 0 0 0 0 \n", - " \n", - " 0 0 0 0 0 0 \n", - " \n", - " 0 0 0 0 0 0 \n", - "\n", - " 0 -\\Delta t⋅q_w \\Delta t⋅q_z -\\Delta t⋅q_y 0 \n", - " \n", - " 0 -\\Delta t⋅q_z -\\Delta t⋅q_w \\Delta t⋅qₓ 0 \n", - " \n", - " 0 \\Delta t⋅q_y -\\Delta t⋅qₓ -\\Delta t⋅q_w 0 \n", - " \n", - " 0 \\Delta t⋅qₓ \\Delta t⋅q_y \\Delta t⋅q_z 0 \n", - " \n", - " 0 0 0 0 0 \n", - " \n", - " 0 0 0 0 0 \n", - " \n", - " \\Delta t 0 0 0 0 \n", - " \n", - " 2 2 \n", - " 0 0 0 0 2⋅q_y + 2⋅q_z - 1 \n", - " \n", - " \n", - " 0 0 0 0 -2⋅q_w⋅q_z - 2⋅qₓ⋅q_y\n", - " \n", - " \n", - " 1 0 0 0 2⋅q_w⋅q_y - 2⋅qₓ⋅q_z \n", - " \n", - " 0 1 0 0 0 \n", - " \n", - " 0 0 1 0 0 \n", - " \n", - " 0 0 0 1 0 \n", - " \n", - " 0 0 0 0 1 \n", - " \n", - " 0 0 0 0 0 \n", - " \n", - " 0 0 0 0 0 \n", - " \n", - " 0 0 0 0 0 \n", - " \n", - " 0 0 0 0 0 \n", - " \n", - " 0 0 0 0 0 \n", - " \n", - " 0 0 0 0 0 \n", - " \n", - " 0 0 0 0 0 \n", - " \n", - " 0 0 0 0 0 \n", - " \n", - " 0 0 0 0 0 \n", - " \n", - " 0 0 0 0 0 \n", - " \n", - " 0 0 0 0 0 \n", - " \n", - " 0 0 0 0 0 \n", - " \n", - " 0 0 0 0 0 \n", - " \n", - " 0 0 0 0 0 \n", - "\n", - " 0 0 0 0 0 0 0 0 0 0 0 0 \n", - " \n", - " 0 0 0 0 0 0 0 0 0 0 0 0 \n", - " \n", - " 0 0 0 0 0 0 0 0 0 0 0 0 \n", - " \n", - " 0 0 0 0 0 0 0 0 0 0 0 0 \n", - " \n", - " 0 0 0 0 0 0 0 0 0 0 0 0 \n", - " \n", - " 0 0 0 0 0 0 0 0 0 0 0 0 \n", - " \n", - " 0 0 0 0 0 0 0 0 0 0 0 0 \n", - " \n", - " \n", - " 2⋅q_w⋅q_z - 2⋅qₓ⋅q_y -2⋅q_w⋅q_y - 2⋅qₓ⋅q_z 0 0 0 0 0 0 0 0 0 0 \n", - " \n", - " 2 2 \n", - " 2⋅qₓ + 2⋅q_z - 1 2⋅q_w⋅qₓ - 2⋅q_y⋅q_z 0 0 0 0 0 0 0 0 0 0 \n", - " \n", - " 2 2 \n", - " -2⋅q_w⋅qₓ - 2⋅q_y⋅q_z 2⋅qₓ + 2⋅q_y - 1 0 0 0 0 0 0 0 0 0 0 \n", - " \n", - " 0 0 0 0 0 0 0 0 0 0 0 0 \n", - " \n", - " 0 0 0 0 0 0 0 0 0 0 0 0 \n", - " \n", - " 0 0 0 0 0 0 0 0 0 0 0 0 \n", - " \n", - " 0 0 0 0 0 0 0 0 0 0 0 0 \n", - " \n", - " 1 0 0 0 0 0 0 0 0 0 0 0 \n", - " \n", - " 0 1 0 0 0 0 0 0 0 0 0 0 \n", - " \n", - " 0 0 1 0 0 0 0 0 0 0 0 0 \n", - " \n", - " 0 0 0 1 0 0 0 0 0 0 0 0 \n", - " \n", - " 0 0 0 0 1 0 0 0 0 0 0 0 \n", - " \n", - " 0 0 0 0 0 1 0 0 0 0 0 0 \n", - " \n", - " 0 0 0 0 0 0 1 0 0 0 0 0 \n", - " \n", - " 0 0 0 0 0 0 0 1 0 0 0 0 \n", - " \n", - " 0 0 0 0 0 0 0 0 1 0 0 0 \n", - " \n", - " 0 0 0 0 0 0 0 0 0 1 0 0 \n", - " \n", - " 0 0 0 0 0 0 0 0 0 0 1 0 \n", - " \n", - " 0 0 0 0 0 0 0 0 0 0 0 1 \n", - " \n", - " 0 0 0 0 0 0 0 0 0 0 0 0 \n", - " \n", - " 0 0 0 0 0 0 0 0 0 0 0 0 \n", - "\n", - "0 0⎤\n", - " ⎥\n", - "0 0⎥\n", - " ⎥\n", - "0 0⎥\n", - " ⎥\n", - "0 0⎥\n", - " ⎥\n", - "0 0⎥\n", - " ⎥\n", - "0 0⎥\n", - " ⎥\n", - "0 0⎥\n", - " ⎥\n", - " ⎥\n", - "0 0⎥\n", - " ⎥\n", - " ⎥\n", - "0 0⎥\n", - " ⎥\n", - " ⎥\n", - "0 0⎥\n", - " ⎥\n", - "0 0⎥\n", - " ⎥\n", - "0 0⎥\n", - " ⎥\n", - "0 0⎥\n", - " ⎥\n", - "0 0⎥\n", - " ⎥\n", - "0 0⎥\n", - " ⎥\n", - "0 0⎥\n", - " ⎥\n", - "0 0⎥\n", - " ⎥\n", - "0 0⎥\n", - " ⎥\n", - "0 0⎥\n", - " ⎥\n", - "0 0⎥\n", - " ⎥\n", - "0 0⎥\n", - " ⎥\n", - "0 0⎥\n", - " ⎥\n", - "0 0⎥\n", - " ⎥\n", - "0 0⎥\n", - " ⎥\n", - "0 0⎥\n", - " ⎥\n", - "0 0⎥\n", - " ⎥\n", - "1 0⎥\n", - " ⎥\n", - "0 1⎦" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "A_x = f.jacobian(state)\n", - "A_x " - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "metadata": {}, - "outputs": [ - { - "data": { - "text/latex": [ - "$\\displaystyle \\left[\\begin{matrix}\\Delta t q_{w} & - \\Delta t q_{z} & \\Delta t q_{y} & 0 & 0 & 0\\\\\\Delta t q_{z} & \\Delta t q_{w} & - \\Delta t q_{x} & 0 & 0 & 0\\\\- \\Delta t q_{y} & \\Delta t q_{x} & \\Delta t q_{w} & 0 & 0 & 0\\\\- \\Delta t q_{x} & - \\Delta t q_{y} & - \\Delta t q_{z} & 0 & 0 & 0\\\\0 & 0 & 0 & 0 & 0 & 0\\\\0 & 0 & 0 & 0 & 0 & 0\\\\0 & 0 & 0 & 0 & 0 & 0\\\\0 & 0 & 0 & - 2 q_{y}^{2} - 2 q_{z}^{2} + 1 & - 2 q_{w} q_{z} + 2 q_{x} q_{y} & 2 q_{w} q_{y} + 2 q_{x} q_{z}\\\\0 & 0 & 0 & 2 q_{w} q_{z} + 2 q_{x} q_{y} & - 2 q_{x}^{2} - 2 q_{z}^{2} + 1 & - 2 q_{w} q_{x} + 2 q_{y} q_{z}\\\\0 & 0 & 0 & - 2 q_{w} q_{y} + 2 q_{x} q_{z} & 2 q_{w} q_{x} + 2 q_{y} q_{z} & - 2 q_{x}^{2} - 2 q_{y}^{2} + 1\\\\0 & 0 & 0 & 0 & 0 & 0\\\\0 & 0 & 0 & 0 & 0 & 0\\\\0 & 0 & 0 & 0 & 0 & 0\\\\0 & 0 & 0 & 0 & 0 & 0\\\\0 & 0 & 0 & 0 & 0 & 0\\\\0 & 0 & 0 & 0 & 0 & 0\\\\0 & 0 & 0 & 0 & 0 & 0\\\\0 & 0 & 0 & 0 & 0 & 0\\\\0 & 0 & 0 & 0 & 0 & 0\\\\0 & 0 & 0 & 0 & 0 & 0\\\\0 & 0 & 0 & 0 & 0 & 0\\\\0 & 0 & 0 & 0 & 0 & 0\\\\0 & 0 & 0 & 0 & 0 & 0\\\\0 & 0 & 0 & 0 & 0 & 0\\\\0 & 0 & 0 & 0 & 0 & 0\\\\0 & 0 & 0 & 0 & 0 & 0\\\\0 & 0 & 0 & 0 & 0 & 0\\\\0 & 0 & 0 & 0 & 0 & 0\\end{matrix}\\right]$" - ], - "text/plain": [ - "⎡\\Delta t⋅q_w -\\Delta t⋅q_z \\Delta t⋅q_y 0 \n", - "⎢ \n", - "⎢\\Delta t⋅q_z \\Delta t⋅q_w -\\Delta t⋅qₓ 0 \n", - "⎢ \n", - "⎢-\\Delta t⋅q_y \\Delta t⋅qₓ \\Delta t⋅q_w 0 \n", - "⎢ \n", - "⎢-\\Delta t⋅qₓ -\\Delta t⋅q_y -\\Delta t⋅q_z 0 \n", - "⎢ \n", - "⎢ 0 0 0 0 \n", - "⎢ \n", - "⎢ 0 0 0 0 \n", - "⎢ \n", - "⎢ 0 0 0 0 \n", - "⎢ \n", - "⎢ 2 2 \n", - "⎢ 0 0 0 - 2⋅q_y - 2⋅q_z + 1 -2⋅q_w⋅q_\n", - "⎢ \n", - "⎢ 2 \n", - "⎢ 0 0 0 2⋅q_w⋅q_z + 2⋅qₓ⋅q_y - 2⋅qₓ -\n", - "⎢ \n", - "⎢ \n", - "⎢ 0 0 0 -2⋅q_w⋅q_y + 2⋅qₓ⋅q_z 2⋅q_w⋅qₓ \n", - "⎢ \n", - "⎢ 0 0 0 0 \n", - "⎢ \n", - "⎢ 0 0 0 0 \n", - "⎢ \n", - "⎢ 0 0 0 0 \n", - "⎢ \n", - "⎢ 0 0 0 0 \n", - "⎢ \n", - "⎢ 0 0 0 0 \n", - "⎢ \n", - "⎢ 0 0 0 0 \n", - "⎢ \n", - "⎢ 0 0 0 0 \n", - "⎢ \n", - "⎢ 0 0 0 0 \n", - "⎢ \n", - "⎢ 0 0 0 0 \n", - "⎢ \n", - "⎢ 0 0 0 0 \n", - "⎢ \n", - "⎢ 0 0 0 0 \n", - "⎢ \n", - "⎢ 0 0 0 0 \n", - "⎢ \n", - "⎢ 0 0 0 0 \n", - "⎢ \n", - "⎢ 0 0 0 0 \n", - "⎢ \n", - "⎢ 0 0 0 0 \n", - "⎢ \n", - "⎢ 0 0 0 0 \n", - "⎢ \n", - "⎢ 0 0 0 0 \n", - "⎢ \n", - "⎣ 0 0 0 0 \n", - "\n", - " 0 0 ⎤\n", - " ⎥\n", - " 0 0 ⎥\n", - " ⎥\n", - " 0 0 ⎥\n", - " ⎥\n", - " 0 0 ⎥\n", - " ⎥\n", - " 0 0 ⎥\n", - " ⎥\n", - " 0 0 ⎥\n", - " ⎥\n", - " 0 0 ⎥\n", - " ⎥\n", - " ⎥\n", - "z + 2⋅qₓ⋅q_y 2⋅q_w⋅q_y + 2⋅qₓ⋅q_z ⎥\n", - " ⎥\n", - " 2 ⎥\n", - " 2⋅q_z + 1 -2⋅q_w⋅qₓ + 2⋅q_y⋅q_z⎥\n", - " ⎥\n", - " 2 2 ⎥\n", - "+ 2⋅q_y⋅q_z - 2⋅qₓ - 2⋅q_y + 1 ⎥\n", - " ⎥\n", - " 0 0 ⎥\n", - " ⎥\n", - " 0 0 ⎥\n", - " ⎥\n", - " 0 0 ⎥\n", - " ⎥\n", - " 0 0 ⎥\n", - " ⎥\n", - " 0 0 ⎥\n", - " ⎥\n", - " 0 0 ⎥\n", - " ⎥\n", - " 0 0 ⎥\n", - " ⎥\n", - " 0 0 ⎥\n", - " ⎥\n", - " 0 0 ⎥\n", - " ⎥\n", - " 0 0 ⎥\n", - " ⎥\n", - " 0 0 ⎥\n", - " ⎥\n", - " 0 0 ⎥\n", - " ⎥\n", - " 0 0 ⎥\n", - " ⎥\n", - " 0 0 ⎥\n", - " ⎥\n", - " 0 0 ⎥\n", - " ⎥\n", - " 0 0 ⎥\n", - " ⎥\n", - " 0 0 ⎥\n", - " ⎥\n", - " 0 0 ⎦" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "A_u = f.jacobian(u)\n", - "A_u" - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "metadata": {}, - "outputs": [ - { - "data": { - "text/latex": [ - "$\\displaystyle \\left[\\begin{matrix}v_{0} \\left(- 2 q_{y}^{2} - 2 q_{z}^{2} + 1\\right) + v_{1} \\cdot \\left(2 q_{w} q_{z} + 2 q_{x} q_{y}\\right) + v_{2} \\left(- 2 q_{w} q_{y} + 2 q_{x} q_{z}\\right)\\\\v_{0} \\left(- 2 q_{w} q_{z} + 2 q_{x} q_{y}\\right) + v_{1} \\left(- 2 q_{x}^{2} - 2 q_{z}^{2} + 1\\right) + v_{2} \\cdot \\left(2 q_{w} q_{x} + 2 q_{y} q_{z}\\right)\\\\v_{0} \\cdot \\left(2 q_{w} q_{y} + 2 q_{x} q_{z}\\right) + v_{1} \\left(- 2 q_{w} q_{x} + 2 q_{y} q_{z}\\right) + v_{2} \\left(- 2 q_{x}^{2} - 2 q_{y}^{2} + 1\\right)\\\\\\left(- p_{0} + s_{FR}0\\right) \\left(- 2 q_{y}^{2} - 2 q_{z}^{2} + 1\\right) + \\left(- p_{1} + s_{FR}1\\right) \\left(2 q_{w} q_{z} + 2 q_{x} q_{y}\\right) + \\left(- p_{2} + s_{FR}2\\right) \\left(- 2 q_{w} q_{y} + 2 q_{x} q_{z}\\right)\\\\\\left(- p_{0} + s_{FR}0\\right) \\left(- 2 q_{w} q_{z} + 2 q_{x} q_{y}\\right) + \\left(- p_{1} + s_{FR}1\\right) \\left(- 2 q_{x}^{2} - 2 q_{z}^{2} + 1\\right) + \\left(- p_{2} + s_{FR}2\\right) \\left(2 q_{w} q_{x} + 2 q_{y} q_{z}\\right)\\\\\\left(- p_{0} + s_{FR}0\\right) \\left(2 q_{w} q_{y} + 2 q_{x} q_{z}\\right) + \\left(- p_{1} + s_{FR}1\\right) \\left(- 2 q_{w} q_{x} + 2 q_{y} q_{z}\\right) + \\left(- p_{2} + s_{FR}2\\right) \\left(- 2 q_{x}^{2} - 2 q_{y}^{2} + 1\\right)\\\\\\left(- p_{0} + s_{FL}0\\right) \\left(- 2 q_{y}^{2} - 2 q_{z}^{2} + 1\\right) + \\left(- p_{1} + s_{FL}1\\right) \\left(2 q_{w} q_{z} + 2 q_{x} q_{y}\\right) + \\left(- p_{2} + s_{FL}2\\right) \\left(- 2 q_{w} q_{y} + 2 q_{x} q_{z}\\right)\\\\\\left(- p_{0} + s_{FL}0\\right) \\left(- 2 q_{w} q_{z} + 2 q_{x} q_{y}\\right) + \\left(- p_{1} + s_{FL}1\\right) \\left(- 2 q_{x}^{2} - 2 q_{z}^{2} + 1\\right) + \\left(- p_{2} + s_{FL}2\\right) \\left(2 q_{w} q_{x} + 2 q_{y} q_{z}\\right)\\\\\\left(- p_{0} + s_{FL}0\\right) \\left(2 q_{w} q_{y} + 2 q_{x} q_{z}\\right) + \\left(- p_{1} + s_{FL}1\\right) \\left(- 2 q_{w} q_{x} + 2 q_{y} q_{z}\\right) + \\left(- p_{2} + s_{FL}2\\right) \\left(- 2 q_{x}^{2} - 2 q_{y}^{2} + 1\\right)\\\\\\left(- p_{0} + s_{RR}0\\right) \\left(- 2 q_{y}^{2} - 2 q_{z}^{2} + 1\\right) + \\left(- p_{1} + s_{RR}1\\right) \\left(2 q_{w} q_{z} + 2 q_{x} q_{y}\\right) + \\left(- p_{2} + s_{RR}2\\right) \\left(- 2 q_{w} q_{y} + 2 q_{x} q_{z}\\right)\\\\\\left(- p_{0} + s_{RR}0\\right) \\left(- 2 q_{w} q_{z} + 2 q_{x} q_{y}\\right) + \\left(- p_{1} + s_{RR}1\\right) \\left(- 2 q_{x}^{2} - 2 q_{z}^{2} + 1\\right) + \\left(- p_{2} + s_{RR}2\\right) \\left(2 q_{w} q_{x} + 2 q_{y} q_{z}\\right)\\\\\\left(- p_{0} + s_{RR}0\\right) \\left(2 q_{w} q_{y} + 2 q_{x} q_{z}\\right) + \\left(- p_{1} + s_{RR}1\\right) \\left(- 2 q_{w} q_{x} + 2 q_{y} q_{z}\\right) + \\left(- p_{2} + s_{RR}2\\right) \\left(- 2 q_{x}^{2} - 2 q_{y}^{2} + 1\\right)\\\\\\left(- p_{0} + s_{RL}0\\right) \\left(- 2 q_{y}^{2} - 2 q_{z}^{2} + 1\\right) + \\left(- p_{1} + s_{RL}1\\right) \\left(2 q_{w} q_{z} + 2 q_{x} q_{y}\\right) + \\left(- p_{2} + s_{RL}2\\right) \\left(- 2 q_{w} q_{y} + 2 q_{x} q_{z}\\right)\\\\\\left(- p_{0} + s_{RL}0\\right) \\left(- 2 q_{w} q_{z} + 2 q_{x} q_{y}\\right) + \\left(- p_{1} + s_{RL}1\\right) \\left(- 2 q_{x}^{2} - 2 q_{z}^{2} + 1\\right) + \\left(- p_{2} + s_{RL}2\\right) \\left(2 q_{w} q_{x} + 2 q_{y} q_{z}\\right)\\\\\\left(- p_{0} + s_{RL}0\\right) \\left(2 q_{w} q_{y} + 2 q_{x} q_{z}\\right) + \\left(- p_{1} + s_{RL}1\\right) \\left(- 2 q_{w} q_{x} + 2 q_{y} q_{z}\\right) + \\left(- p_{2} + s_{RL}2\\right) \\left(- 2 q_{x}^{2} - 2 q_{y}^{2} + 1\\right)\\end{matrix}\\right]$" - ], - "text/plain": [ - "⎡ ⎛ 2 2 ⎞ \n", - "⎢ v₀⋅⎝- 2⋅q_y - 2⋅q_z + 1⎠ + v₁⋅(2⋅q_w⋅q_z + 2⋅qₓ⋅q_y) + v\n", - "⎢ \n", - "⎢ ⎛ 2 2 ⎞ \n", - "⎢ v₀⋅(-2⋅q_w⋅q_z + 2⋅qₓ⋅q_y) + v₁⋅⎝- 2⋅qₓ - 2⋅q_z + 1⎠ + \n", - "⎢ \n", - "⎢ \n", - "⎢ v₀⋅(2⋅q_w⋅q_y + 2⋅qₓ⋅q_z) + v₁⋅(-2⋅q_w⋅qₓ + 2⋅q_y⋅q_z) + \n", - "⎢ \n", - "⎢ ⎛ 2 2 ⎞ \n", - "⎢(-p₀ + s_{FR}0)⋅⎝- 2⋅q_y - 2⋅q_z + 1⎠ + (-p₁ + s_{FR}1)⋅(2⋅q_w⋅q_z + 2⋅qₓ⋅q\n", - "⎢ \n", - "⎢ ⎛ 2 2 \n", - "⎢(-p₀ + s_{FR}0)⋅(-2⋅q_w⋅q_z + 2⋅qₓ⋅q_y) + (-p₁ + s_{FR}1)⋅⎝- 2⋅qₓ - 2⋅q_z +\n", - "⎢ \n", - "⎢ \n", - "⎢(-p₀ + s_{FR}0)⋅(2⋅q_w⋅q_y + 2⋅qₓ⋅q_z) + (-p₁ + s_{FR}1)⋅(-2⋅q_w⋅qₓ + 2⋅q_y⋅q\n", - "⎢ \n", - "⎢ ⎛ 2 2 ⎞ \n", - "⎢(-p₀ + s_{FL}0)⋅⎝- 2⋅q_y - 2⋅q_z + 1⎠ + (-p₁ + s_{FL}1)⋅(2⋅q_w⋅q_z + 2⋅qₓ⋅q\n", - "⎢ \n", - "⎢ ⎛ 2 2 \n", - "⎢(-p₀ + s_{FL}0)⋅(-2⋅q_w⋅q_z + 2⋅qₓ⋅q_y) + (-p₁ + s_{FL}1)⋅⎝- 2⋅qₓ - 2⋅q_z +\n", - "⎢ \n", - "⎢ \n", - "⎢(-p₀ + s_{FL}0)⋅(2⋅q_w⋅q_y + 2⋅qₓ⋅q_z) + (-p₁ + s_{FL}1)⋅(-2⋅q_w⋅qₓ + 2⋅q_y⋅q\n", - "⎢ \n", - "⎢ ⎛ 2 2 ⎞ \n", - "⎢(-p₀ + s_{RR}0)⋅⎝- 2⋅q_y - 2⋅q_z + 1⎠ + (-p₁ + s_{RR}1)⋅(2⋅q_w⋅q_z + 2⋅qₓ⋅q\n", - "⎢ \n", - "⎢ ⎛ 2 2 \n", - "⎢(-p₀ + s_{RR}0)⋅(-2⋅q_w⋅q_z + 2⋅qₓ⋅q_y) + (-p₁ + s_{RR}1)⋅⎝- 2⋅qₓ - 2⋅q_z +\n", - "⎢ \n", - "⎢ \n", - "⎢(-p₀ + s_{RR}0)⋅(2⋅q_w⋅q_y + 2⋅qₓ⋅q_z) + (-p₁ + s_{RR}1)⋅(-2⋅q_w⋅qₓ + 2⋅q_y⋅q\n", - "⎢ \n", - "⎢ ⎛ 2 2 ⎞ \n", - "⎢(-p₀ + s_{RL}0)⋅⎝- 2⋅q_y - 2⋅q_z + 1⎠ + (-p₁ + s_{RL}1)⋅(2⋅q_w⋅q_z + 2⋅qₓ⋅q\n", - "⎢ \n", - "⎢ ⎛ 2 2 \n", - "⎢(-p₀ + s_{RL}0)⋅(-2⋅q_w⋅q_z + 2⋅qₓ⋅q_y) + (-p₁ + s_{RL}1)⋅⎝- 2⋅qₓ - 2⋅q_z +\n", - "⎢ \n", - "⎢ \n", - "⎣(-p₀ + s_{RL}0)⋅(2⋅q_w⋅q_y + 2⋅qₓ⋅q_z) + (-p₁ + s_{RL}1)⋅(-2⋅q_w⋅qₓ + 2⋅q_y⋅q\n", - "\n", - " ⎤\n", - "₂⋅(-2⋅q_w⋅q_y + 2⋅qₓ⋅q_z) ⎥\n", - " ⎥\n", - " ⎥\n", - "v₂⋅(2⋅q_w⋅qₓ + 2⋅q_y⋅q_z) ⎥\n", - " ⎥\n", - " ⎛ 2 2 ⎞ ⎥\n", - "v₂⋅⎝- 2⋅qₓ - 2⋅q_y + 1⎠ ⎥\n", - " ⎥\n", - " ⎥\n", - "_y) + (-p₂ + s_{FR}2)⋅(-2⋅q_w⋅q_y + 2⋅qₓ⋅q_z)⎥\n", - " ⎥\n", - " ⎞ ⎥\n", - " 1⎠ + (-p₂ + s_{FR}2)⋅(2⋅q_w⋅qₓ + 2⋅q_y⋅q_z) ⎥\n", - " ⎥\n", - " ⎛ 2 2 ⎞ ⎥\n", - "_z) + (-p₂ + s_{FR}2)⋅⎝- 2⋅qₓ - 2⋅q_y + 1⎠ ⎥\n", - " ⎥\n", - " ⎥\n", - "_y) + (-p₂ + s_{FL}2)⋅(-2⋅q_w⋅q_y + 2⋅qₓ⋅q_z)⎥\n", - " ⎥\n", - " ⎞ ⎥\n", - " 1⎠ + (-p₂ + s_{FL}2)⋅(2⋅q_w⋅qₓ + 2⋅q_y⋅q_z) ⎥\n", - " ⎥\n", - " ⎛ 2 2 ⎞ ⎥\n", - "_z) + (-p₂ + s_{FL}2)⋅⎝- 2⋅qₓ - 2⋅q_y + 1⎠ ⎥\n", - " ⎥\n", - " ⎥\n", - "_y) + (-p₂ + s_{RR}2)⋅(-2⋅q_w⋅q_y + 2⋅qₓ⋅q_z)⎥\n", - " ⎥\n", - " ⎞ ⎥\n", - " 1⎠ + (-p₂ + s_{RR}2)⋅(2⋅q_w⋅qₓ + 2⋅q_y⋅q_z) ⎥\n", - " ⎥\n", - " ⎛ 2 2 ⎞ ⎥\n", - "_z) + (-p₂ + s_{RR}2)⋅⎝- 2⋅qₓ - 2⋅q_y + 1⎠ ⎥\n", - " ⎥\n", - " ⎥\n", - "_y) + (-p₂ + s_{RL}2)⋅(-2⋅q_w⋅q_y + 2⋅qₓ⋅q_z)⎥\n", - " ⎥\n", - " ⎞ ⎥\n", - " 1⎠ + (-p₂ + s_{RL}2)⋅(2⋅q_w⋅qₓ + 2⋅q_y⋅q_z) ⎥\n", - " ⎥\n", - " ⎛ 2 2 ⎞ ⎥\n", - "_z) + (-p₂ + s_{RL}2)⋅⎝- 2⋅qₓ - 2⋅q_y + 1⎠ ⎦" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "#Measurement model\n", - "R = sf.Rot3(q).to_rotation_matrix()\n", - "z1 = R.T*v\n", - "z2 = R.T*(s1-p)\n", - "z3 = R.T*(s2-p)\n", - "z4 = R.T*(s3-p)\n", - "z5 = R.T*(s4-p)\n", - "h = sf.Matrix.block_matrix([[z1],\n", - " [z2],\n", - " [z3],\n", - " [z4],\n", - " [z5]])\n", - "h" - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "metadata": {}, - "outputs": [ - { - "data": { - "text/latex": [ - "$\\displaystyle \\left[\\begin{array}{cccccccccccccccccccccccccccc}2 q_{y} v_{1} + 2 q_{z} v_{2} & - 2 q_{w} v_{2} + 2 q_{x} v_{1} - 4 q_{y} v_{0} & 2 q_{w} v_{1} + 2 q_{x} v_{2} - 4 q_{z} v_{0} & - 2 q_{y} v_{2} + 2 q_{z} v_{1} & 0 & 0 & 0 & - 2 q_{y}^{2} - 2 q_{z}^{2} + 1 & 2 q_{w} q_{z} + 2 q_{x} q_{y} & - 2 q_{w} q_{y} + 2 q_{x} q_{z} & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0\\\\2 q_{w} v_{2} - 4 q_{x} v_{1} + 2 q_{y} v_{0} & 2 q_{x} v_{0} + 2 q_{z} v_{2} & - 2 q_{w} v_{0} + 2 q_{y} v_{2} - 4 q_{z} v_{1} & 2 q_{x} v_{2} - 2 q_{z} v_{0} & 0 & 0 & 0 & - 2 q_{w} q_{z} + 2 q_{x} q_{y} & - 2 q_{x}^{2} - 2 q_{z}^{2} + 1 & 2 q_{w} q_{x} + 2 q_{y} q_{z} & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0\\\\- 2 q_{w} v_{1} - 4 q_{x} v_{2} + 2 q_{z} v_{0} & 2 q_{w} v_{0} - 4 q_{y} v_{2} + 2 q_{z} v_{1} & 2 q_{x} v_{0} + 2 q_{y} v_{1} & - 2 q_{x} v_{1} + 2 q_{y} v_{0} & 0 & 0 & 0 & 2 q_{w} q_{y} + 2 q_{x} q_{z} & - 2 q_{w} q_{x} + 2 q_{y} q_{z} & - 2 q_{x}^{2} - 2 q_{y}^{2} + 1 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0\\\\2 q_{y} \\left(- p_{1} + s_{FR}1\\right) + 2 q_{z} \\left(- p_{2} + s_{FR}2\\right) & - 2 q_{w} \\left(- p_{2} + s_{FR}2\\right) + 2 q_{x} \\left(- p_{1} + s_{FR}1\\right) - 4 q_{y} \\left(- p_{0} + s_{FR}0\\right) & 2 q_{w} \\left(- p_{1} + s_{FR}1\\right) + 2 q_{x} \\left(- p_{2} + s_{FR}2\\right) - 4 q_{z} \\left(- p_{0} + s_{FR}0\\right) & - 2 q_{y} \\left(- p_{2} + s_{FR}2\\right) + 2 q_{z} \\left(- p_{1} + s_{FR}1\\right) & 2 q_{y}^{2} + 2 q_{z}^{2} - 1 & - 2 q_{w} q_{z} - 2 q_{x} q_{y} & 2 q_{w} q_{y} - 2 q_{x} q_{z} & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & - 2 q_{y}^{2} - 2 q_{z}^{2} + 1 & 2 q_{w} q_{z} + 2 q_{x} q_{y} & - 2 q_{w} q_{y} + 2 q_{x} q_{z} & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0\\\\2 q_{w} \\left(- p_{2} + s_{FR}2\\right) - 4 q_{x} \\left(- p_{1} + s_{FR}1\\right) + 2 q_{y} \\left(- p_{0} + s_{FR}0\\right) & 2 q_{x} \\left(- p_{0} + s_{FR}0\\right) + 2 q_{z} \\left(- p_{2} + s_{FR}2\\right) & - 2 q_{w} \\left(- p_{0} + s_{FR}0\\right) + 2 q_{y} \\left(- p_{2} + s_{FR}2\\right) - 4 q_{z} \\left(- p_{1} + s_{FR}1\\right) & 2 q_{x} \\left(- p_{2} + s_{FR}2\\right) - 2 q_{z} \\left(- p_{0} + s_{FR}0\\right) & 2 q_{w} q_{z} - 2 q_{x} q_{y} & 2 q_{x}^{2} + 2 q_{z}^{2} - 1 & - 2 q_{w} q_{x} - 2 q_{y} q_{z} & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & - 2 q_{w} q_{z} + 2 q_{x} q_{y} & - 2 q_{x}^{2} - 2 q_{z}^{2} + 1 & 2 q_{w} q_{x} + 2 q_{y} q_{z} & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0\\\\- 2 q_{w} \\left(- p_{1} + s_{FR}1\\right) - 4 q_{x} \\left(- p_{2} + s_{FR}2\\right) + 2 q_{z} \\left(- p_{0} + s_{FR}0\\right) & 2 q_{w} \\left(- p_{0} + s_{FR}0\\right) - 4 q_{y} \\left(- p_{2} + s_{FR}2\\right) + 2 q_{z} \\left(- p_{1} + s_{FR}1\\right) & 2 q_{x} \\left(- p_{0} + s_{FR}0\\right) + 2 q_{y} \\left(- p_{1} + s_{FR}1\\right) & - 2 q_{x} \\left(- p_{1} + s_{FR}1\\right) + 2 q_{y} \\left(- p_{0} + s_{FR}0\\right) & - 2 q_{w} q_{y} - 2 q_{x} q_{z} & 2 q_{w} q_{x} - 2 q_{y} q_{z} & 2 q_{x}^{2} + 2 q_{y}^{2} - 1 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 2 q_{w} q_{y} + 2 q_{x} q_{z} & - 2 q_{w} q_{x} + 2 q_{y} q_{z} & - 2 q_{x}^{2} - 2 q_{y}^{2} + 1 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0\\\\2 q_{y} \\left(- p_{1} + s_{FL}1\\right) + 2 q_{z} \\left(- p_{2} + s_{FL}2\\right) & - 2 q_{w} \\left(- p_{2} + s_{FL}2\\right) + 2 q_{x} \\left(- p_{1} + s_{FL}1\\right) - 4 q_{y} \\left(- p_{0} + s_{FL}0\\right) & 2 q_{w} \\left(- p_{1} + s_{FL}1\\right) + 2 q_{x} \\left(- p_{2} + s_{FL}2\\right) - 4 q_{z} \\left(- p_{0} + s_{FL}0\\right) & - 2 q_{y} \\left(- p_{2} + s_{FL}2\\right) + 2 q_{z} \\left(- p_{1} + s_{FL}1\\right) & 2 q_{y}^{2} + 2 q_{z}^{2} - 1 & - 2 q_{w} q_{z} - 2 q_{x} q_{y} & 2 q_{w} q_{y} - 2 q_{x} q_{z} & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & - 2 q_{y}^{2} - 2 q_{z}^{2} + 1 & 2 q_{w} q_{z} + 2 q_{x} q_{y} & - 2 q_{w} q_{y} + 2 q_{x} q_{z} & 0 & 0 & 0 & 0 & 0 & 0\\\\2 q_{w} \\left(- p_{2} + s_{FL}2\\right) - 4 q_{x} \\left(- p_{1} + s_{FL}1\\right) + 2 q_{y} \\left(- p_{0} + s_{FL}0\\right) & 2 q_{x} \\left(- p_{0} + s_{FL}0\\right) + 2 q_{z} \\left(- p_{2} + s_{FL}2\\right) & - 2 q_{w} \\left(- p_{0} + s_{FL}0\\right) + 2 q_{y} \\left(- p_{2} + s_{FL}2\\right) - 4 q_{z} \\left(- p_{1} + s_{FL}1\\right) & 2 q_{x} \\left(- p_{2} + s_{FL}2\\right) - 2 q_{z} \\left(- p_{0} + s_{FL}0\\right) & 2 q_{w} q_{z} - 2 q_{x} q_{y} & 2 q_{x}^{2} + 2 q_{z}^{2} - 1 & - 2 q_{w} q_{x} - 2 q_{y} q_{z} & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & - 2 q_{w} q_{z} + 2 q_{x} q_{y} & - 2 q_{x}^{2} - 2 q_{z}^{2} + 1 & 2 q_{w} q_{x} + 2 q_{y} q_{z} & 0 & 0 & 0 & 0 & 0 & 0\\\\- 2 q_{w} \\left(- p_{1} + s_{FL}1\\right) - 4 q_{x} \\left(- p_{2} + s_{FL}2\\right) + 2 q_{z} \\left(- p_{0} + s_{FL}0\\right) & 2 q_{w} \\left(- p_{0} + s_{FL}0\\right) - 4 q_{y} \\left(- p_{2} + s_{FL}2\\right) + 2 q_{z} \\left(- p_{1} + s_{FL}1\\right) & 2 q_{x} \\left(- p_{0} + s_{FL}0\\right) + 2 q_{y} \\left(- p_{1} + s_{FL}1\\right) & - 2 q_{x} \\left(- p_{1} + s_{FL}1\\right) + 2 q_{y} \\left(- p_{0} + s_{FL}0\\right) & - 2 q_{w} q_{y} - 2 q_{x} q_{z} & 2 q_{w} q_{x} - 2 q_{y} q_{z} & 2 q_{x}^{2} + 2 q_{y}^{2} - 1 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 2 q_{w} q_{y} + 2 q_{x} q_{z} & - 2 q_{w} q_{x} + 2 q_{y} q_{z} & - 2 q_{x}^{2} - 2 q_{y}^{2} + 1 & 0 & 0 & 0 & 0 & 0 & 0\\\\2 q_{y} \\left(- p_{1} + s_{RR}1\\right) + 2 q_{z} \\left(- p_{2} + s_{RR}2\\right) & - 2 q_{w} \\left(- p_{2} + s_{RR}2\\right) + 2 q_{x} \\left(- p_{1} + s_{RR}1\\right) - 4 q_{y} \\left(- p_{0} + s_{RR}0\\right) & 2 q_{w} \\left(- p_{1} + s_{RR}1\\right) + 2 q_{x} \\left(- p_{2} + s_{RR}2\\right) - 4 q_{z} \\left(- p_{0} + s_{RR}0\\right) & - 2 q_{y} \\left(- p_{2} + s_{RR}2\\right) + 2 q_{z} \\left(- p_{1} + s_{RR}1\\right) & 2 q_{y}^{2} + 2 q_{z}^{2} - 1 & - 2 q_{w} q_{z} - 2 q_{x} q_{y} & 2 q_{w} q_{y} - 2 q_{x} q_{z} & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & - 2 q_{y}^{2} - 2 q_{z}^{2} + 1 & 2 q_{w} q_{z} + 2 q_{x} q_{y} & - 2 q_{w} q_{y} + 2 q_{x} q_{z} & 0 & 0 & 0\\\\2 q_{w} \\left(- p_{2} + s_{RR}2\\right) - 4 q_{x} \\left(- p_{1} + s_{RR}1\\right) + 2 q_{y} \\left(- p_{0} + s_{RR}0\\right) & 2 q_{x} \\left(- p_{0} + s_{RR}0\\right) + 2 q_{z} \\left(- p_{2} + s_{RR}2\\right) & - 2 q_{w} \\left(- p_{0} + s_{RR}0\\right) + 2 q_{y} \\left(- p_{2} + s_{RR}2\\right) - 4 q_{z} \\left(- p_{1} + s_{RR}1\\right) & 2 q_{x} \\left(- p_{2} + s_{RR}2\\right) - 2 q_{z} \\left(- p_{0} + s_{RR}0\\right) & 2 q_{w} q_{z} - 2 q_{x} q_{y} & 2 q_{x}^{2} + 2 q_{z}^{2} - 1 & - 2 q_{w} q_{x} - 2 q_{y} q_{z} & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & - 2 q_{w} q_{z} + 2 q_{x} q_{y} & - 2 q_{x}^{2} - 2 q_{z}^{2} + 1 & 2 q_{w} q_{x} + 2 q_{y} q_{z} & 0 & 0 & 0\\\\- 2 q_{w} \\left(- p_{1} + s_{RR}1\\right) - 4 q_{x} \\left(- p_{2} + s_{RR}2\\right) + 2 q_{z} \\left(- p_{0} + s_{RR}0\\right) & 2 q_{w} \\left(- p_{0} + s_{RR}0\\right) - 4 q_{y} \\left(- p_{2} + s_{RR}2\\right) + 2 q_{z} \\left(- p_{1} + s_{RR}1\\right) & 2 q_{x} \\left(- p_{0} + s_{RR}0\\right) + 2 q_{y} \\left(- p_{1} + s_{RR}1\\right) & - 2 q_{x} \\left(- p_{1} + s_{RR}1\\right) + 2 q_{y} \\left(- p_{0} + s_{RR}0\\right) & - 2 q_{w} q_{y} - 2 q_{x} q_{z} & 2 q_{w} q_{x} - 2 q_{y} q_{z} & 2 q_{x}^{2} + 2 q_{y}^{2} - 1 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 2 q_{w} q_{y} + 2 q_{x} q_{z} & - 2 q_{w} q_{x} + 2 q_{y} q_{z} & - 2 q_{x}^{2} - 2 q_{y}^{2} + 1 & 0 & 0 & 0\\\\2 q_{y} \\left(- p_{1} + s_{RL}1\\right) + 2 q_{z} \\left(- p_{2} + s_{RL}2\\right) & - 2 q_{w} \\left(- p_{2} + s_{RL}2\\right) + 2 q_{x} \\left(- p_{1} + s_{RL}1\\right) - 4 q_{y} \\left(- p_{0} + s_{RL}0\\right) & 2 q_{w} \\left(- p_{1} + s_{RL}1\\right) + 2 q_{x} \\left(- p_{2} + s_{RL}2\\right) - 4 q_{z} \\left(- p_{0} + s_{RL}0\\right) & - 2 q_{y} \\left(- p_{2} + s_{RL}2\\right) + 2 q_{z} \\left(- p_{1} + s_{RL}1\\right) & 2 q_{y}^{2} + 2 q_{z}^{2} - 1 & - 2 q_{w} q_{z} - 2 q_{x} q_{y} & 2 q_{w} q_{y} - 2 q_{x} q_{z} & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & - 2 q_{y}^{2} - 2 q_{z}^{2} + 1 & 2 q_{w} q_{z} + 2 q_{x} q_{y} & - 2 q_{w} q_{y} + 2 q_{x} q_{z}\\\\2 q_{w} \\left(- p_{2} + s_{RL}2\\right) - 4 q_{x} \\left(- p_{1} + s_{RL}1\\right) + 2 q_{y} \\left(- p_{0} + s_{RL}0\\right) & 2 q_{x} \\left(- p_{0} + s_{RL}0\\right) + 2 q_{z} \\left(- p_{2} + s_{RL}2\\right) & - 2 q_{w} \\left(- p_{0} + s_{RL}0\\right) + 2 q_{y} \\left(- p_{2} + s_{RL}2\\right) - 4 q_{z} \\left(- p_{1} + s_{RL}1\\right) & 2 q_{x} \\left(- p_{2} + s_{RL}2\\right) - 2 q_{z} \\left(- p_{0} + s_{RL}0\\right) & 2 q_{w} q_{z} - 2 q_{x} q_{y} & 2 q_{x}^{2} + 2 q_{z}^{2} - 1 & - 2 q_{w} q_{x} - 2 q_{y} q_{z} & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & - 2 q_{w} q_{z} + 2 q_{x} q_{y} & - 2 q_{x}^{2} - 2 q_{z}^{2} + 1 & 2 q_{w} q_{x} + 2 q_{y} q_{z}\\\\- 2 q_{w} \\left(- p_{1} + s_{RL}1\\right) - 4 q_{x} \\left(- p_{2} + s_{RL}2\\right) + 2 q_{z} \\left(- p_{0} + s_{RL}0\\right) & 2 q_{w} \\left(- p_{0} + s_{RL}0\\right) - 4 q_{y} \\left(- p_{2} + s_{RL}2\\right) + 2 q_{z} \\left(- p_{1} + s_{RL}1\\right) & 2 q_{x} \\left(- p_{0} + s_{RL}0\\right) + 2 q_{y} \\left(- p_{1} + s_{RL}1\\right) & - 2 q_{x} \\left(- p_{1} + s_{RL}1\\right) + 2 q_{y} \\left(- p_{0} + s_{RL}0\\right) & - 2 q_{w} q_{y} - 2 q_{x} q_{z} & 2 q_{w} q_{x} - 2 q_{y} q_{z} & 2 q_{x}^{2} + 2 q_{y}^{2} - 1 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 2 q_{w} q_{y} + 2 q_{x} q_{z} & - 2 q_{w} q_{x} + 2 q_{y} q_{z} & - 2 q_{x}^{2} - 2 q_{y}^{2} + 1\\end{array}\\right]$" - ], - "text/plain": [ - "⎡ \n", - "⎢ 2⋅q_y⋅v₁ + 2⋅q_z⋅v₂ \n", - "⎢ \n", - "⎢ \n", - "⎢ 2⋅q_w⋅v₂ - 4⋅qₓ⋅v₁ + 2⋅q_y⋅v₀ \n", - "⎢ \n", - "⎢ \n", - "⎢ -2⋅q_w⋅v₁ - 4⋅qₓ⋅v₂ + 2⋅q_z⋅v₀ \n", - "⎢ \n", - "⎢ \n", - "⎢ 2⋅q_y⋅(-p₁ + s_{FR}1) + 2⋅q_z⋅(-p₂ + s_{FR}2) -2⋅q_w\n", - "⎢ \n", - "⎢ \n", - "⎢2⋅q_w⋅(-p₂ + s_{FR}2) - 4⋅qₓ⋅(-p₁ + s_{FR}1) + 2⋅q_y⋅(-p₀ + s_{FR}0) \n", - "⎢ \n", - "⎢ \n", - "⎢-2⋅q_w⋅(-p₁ + s_{FR}1) - 4⋅qₓ⋅(-p₂ + s_{FR}2) + 2⋅q_z⋅(-p₀ + s_{FR}0) 2⋅q_w⋅\n", - "⎢ \n", - "⎢ \n", - "⎢ 2⋅q_y⋅(-p₁ + s_{FL}1) + 2⋅q_z⋅(-p₂ + s_{FL}2) -2⋅q_w\n", - "⎢ \n", - "⎢ \n", - "⎢2⋅q_w⋅(-p₂ + s_{FL}2) - 4⋅qₓ⋅(-p₁ + s_{FL}1) + 2⋅q_y⋅(-p₀ + s_{FL}0) \n", - "⎢ \n", - "⎢ \n", - "⎢-2⋅q_w⋅(-p₁ + s_{FL}1) - 4⋅qₓ⋅(-p₂ + s_{FL}2) + 2⋅q_z⋅(-p₀ + s_{FL}0) 2⋅q_w⋅\n", - "⎢ \n", - "⎢ \n", - "⎢ 2⋅q_y⋅(-p₁ + s_{RR}1) + 2⋅q_z⋅(-p₂ + s_{RR}2) -2⋅q_w\n", - "⎢ \n", - "⎢ \n", - "⎢2⋅q_w⋅(-p₂ + s_{RR}2) - 4⋅qₓ⋅(-p₁ + s_{RR}1) + 2⋅q_y⋅(-p₀ + s_{RR}0) \n", - "⎢ \n", - "⎢ \n", - "⎢-2⋅q_w⋅(-p₁ + s_{RR}1) - 4⋅qₓ⋅(-p₂ + s_{RR}2) + 2⋅q_z⋅(-p₀ + s_{RR}0) 2⋅q_w⋅\n", - "⎢ \n", - "⎢ \n", - "⎢ 2⋅q_y⋅(-p₁ + s_{RL}1) + 2⋅q_z⋅(-p₂ + s_{RL}2) -2⋅q_w\n", - "⎢ \n", - "⎢ \n", - "⎢2⋅q_w⋅(-p₂ + s_{RL}2) - 4⋅qₓ⋅(-p₁ + s_{RL}1) + 2⋅q_y⋅(-p₀ + s_{RL}0) \n", - "⎢ \n", - "⎢ \n", - "⎣-2⋅q_w⋅(-p₁ + s_{RL}1) - 4⋅qₓ⋅(-p₂ + s_{RL}2) + 2⋅q_z⋅(-p₀ + s_{RL}0) 2⋅q_w⋅\n", - "\n", - " \n", - " -2⋅q_w⋅v₂ + 2⋅qₓ⋅v₁ - 4⋅q_y⋅v₀ \n", - " \n", - " \n", - " 2⋅qₓ⋅v₀ + 2⋅q_z⋅v₂ \n", - " \n", - " \n", - " 2⋅q_w⋅v₀ - 4⋅q_y⋅v₂ + 2⋅q_z⋅v₁ \n", - " \n", - " \n", - "⋅(-p₂ + s_{FR}2) + 2⋅qₓ⋅(-p₁ + s_{FR}1) - 4⋅q_y⋅(-p₀ + s_{FR}0) 2⋅q_w⋅(-p₁ +\n", - " \n", - " \n", - " 2⋅qₓ⋅(-p₀ + s_{FR}0) + 2⋅q_z⋅(-p₂ + s_{FR}2) -2⋅q_w⋅(-p₀ +\n", - " \n", - " \n", - "(-p₀ + s_{FR}0) - 4⋅q_y⋅(-p₂ + s_{FR}2) + 2⋅q_z⋅(-p₁ + s_{FR}1) \n", - " \n", - " \n", - "⋅(-p₂ + s_{FL}2) + 2⋅qₓ⋅(-p₁ + s_{FL}1) - 4⋅q_y⋅(-p₀ + s_{FL}0) 2⋅q_w⋅(-p₁ +\n", - " \n", - " \n", - " 2⋅qₓ⋅(-p₀ + s_{FL}0) + 2⋅q_z⋅(-p₂ + s_{FL}2) -2⋅q_w⋅(-p₀ +\n", - " \n", - " \n", - "(-p₀ + s_{FL}0) - 4⋅q_y⋅(-p₂ + s_{FL}2) + 2⋅q_z⋅(-p₁ + s_{FL}1) \n", - " \n", - " \n", - "⋅(-p₂ + s_{RR}2) + 2⋅qₓ⋅(-p₁ + s_{RR}1) - 4⋅q_y⋅(-p₀ + s_{RR}0) 2⋅q_w⋅(-p₁ +\n", - " \n", - " \n", - " 2⋅qₓ⋅(-p₀ + s_{RR}0) + 2⋅q_z⋅(-p₂ + s_{RR}2) -2⋅q_w⋅(-p₀ +\n", - " \n", - " \n", - "(-p₀ + s_{RR}0) - 4⋅q_y⋅(-p₂ + s_{RR}2) + 2⋅q_z⋅(-p₁ + s_{RR}1) \n", - " \n", - " \n", - "⋅(-p₂ + s_{RL}2) + 2⋅qₓ⋅(-p₁ + s_{RL}1) - 4⋅q_y⋅(-p₀ + s_{RL}0) 2⋅q_w⋅(-p₁ +\n", - " \n", - " \n", - " 2⋅qₓ⋅(-p₀ + s_{RL}0) + 2⋅q_z⋅(-p₂ + s_{RL}2) -2⋅q_w⋅(-p₀ +\n", - " \n", - " \n", - "(-p₀ + s_{RL}0) - 4⋅q_y⋅(-p₂ + s_{RL}2) + 2⋅q_z⋅(-p₁ + s_{RL}1) \n", - "\n", - " \n", - " 2⋅q_w⋅v₁ + 2⋅qₓ⋅v₂ - 4⋅q_z⋅v₀ -2⋅q_y\n", - " \n", - " \n", - " -2⋅q_w⋅v₀ + 2⋅q_y⋅v₂ - 4⋅q_z⋅v₁ 2⋅qₓ⋅\n", - " \n", - " \n", - " 2⋅qₓ⋅v₀ + 2⋅q_y⋅v₁ -2⋅qₓ⋅\n", - " \n", - " \n", - " s_{FR}1) + 2⋅qₓ⋅(-p₂ + s_{FR}2) - 4⋅q_z⋅(-p₀ + s_{FR}0) -2⋅q_y⋅(-p₂ + s_{FR\n", - " \n", - " \n", - " s_{FR}0) + 2⋅q_y⋅(-p₂ + s_{FR}2) - 4⋅q_z⋅(-p₁ + s_{FR}1) 2⋅qₓ⋅(-p₂ + s_{FR}\n", - " \n", - " \n", - "2⋅qₓ⋅(-p₀ + s_{FR}0) + 2⋅q_y⋅(-p₁ + s_{FR}1) -2⋅qₓ⋅(-p₁ + s_{FR}\n", - " \n", - " \n", - " s_{FL}1) + 2⋅qₓ⋅(-p₂ + s_{FL}2) - 4⋅q_z⋅(-p₀ + s_{FL}0) -2⋅q_y⋅(-p₂ + s_{FL\n", - " \n", - " \n", - " s_{FL}0) + 2⋅q_y⋅(-p₂ + s_{FL}2) - 4⋅q_z⋅(-p₁ + s_{FL}1) 2⋅qₓ⋅(-p₂ + s_{FL}\n", - " \n", - " \n", - "2⋅qₓ⋅(-p₀ + s_{FL}0) + 2⋅q_y⋅(-p₁ + s_{FL}1) -2⋅qₓ⋅(-p₁ + s_{FL}\n", - " \n", - " \n", - " s_{RR}1) + 2⋅qₓ⋅(-p₂ + s_{RR}2) - 4⋅q_z⋅(-p₀ + s_{RR}0) -2⋅q_y⋅(-p₂ + s_{RR\n", - " \n", - " \n", - " s_{RR}0) + 2⋅q_y⋅(-p₂ + s_{RR}2) - 4⋅q_z⋅(-p₁ + s_{RR}1) 2⋅qₓ⋅(-p₂ + s_{RR}\n", - " \n", - " \n", - "2⋅qₓ⋅(-p₀ + s_{RR}0) + 2⋅q_y⋅(-p₁ + s_{RR}1) -2⋅qₓ⋅(-p₁ + s_{RR}\n", - " \n", - " \n", - " s_{RL}1) + 2⋅qₓ⋅(-p₂ + s_{RL}2) - 4⋅q_z⋅(-p₀ + s_{RL}0) -2⋅q_y⋅(-p₂ + s_{RL\n", - " \n", - " \n", - " s_{RL}0) + 2⋅q_y⋅(-p₂ + s_{RL}2) - 4⋅q_z⋅(-p₁ + s_{RL}1) 2⋅qₓ⋅(-p₂ + s_{RL}\n", - " \n", - " \n", - "2⋅qₓ⋅(-p₀ + s_{RL}0) + 2⋅q_y⋅(-p₁ + s_{RL}1) -2⋅qₓ⋅(-p₁ + s_{RL}\n", - "\n", - " \n", - "⋅v₂ + 2⋅q_z⋅v₁ 0 0 \n", - " \n", - " \n", - "v₂ - 2⋅q_z⋅v₀ 0 0 \n", - " \n", - " \n", - "v₁ + 2⋅q_y⋅v₀ 0 0 \n", - " \n", - " 2 2 \n", - "}2) + 2⋅q_z⋅(-p₁ + s_{FR}1) 2⋅q_y + 2⋅q_z - 1 -2⋅q_w⋅q_z - 2⋅qₓ⋅q_y 2⋅q\n", - " \n", - " 2 2 \n", - "2) - 2⋅q_z⋅(-p₀ + s_{FR}0) 2⋅q_w⋅q_z - 2⋅qₓ⋅q_y 2⋅qₓ + 2⋅q_z - 1 -2⋅\n", - " \n", - " \n", - "1) + 2⋅q_y⋅(-p₀ + s_{FR}0) -2⋅q_w⋅q_y - 2⋅qₓ⋅q_z 2⋅q_w⋅qₓ - 2⋅q_y⋅q_z 2⋅\n", - " \n", - " 2 2 \n", - "}2) + 2⋅q_z⋅(-p₁ + s_{FL}1) 2⋅q_y + 2⋅q_z - 1 -2⋅q_w⋅q_z - 2⋅qₓ⋅q_y 2⋅q\n", - " \n", - " 2 2 \n", - "2) - 2⋅q_z⋅(-p₀ + s_{FL}0) 2⋅q_w⋅q_z - 2⋅qₓ⋅q_y 2⋅qₓ + 2⋅q_z - 1 -2⋅\n", - " \n", - " \n", - "1) + 2⋅q_y⋅(-p₀ + s_{FL}0) -2⋅q_w⋅q_y - 2⋅qₓ⋅q_z 2⋅q_w⋅qₓ - 2⋅q_y⋅q_z 2⋅\n", - " \n", - " 2 2 \n", - "}2) + 2⋅q_z⋅(-p₁ + s_{RR}1) 2⋅q_y + 2⋅q_z - 1 -2⋅q_w⋅q_z - 2⋅qₓ⋅q_y 2⋅q\n", - " \n", - " 2 2 \n", - "2) - 2⋅q_z⋅(-p₀ + s_{RR}0) 2⋅q_w⋅q_z - 2⋅qₓ⋅q_y 2⋅qₓ + 2⋅q_z - 1 -2⋅\n", - " \n", - " \n", - "1) + 2⋅q_y⋅(-p₀ + s_{RR}0) -2⋅q_w⋅q_y - 2⋅qₓ⋅q_z 2⋅q_w⋅qₓ - 2⋅q_y⋅q_z 2⋅\n", - " \n", - " 2 2 \n", - "}2) + 2⋅q_z⋅(-p₁ + s_{RL}1) 2⋅q_y + 2⋅q_z - 1 -2⋅q_w⋅q_z - 2⋅qₓ⋅q_y 2⋅q\n", - " \n", - " 2 2 \n", - "2) - 2⋅q_z⋅(-p₀ + s_{RL}0) 2⋅q_w⋅q_z - 2⋅qₓ⋅q_y 2⋅qₓ + 2⋅q_z - 1 -2⋅\n", - " \n", - " \n", - "1) + 2⋅q_y⋅(-p₀ + s_{RL}0) -2⋅q_w⋅q_y - 2⋅qₓ⋅q_z 2⋅q_w⋅qₓ - 2⋅q_y⋅q_z 2⋅\n", - "\n", - " 2 2 \n", - " 0 - 2⋅q_y - 2⋅q_z + 1 2⋅q_w⋅q_z + 2⋅qₓ⋅q_y -2⋅q_w⋅q_y +\n", - " \n", - " 2 2 \n", - " 0 -2⋅q_w⋅q_z + 2⋅qₓ⋅q_y - 2⋅qₓ - 2⋅q_z + 1 2⋅q_w⋅qₓ + 2\n", - " \n", - " 2 \n", - " 0 2⋅q_w⋅q_y + 2⋅qₓ⋅q_z -2⋅q_w⋅qₓ + 2⋅q_y⋅q_z - 2⋅qₓ - 2⋅\n", - " \n", - " \n", - "_w⋅q_y - 2⋅qₓ⋅q_z 0 0 0 \n", - " \n", - " \n", - "q_w⋅qₓ - 2⋅q_y⋅q_z 0 0 0 \n", - " \n", - " 2 2 \n", - "qₓ + 2⋅q_y - 1 0 0 0 \n", - " \n", - " \n", - "_w⋅q_y - 2⋅qₓ⋅q_z 0 0 0 \n", - " \n", - " \n", - "q_w⋅qₓ - 2⋅q_y⋅q_z 0 0 0 \n", - " \n", - " 2 2 \n", - "qₓ + 2⋅q_y - 1 0 0 0 \n", - " \n", - " \n", - "_w⋅q_y - 2⋅qₓ⋅q_z 0 0 0 \n", - " \n", - " \n", - "q_w⋅qₓ - 2⋅q_y⋅q_z 0 0 0 \n", - " \n", - " 2 2 \n", - "qₓ + 2⋅q_y - 1 0 0 0 \n", - " \n", - " \n", - "_w⋅q_y - 2⋅qₓ⋅q_z 0 0 0 \n", - " \n", - " \n", - "q_w⋅qₓ - 2⋅q_y⋅q_z 0 0 0 \n", - " \n", - " 2 2 \n", - "qₓ + 2⋅q_y - 1 0 0 0 \n", - "\n", - " \n", - " 2⋅qₓ⋅q_z 0 0 0 0 0 0 0 0 \n", - " \n", - " \n", - "⋅q_y⋅q_z 0 0 0 0 0 0 0 0 \n", - " \n", - " 2 \n", - "q_y + 1 0 0 0 0 0 0 0 0 \n", - " \n", - " 2 2 \n", - " 0 0 0 0 0 0 - 2⋅q_y - 2⋅q_z + 1 2⋅q_w⋅q_z + 2⋅qₓ⋅q_y -2⋅\n", - " \n", - " 2 2 \n", - " 0 0 0 0 0 0 -2⋅q_w⋅q_z + 2⋅qₓ⋅q_y - 2⋅qₓ - 2⋅q_z + 1 2⋅q\n", - " \n", - " \n", - " 0 0 0 0 0 0 2⋅q_w⋅q_y + 2⋅qₓ⋅q_z -2⋅q_w⋅qₓ + 2⋅q_y⋅q_z - 2\n", - " \n", - " \n", - " 0 0 0 0 0 0 0 0 \n", - " \n", - " \n", - " 0 0 0 0 0 0 0 0 \n", - " \n", - " \n", - " 0 0 0 0 0 0 0 0 \n", - " \n", - " \n", - " 0 0 0 0 0 0 0 0 \n", - " \n", - " \n", - " 0 0 0 0 0 0 0 0 \n", - " \n", - " \n", - " 0 0 0 0 0 0 0 0 \n", - " \n", - " \n", - " 0 0 0 0 0 0 0 0 \n", - " \n", - " \n", - " 0 0 0 0 0 0 0 0 \n", - " \n", - " \n", - " 0 0 0 0 0 0 0 0 \n", - "\n", - " \n", - " 0 0 0 0 \n", - " \n", - " \n", - " 0 0 0 0 \n", - " \n", - " \n", - " 0 0 0 0 \n", - " \n", - " \n", - "q_w⋅q_y + 2⋅qₓ⋅q_z 0 0 0 \n", - " \n", - " \n", - "_w⋅qₓ + 2⋅q_y⋅q_z 0 0 0 \n", - " \n", - " 2 2 \n", - "⋅qₓ - 2⋅q_y + 1 0 0 0 \n", - " \n", - " 2 2 \n", - " 0 - 2⋅q_y - 2⋅q_z + 1 2⋅q_w⋅q_z + 2⋅qₓ⋅q_y -2⋅q_w⋅q_y +\n", - " \n", - " 2 2 \n", - " 0 -2⋅q_w⋅q_z + 2⋅qₓ⋅q_y - 2⋅qₓ - 2⋅q_z + 1 2⋅q_w⋅qₓ + 2\n", - " \n", - " 2 \n", - " 0 2⋅q_w⋅q_y + 2⋅qₓ⋅q_z -2⋅q_w⋅qₓ + 2⋅q_y⋅q_z - 2⋅qₓ - 2⋅\n", - " \n", - " \n", - " 0 0 0 0 \n", - " \n", - " \n", - " 0 0 0 0 \n", - " \n", - " \n", - " 0 0 0 0 \n", - " \n", - " \n", - " 0 0 0 0 \n", - " \n", - " \n", - " 0 0 0 0 \n", - " \n", - " \n", - " 0 0 0 0 \n", - "\n", - " \n", - " 0 0 0 \n", - " \n", - " \n", - " 0 0 0 \n", - " \n", - " \n", - " 0 0 0 \n", - " \n", - " \n", - " 0 0 0 \n", - " \n", - " \n", - " 0 0 0 \n", - " \n", - " \n", - " 0 0 0 \n", - " \n", - " \n", - " 2⋅qₓ⋅q_z 0 0 0 \n", - " \n", - " \n", - "⋅q_y⋅q_z 0 0 0 \n", - " \n", - " 2 \n", - "q_y + 1 0 0 0 \n", - " \n", - " 2 2 \n", - " - 2⋅q_y - 2⋅q_z + 1 2⋅q_w⋅q_z + 2⋅qₓ⋅q_y -2⋅q_w⋅q_y + 2⋅qₓ⋅q_z\n", - " \n", - " 2 2 \n", - " -2⋅q_w⋅q_z + 2⋅qₓ⋅q_y - 2⋅qₓ - 2⋅q_z + 1 2⋅q_w⋅qₓ + 2⋅q_y⋅q_z \n", - " \n", - " 2 2 \n", - " 2⋅q_w⋅q_y + 2⋅qₓ⋅q_z -2⋅q_w⋅qₓ + 2⋅q_y⋅q_z - 2⋅qₓ - 2⋅q_y + 1 \n", - " \n", - " \n", - " 0 0 0 \n", - " \n", - " \n", - " 0 0 0 \n", - " \n", - " \n", - " 0 0 0 \n", - "\n", - " ⎤\n", - " 0 0 0 ⎥\n", - " ⎥\n", - " ⎥\n", - " 0 0 0 ⎥\n", - " ⎥\n", - " ⎥\n", - " 0 0 0 ⎥\n", - " ⎥\n", - " ⎥\n", - " 0 0 0 ⎥\n", - " ⎥\n", - " ⎥\n", - " 0 0 0 ⎥\n", - " ⎥\n", - " ⎥\n", - " 0 0 0 ⎥\n", - " ⎥\n", - " ⎥\n", - " 0 0 0 ⎥\n", - " ⎥\n", - " ⎥\n", - " 0 0 0 ⎥\n", - " ⎥\n", - " ⎥\n", - " 0 0 0 ⎥\n", - " ⎥\n", - " ⎥\n", - " 0 0 0 ⎥\n", - " ⎥\n", - " ⎥\n", - " 0 0 0 ⎥\n", - " ⎥\n", - " ⎥\n", - " 0 0 0 ⎥\n", - " ⎥\n", - " 2 2 ⎥\n", - " - 2⋅q_y - 2⋅q_z + 1 2⋅q_w⋅q_z + 2⋅qₓ⋅q_y -2⋅q_w⋅q_y + 2⋅qₓ⋅q_z⎥\n", - " ⎥\n", - " 2 2 ⎥\n", - " -2⋅q_w⋅q_z + 2⋅qₓ⋅q_y - 2⋅qₓ - 2⋅q_z + 1 2⋅q_w⋅qₓ + 2⋅q_y⋅q_z ⎥\n", - " ⎥\n", - " 2 2 ⎥\n", - " 2⋅q_w⋅q_y + 2⋅qₓ⋅q_z -2⋅q_w⋅qₓ + 2⋅q_y⋅q_z - 2⋅qₓ - 2⋅q_y + 1 ⎦" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "H = h.jacobian(state)\n", - "H" - ] - }, - { - "cell_type": "code", - "execution_count": 11, - "metadata": {}, - "outputs": [ - { - "data": { - "text/latex": [ - "$\\displaystyle \\left[\\begin{array}{ccccccccccccccc}R_{v} & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0\\\\0 & R_{v} & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0\\\\0 & 0 & R_{v} & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0\\\\0 & 0 & 0 & R_{s_{FR}} & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0\\\\0 & 0 & 0 & 0 & R_{s_{FR}} & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0\\\\0 & 0 & 0 & 0 & 0 & R_{s_{FR}} & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0\\\\0 & 0 & 0 & 0 & 0 & 0 & R_{s_{FL}} & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0\\\\0 & 0 & 0 & 0 & 0 & 0 & 0 & R_{s_{FL}} & 0 & 0 & 0 & 0 & 0 & 0 & 0\\\\0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & R_{s_{FL}} & 0 & 0 & 0 & 0 & 0 & 0\\\\0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & R_{s_{RR}} & 0 & 0 & 0 & 0 & 0\\\\0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & R_{s_{RR}} & 0 & 0 & 0 & 0\\\\0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & R_{s_{RR}} & 0 & 0 & 0\\\\0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & R_{s_{RL}} & 0 & 0\\\\0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & R_{s_{RL}} & 0\\\\0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & R_{s_{RL}}\\end{array}\\right]$" - ], - "text/plain": [ - "⎡Rᵥ 0 0 0 0 0 0 0 0\n", - "⎢ \n", - "⎢0 Rᵥ 0 0 0 0 0 0 0\n", - "⎢ \n", - "⎢0 0 Rᵥ 0 0 0 0 0 0\n", - "⎢ \n", - "⎢0 0 0 R_{s_{FR}} 0 0 0 0 0\n", - "⎢ \n", - "⎢0 0 0 0 R_{s_{FR}} 0 0 0 0\n", - "⎢ \n", - "⎢0 0 0 0 0 R_{s_{FR}} 0 0 0\n", - "⎢ \n", - "⎢0 0 0 0 0 0 R_{s_{FL}} 0 0\n", - "⎢ \n", - "⎢0 0 0 0 0 0 0 R_{s_{FL}} 0\n", - "⎢ \n", - "⎢0 0 0 0 0 0 0 0 R_{s_\n", - "⎢ \n", - "⎢0 0 0 0 0 0 0 0 0\n", - "⎢ \n", - "⎢0 0 0 0 0 0 0 0 0\n", - "⎢ \n", - "⎢0 0 0 0 0 0 0 0 0\n", - "⎢ \n", - "⎢0 0 0 0 0 0 0 0 0\n", - "⎢ \n", - "⎢0 0 0 0 0 0 0 0 0\n", - "⎢ \n", - "⎣0 0 0 0 0 0 0 0 0\n", - "\n", - " 0 0 0 0 0 0 ⎤\n", - " ⎥\n", - " 0 0 0 0 0 0 ⎥\n", - " ⎥\n", - " 0 0 0 0 0 0 ⎥\n", - " ⎥\n", - " 0 0 0 0 0 0 ⎥\n", - " ⎥\n", - " 0 0 0 0 0 0 ⎥\n", - " ⎥\n", - " 0 0 0 0 0 0 ⎥\n", - " ⎥\n", - " 0 0 0 0 0 0 ⎥\n", - " ⎥\n", - " 0 0 0 0 0 0 ⎥\n", - " ⎥\n", - "{FL}} 0 0 0 0 0 0 ⎥\n", - " ⎥\n", - " R_{s_{RR}} 0 0 0 0 0 ⎥\n", - " ⎥\n", - " 0 R_{s_{RR}} 0 0 0 0 ⎥\n", - " ⎥\n", - " 0 0 R_{s_{RR}} 0 0 0 ⎥\n", - " ⎥\n", - " 0 0 0 R_{s_{RL}} 0 0 ⎥\n", - " ⎥\n", - " 0 0 0 0 R_{s_{RL}} 0 ⎥\n", - " ⎥\n", - " 0 0 0 0 0 R_{s_{RL}}⎦" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "R_vel = sf.Symbol('R_v')\n", - "R_s1 = sf.Symbol('R_{s_{FR}}')\n", - "R_s2 = sf.Symbol('R_{s_{FL}}')\n", - "R_s3 = sf.Symbol('R_{s_{RR}}')\n", - "R_s4 = sf.Symbol('R_{s_{RL}}')\n", - "\n", - "R_cov = sf.Matrix.diag([R_vel,R_vel,R_vel,\n", - " R_s1, R_s1, R_s1,\n", - " R_s2, R_s2, R_s2,\n", - " R_s3, R_s3, R_s3,\n", - " R_s4, R_s4, R_s4])\n", - "R_cov" - ] - }, - { - "cell_type": "code", - "execution_count": 12, - "metadata": {}, - "outputs": [ - { - "data": { - "text/latex": [ - "$\\displaystyle \\left[\\begin{array}{cccccccccccccccccccccccccccc}Q_{q} & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0\\\\0 & Q_{q} & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0\\\\0 & 0 & Q_{q} & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0\\\\0 & 0 & 0 & Q_{q} & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0\\\\0 & 0 & 0 & 0 & Q_{p} & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0\\\\0 & 0 & 0 & 0 & 0 & Q_{p} & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0\\\\0 & 0 & 0 & 0 & 0 & 0 & Q_{p} & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0\\\\0 & 0 & 0 & 0 & 0 & 0 & 0 & Q_{v} & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0\\\\0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & Q_{v} & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0\\\\0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & Q_{v} & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0\\\\0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & Q_{bg} & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0\\\\0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & Q_{bg} & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0\\\\0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & Q_{bg} & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0\\\\0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & Q_{ba} & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0\\\\0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & Q_{ba} & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0\\\\0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & Q_{ba} & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0\\\\0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & Q_{s_{FR}} & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0\\\\0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & Q_{s_{FR}} & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0\\\\0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & Q_{s_{FR}} & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0\\\\0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & Q_{s_{FL}} & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0\\\\0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & Q_{s_{FL}} & 0 & 0 & 0 & 0 & 0 & 0 & 0\\\\0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & Q_{s_{FL}} & 0 & 0 & 0 & 0 & 0 & 0\\\\0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & Q_{s_{RR}} & 0 & 0 & 0 & 0 & 0\\\\0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & Q_{s_{RR}} & 0 & 0 & 0 & 0\\\\0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & Q_{s_{RR}} & 0 & 0 & 0\\\\0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & Q_{s_{RL}} & 0 & 0\\\\0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & Q_{s_{RL}} & 0\\\\0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & Q_{s_{RL}}\\end{array}\\right]$" - ], - "text/plain": [ - "⎡Q_q 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 \n", - "⎢ \n", - "⎢ 0 Q_q 0 0 0 0 0 0 0 0 0 0 0 0 0 0 \n", - "⎢ \n", - "⎢ 0 0 Q_q 0 0 0 0 0 0 0 0 0 0 0 0 0 \n", - "⎢ \n", - "⎢ 0 0 0 Q_q 0 0 0 0 0 0 0 0 0 0 0 0 \n", - "⎢ \n", - "⎢ 0 0 0 0 Qₚ 0 0 0 0 0 0 0 0 0 0 0 \n", - "⎢ \n", - "⎢ 0 0 0 0 0 Qₚ 0 0 0 0 0 0 0 0 0 0 \n", - "⎢ \n", - "⎢ 0 0 0 0 0 0 Qₚ 0 0 0 0 0 0 0 0 0 \n", - "⎢ \n", - "⎢ 0 0 0 0 0 0 0 Qᵥ 0 0 0 0 0 0 0 0 \n", - "⎢ \n", - "⎢ 0 0 0 0 0 0 0 0 Qᵥ 0 0 0 0 0 0 0 \n", - "⎢ \n", - "⎢ 0 0 0 0 0 0 0 0 0 Qᵥ 0 0 0 0 0 0 \n", - "⎢ \n", - "⎢ 0 0 0 0 0 0 0 0 0 0 Q_bg 0 0 0 0 0 \n", - "⎢ \n", - "⎢ 0 0 0 0 0 0 0 0 0 0 0 Q_bg 0 0 0 0 \n", - "⎢ \n", - "⎢ 0 0 0 0 0 0 0 0 0 0 0 0 Q_bg 0 0 0 \n", - "⎢ \n", - "⎢ 0 0 0 0 0 0 0 0 0 0 0 0 0 Q_ba 0 0 \n", - "⎢ \n", - "⎢ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 Q_ba 0 \n", - "⎢ \n", - "⎢ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 Q_b\n", - "⎢ \n", - "⎢ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 \n", - "⎢ \n", - "⎢ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 \n", - "⎢ \n", - "⎢ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 \n", - "⎢ \n", - "⎢ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 \n", - "⎢ \n", - "⎢ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 \n", - "⎢ \n", - "⎢ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 \n", - "⎢ \n", - "⎢ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 \n", - "⎢ \n", - "⎢ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 \n", - "⎢ \n", - "⎢ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 \n", - "⎢ \n", - "⎢ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 \n", - "⎢ \n", - "⎢ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 \n", - "⎢ \n", - "⎣ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 \n", - "\n", - " 0 0 0 0 0 0 \n", - " \n", - " 0 0 0 0 0 0 \n", - " \n", - " 0 0 0 0 0 0 \n", - " \n", - " 0 0 0 0 0 0 \n", - " \n", - " 0 0 0 0 0 0 \n", - " \n", - " 0 0 0 0 0 0 \n", - " \n", - " 0 0 0 0 0 0 \n", - " \n", - " 0 0 0 0 0 0 \n", - " \n", - " 0 0 0 0 0 0 \n", - " \n", - " 0 0 0 0 0 0 \n", - " \n", - " 0 0 0 0 0 0 \n", - " \n", - " 0 0 0 0 0 0 \n", - " \n", - " 0 0 0 0 0 0 \n", - " \n", - " 0 0 0 0 0 0 \n", - " \n", - " 0 0 0 0 0 0 \n", - " \n", - "a 0 0 0 0 0 0 \n", - " \n", - " Q_{s_{FR}} 0 0 0 0 0 \n", - " \n", - " 0 Q_{s_{FR}} 0 0 0 0 \n", - " \n", - " 0 0 Q_{s_{FR}} 0 0 0 \n", - " \n", - " 0 0 0 Q_{s_{FL}} 0 0 \n", - " \n", - " 0 0 0 0 Q_{s_{FL}} 0 \n", - " \n", - " 0 0 0 0 0 Q_{s_{FL}} \n", - " \n", - " 0 0 0 0 0 0 Q_{\n", - " \n", - " 0 0 0 0 0 0 \n", - " \n", - " 0 0 0 0 0 0 \n", - " \n", - " 0 0 0 0 0 0 \n", - " \n", - " 0 0 0 0 0 0 \n", - " \n", - " 0 0 0 0 0 0 \n", - "\n", - " 0 0 0 0 0 0 ⎤\n", - " ⎥\n", - " 0 0 0 0 0 0 ⎥\n", - " ⎥\n", - " 0 0 0 0 0 0 ⎥\n", - " ⎥\n", - " 0 0 0 0 0 0 ⎥\n", - " ⎥\n", - " 0 0 0 0 0 0 ⎥\n", - " ⎥\n", - " 0 0 0 0 0 0 ⎥\n", - " ⎥\n", - " 0 0 0 0 0 0 ⎥\n", - " ⎥\n", - " 0 0 0 0 0 0 ⎥\n", - " ⎥\n", - " 0 0 0 0 0 0 ⎥\n", - " ⎥\n", - " 0 0 0 0 0 0 ⎥\n", - " ⎥\n", - " 0 0 0 0 0 0 ⎥\n", - " ⎥\n", - " 0 0 0 0 0 0 ⎥\n", - " ⎥\n", - " 0 0 0 0 0 0 ⎥\n", - " ⎥\n", - " 0 0 0 0 0 0 ⎥\n", - " ⎥\n", - " 0 0 0 0 0 0 ⎥\n", - " ⎥\n", - " 0 0 0 0 0 0 ⎥\n", - " ⎥\n", - " 0 0 0 0 0 0 ⎥\n", - " ⎥\n", - " 0 0 0 0 0 0 ⎥\n", - " ⎥\n", - " 0 0 0 0 0 0 ⎥\n", - " ⎥\n", - " 0 0 0 0 0 0 ⎥\n", - " ⎥\n", - " 0 0 0 0 0 0 ⎥\n", - " ⎥\n", - " 0 0 0 0 0 0 ⎥\n", - " ⎥\n", - "s_{RR}} 0 0 0 0 0 ⎥\n", - " ⎥\n", - " 0 Q_{s_{RR}} 0 0 0 0 ⎥\n", - " ⎥\n", - " 0 0 Q_{s_{RR}} 0 0 0 ⎥\n", - " ⎥\n", - " 0 0 0 Q_{s_{RL}} 0 0 ⎥\n", - " ⎥\n", - " 0 0 0 0 Q_{s_{RL}} 0 ⎥\n", - " ⎥\n", - " 0 0 0 0 0 Q_{s_{RL}}⎦" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "\n", - "Q_vel = sf.Symbol('Q_v')\n", - "Q_pos = sf.Symbol('Q_p')\n", - "Q_quat = sf.Symbol('Q_q')\n", - "Q_bg = sf.Symbol('Q_bg')\n", - "Q_ba = sf.Symbol('Q_ba')\n", - "Q_s1 = sf.Symbol('Q_{s_{FR}}')\n", - "Q_s2 = sf.Symbol('Q_{s_{FL}}')\n", - "Q_s3 = sf.Symbol('Q_{s_{RR}}')\n", - "Q_s4 = sf.Symbol('Q_{s_{RL}}')\n", - "\n", - "Q_cov = sf.Matrix.diag([Q_quat,Q_quat,Q_quat,Q_quat,\n", - " Q_pos, Q_pos, Q_pos,\n", - " Q_vel, Q_vel, Q_vel,\n", - " Q_bg, Q_bg, Q_bg,\n", - " Q_ba, Q_ba, Q_ba,\n", - " Q_s1, Q_s1, Q_s1,\n", - " Q_s2, Q_s2, Q_s2,\n", - " Q_s3, Q_s3, Q_s3,\n", - " Q_s4, Q_s4, Q_s4])\n", - "Q_cov\n" - ] - }, - { - "cell_type": "code", - "execution_count": 13, - "metadata": {}, - "outputs": [ - { - "data": { - "text/latex": [ - "$\\displaystyle \\left[\\begin{matrix}q_{x}\\\\q_{y}\\\\q_{z}\\\\q_{w}\\\\p_{0}\\\\p_{1}\\\\p_{2}\\\\v_{0}\\\\v_{1}\\\\v_{2}\\\\b_{g0}\\\\b_{g1}\\\\b_{g2}\\\\b_{a0}\\\\b_{a1}\\\\b_{a2}\\\\s_{FR}0\\\\s_{FR}1\\\\s_{FR}2\\\\s_{FL}0\\\\s_{FL}1\\\\s_{FL}2\\\\s_{RR}0\\\\s_{RR}1\\\\s_{RR}2\\\\s_{RL}0\\\\s_{RL}1\\\\s_{RL}2\\end{matrix}\\right]$" - ], - "text/plain": [ - "⎡ qₓ ⎤\n", - "⎢ ⎥\n", - "⎢ q_y ⎥\n", - "⎢ ⎥\n", - "⎢ q_z ⎥\n", - "⎢ ⎥\n", - "⎢ q_w ⎥\n", - "⎢ ⎥\n", - "⎢ p₀ ⎥\n", - "⎢ ⎥\n", - "⎢ p₁ ⎥\n", - "⎢ ⎥\n", - "⎢ p₂ ⎥\n", - "⎢ ⎥\n", - "⎢ v₀ ⎥\n", - "⎢ ⎥\n", - "⎢ v₁ ⎥\n", - "⎢ ⎥\n", - "⎢ v₂ ⎥\n", - "⎢ ⎥\n", - "⎢ b_g0 ⎥\n", - "⎢ ⎥\n", - "⎢ b_g1 ⎥\n", - "⎢ ⎥\n", - "⎢ b_g2 ⎥\n", - "⎢ ⎥\n", - "⎢ bₐ₀ ⎥\n", - "⎢ ⎥\n", - "⎢ bₐ₁ ⎥\n", - "⎢ ⎥\n", - "⎢ bₐ₂ ⎥\n", - "⎢ ⎥\n", - "⎢s_{FR}0⎥\n", - "⎢ ⎥\n", - "⎢s_{FR}1⎥\n", - "⎢ ⎥\n", - "⎢s_{FR}2⎥\n", - "⎢ ⎥\n", - "⎢s_{FL}0⎥\n", - "⎢ ⎥\n", - "⎢s_{FL}1⎥\n", - "⎢ ⎥\n", - "⎢s_{FL}2⎥\n", - "⎢ ⎥\n", - "⎢s_{RR}0⎥\n", - "⎢ ⎥\n", - "⎢s_{RR}1⎥\n", - "⎢ ⎥\n", - "⎢s_{RR}2⎥\n", - "⎢ ⎥\n", - "⎢s_{RL}0⎥\n", - "⎢ ⎥\n", - "⎢s_{RL}1⎥\n", - "⎢ ⎥\n", - "⎣s_{RL}2⎦" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "state" - ] - }, - { - "cell_type": "code", - "execution_count": 14, - "metadata": {}, - "outputs": [], - "source": [ - "P = sf.matrix_type_from_shape((28,28)).symbolic('P')" - ] - }, - { - "cell_type": "code", - "execution_count": 15, - "metadata": {}, - "outputs": [ - { - "data": { - "text/latex": [ - "$\\displaystyle \\left[\\begin{matrix}q_{x}\\\\q_{y}\\\\q_{z}\\\\q_{w}\\\\p_{0}\\\\p_{1}\\\\p_{2}\\\\v_{0}\\\\v_{1}\\\\v_{2}\\\\b_{g0}\\\\b_{g1}\\\\b_{g2}\\\\b_{a0}\\\\b_{a1}\\\\b_{a2}\\\\s_{FR}0\\\\s_{FR}1\\\\s_{FR}2\\\\s_{FL}0\\\\s_{FL}1\\\\s_{FL}2\\\\s_{RR}0\\\\s_{RR}1\\\\s_{RR}2\\\\s_{RL}0\\\\s_{RL}1\\\\s_{RL}2\\end{matrix}\\right]$" - ], - "text/plain": [ - "⎡ qₓ ⎤\n", - "⎢ ⎥\n", - "⎢ q_y ⎥\n", - "⎢ ⎥\n", - "⎢ q_z ⎥\n", - "⎢ ⎥\n", - "⎢ q_w ⎥\n", - "⎢ ⎥\n", - "⎢ p₀ ⎥\n", - "⎢ ⎥\n", - "⎢ p₁ ⎥\n", - "⎢ ⎥\n", - "⎢ p₂ ⎥\n", - "⎢ ⎥\n", - "⎢ v₀ ⎥\n", - "⎢ ⎥\n", - "⎢ v₁ ⎥\n", - "⎢ ⎥\n", - "⎢ v₂ ⎥\n", - "⎢ ⎥\n", - "⎢ b_g0 ⎥\n", - "⎢ ⎥\n", - "⎢ b_g1 ⎥\n", - "⎢ ⎥\n", - "⎢ b_g2 ⎥\n", - "⎢ ⎥\n", - "⎢ bₐ₀ ⎥\n", - "⎢ ⎥\n", - "⎢ bₐ₁ ⎥\n", - "⎢ ⎥\n", - "⎢ bₐ₂ ⎥\n", - "⎢ ⎥\n", - "⎢s_{FR}0⎥\n", - "⎢ ⎥\n", - "⎢s_{FR}1⎥\n", - "⎢ ⎥\n", - "⎢s_{FR}2⎥\n", - "⎢ ⎥\n", - "⎢s_{FL}0⎥\n", - "⎢ ⎥\n", - "⎢s_{FL}1⎥\n", - "⎢ ⎥\n", - "⎢s_{FL}2⎥\n", - "⎢ ⎥\n", - "⎢s_{RR}0⎥\n", - "⎢ ⎥\n", - "⎢s_{RR}1⎥\n", - "⎢ ⎥\n", - "⎢s_{RR}2⎥\n", - "⎢ ⎥\n", - "⎢s_{RL}0⎥\n", - "⎢ ⎥\n", - "⎢s_{RL}1⎥\n", - "⎢ ⎥\n", - "⎣s_{RL}2⎦" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "state = sf.Matrix.block_matrix([[sf.Matrix([q.x, q.y, q.z, q.w])],\\\n", - " [p],\\\n", - " [v],\\\n", - " [b_g],\\\n", - " [b_a],\\\n", - " [s1],\\\n", - " [s2],\\\n", - " [s3],\\\n", - " [s4]])\n", - "state" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Generate Codes" - ] - }, - { - "cell_type": "code", - "execution_count": 16, - "metadata": {}, - "outputs": [], - "source": [ - "def compute_mean( state: sf.matrix_type_from_shape((28,1)), u: sf.matrix_type_from_shape((6,1)), dT: sf.Scalar = 0, epsilon: sf.Scalar = 0) -> sf.matrix_type_from_shape((28,1)):\n", - " omega = u[0:3]\n", - " accel = u[3:6]\n", - " q = sf.Quaternion(xyz=state[0:3], w=state[3])\n", - " p = state[4:7]\n", - " v = state[7:10]\n", - " b_g = state[10:13]\n", - " b_a = state[13:16]\n", - " s1 = state[16:19]\n", - " s2 = state[19:22]\n", - " s3 = state[22:25]\n", - " s4 = state[25:28]\n", - " f1 = q*sf.Quaternion(xyz=(omega-b_g)*dT, w = 1.)\n", - " # f1 = q*sf.Rot3.from_tangent((gyro-b_g)*dT, epsilon=epsilon).q\n", - " f1 = sf.Matrix([f1.x, f1.y, f1.z, f1.w])\n", - " f2 = p+dT*v\n", - " f3 = v+sf.Rot3(q).to_rotation_matrix()*(accel-b_a)-gravity\n", - " f4 = b_g\n", - " f5 = b_a\n", - " f6 = s1\n", - " f7 = s2\n", - " f8 = s3\n", - " f9 = s4\n", - " f = sf.Matrix.block_matrix([[f1],\\\n", - " [f2],\\\n", - " [f3],\\\n", - " [f4],\\\n", - " [f5],\\\n", - " [f6],\\\n", - " [f7],\\\n", - " [f8],\\\n", - " [f9]])\n", - " return f" - ] - }, - { - "cell_type": "code", - "execution_count": 17, - "metadata": {}, - "outputs": [ - { - "data": { - "text/latex": [ - "$\\displaystyle \\left[\\begin{matrix}\\Delta t q_{w} \\left(\\omega0 - b_{g0}\\right) + \\Delta t q_{y} \\left(\\omega2 - b_{g2}\\right) - \\Delta t q_{z} \\left(\\omega1 - b_{g1}\\right) + 1.0 q_{x}\\\\\\Delta t q_{w} \\left(\\omega1 - b_{g1}\\right) - \\Delta t q_{x} \\left(\\omega2 - b_{g2}\\right) + \\Delta t q_{z} \\left(\\omega0 - b_{g0}\\right) + 1.0 q_{y}\\\\\\Delta t q_{w} \\left(\\omega2 - b_{g2}\\right) + \\Delta t q_{x} \\left(\\omega1 - b_{g1}\\right) - \\Delta t q_{y} \\left(\\omega0 - b_{g0}\\right) + 1.0 q_{z}\\\\- \\Delta t q_{x} \\left(\\omega0 - b_{g0}\\right) - \\Delta t q_{y} \\left(\\omega1 - b_{g1}\\right) - \\Delta t q_{z} \\left(\\omega2 - b_{g2}\\right) + 1.0 q_{w}\\\\\\Delta t v_{0} + p_{0}\\\\\\Delta t v_{1} + p_{1}\\\\\\Delta t v_{2} + p_{2}\\\\v_{0} + \\left(a_{0} - b_{a0}\\right) \\left(- 2 q_{y}^{2} - 2 q_{z}^{2} + 1\\right) + \\left(a_{1} - b_{a1}\\right) \\left(- 2 q_{w} q_{z} + 2 q_{x} q_{y}\\right) + \\left(a_{2} - b_{a2}\\right) \\left(2 q_{w} q_{y} + 2 q_{x} q_{z}\\right)\\\\v_{1} + \\left(a_{0} - b_{a0}\\right) \\left(2 q_{w} q_{z} + 2 q_{x} q_{y}\\right) + \\left(a_{1} - b_{a1}\\right) \\left(- 2 q_{x}^{2} - 2 q_{z}^{2} + 1\\right) + \\left(a_{2} - b_{a2}\\right) \\left(- 2 q_{w} q_{x} + 2 q_{y} q_{z}\\right)\\\\v_{2} + \\left(a_{0} - b_{a0}\\right) \\left(- 2 q_{w} q_{y} + 2 q_{x} q_{z}\\right) + \\left(a_{1} - b_{a1}\\right) \\left(2 q_{w} q_{x} + 2 q_{y} q_{z}\\right) + \\left(a_{2} - b_{a2}\\right) \\left(- 2 q_{x}^{2} - 2 q_{y}^{2} + 1\\right) + 9.8\\\\b_{g0}\\\\b_{g1}\\\\b_{g2}\\\\b_{a0}\\\\b_{a1}\\\\b_{a2}\\\\s_{FR}0\\\\s_{FR}1\\\\s_{FR}2\\\\s_{FL}0\\\\s_{FL}1\\\\s_{FL}2\\\\s_{RR}0\\\\s_{RR}1\\\\s_{RR}2\\\\s_{RL}0\\\\s_{RL}1\\\\s_{RL}2\\end{matrix}\\right]$" - ], - "text/plain": [ - "⎡ \\Delta t⋅q_w⋅(\\omega0 - b_g0) + \\Delta t⋅q_y⋅(\\omega2 - b_g2) - \\Delta\n", - "⎢ \n", - "⎢ \\Delta t⋅q_w⋅(\\omega1 - b_g1) - \\Delta t⋅qₓ⋅(\\omega2 - b_g2) + \\Delta \n", - "⎢ \n", - "⎢ \\Delta t⋅q_w⋅(\\omega2 - b_g2) + \\Delta t⋅qₓ⋅(\\omega1 - b_g1) - \\Delta \n", - "⎢ \n", - "⎢ -\\Delta t⋅qₓ⋅(\\omega0 - b_g0) - \\Delta t⋅q_y⋅(\\omega1 - b_g1) - \\Delta\n", - "⎢ \n", - "⎢ \\Delta t⋅v₀ + p₀ \n", - "⎢ \n", - "⎢ \\Delta t⋅v₁ + p₁ \n", - "⎢ \n", - "⎢ \\Delta t⋅v₂ + p₂ \n", - "⎢ \n", - "⎢ ⎛ 2 2 ⎞ \n", - "⎢ v₀ + (a₀ - bₐ₀)⋅⎝- 2⋅q_y - 2⋅q_z + 1⎠ + (a₁ - bₐ₁)⋅(-2⋅q_w⋅q_z + 2⋅qₓ⋅q_y\n", - "⎢ \n", - "⎢ ⎛ 2 2 ⎞\n", - "⎢ v₁ + (a₀ - bₐ₀)⋅(2⋅q_w⋅q_z + 2⋅qₓ⋅q_y) + (a₁ - bₐ₁)⋅⎝- 2⋅qₓ - 2⋅q_z + 1⎠\n", - "⎢ \n", - "⎢ \n", - "⎢v₂ + (a₀ - bₐ₀)⋅(-2⋅q_w⋅q_y + 2⋅qₓ⋅q_z) + (a₁ - bₐ₁)⋅(2⋅q_w⋅qₓ + 2⋅q_y⋅q_z) +\n", - "⎢ \n", - "⎢ b_g0 \n", - "⎢ \n", - "⎢ b_g1 \n", - "⎢ \n", - "⎢ b_g2 \n", - "⎢ \n", - "⎢ bₐ₀ \n", - "⎢ \n", - "⎢ bₐ₁ \n", - "⎢ \n", - "⎢ bₐ₂ \n", - "⎢ \n", - "⎢ s_{FR}0 \n", - "⎢ \n", - "⎢ s_{FR}1 \n", - "⎢ \n", - "⎢ s_{FR}2 \n", - "⎢ \n", - "⎢ s_{FL}0 \n", - "⎢ \n", - "⎢ s_{FL}1 \n", - "⎢ \n", - "⎢ s_{FL}2 \n", - "⎢ \n", - "⎢ s_{RR}0 \n", - "⎢ \n", - "⎢ s_{RR}1 \n", - "⎢ \n", - "⎢ s_{RR}2 \n", - "⎢ \n", - "⎢ s_{RL}0 \n", - "⎢ \n", - "⎢ s_{RL}1 \n", - "⎢ \n", - "⎣ s_{RL}2 \n", - "\n", - " t⋅q_z⋅(\\omega1 - b_g1) + 1.0⋅qₓ ⎤\n", - " ⎥\n", - "t⋅q_z⋅(\\omega0 - b_g0) + 1.0⋅q_y ⎥\n", - " ⎥\n", - "t⋅q_y⋅(\\omega0 - b_g0) + 1.0⋅q_z ⎥\n", - " ⎥\n", - " t⋅q_z⋅(\\omega2 - b_g2) + 1.0⋅q_w ⎥\n", - " ⎥\n", - " ⎥\n", - " ⎥\n", - " ⎥\n", - " ⎥\n", - " ⎥\n", - " ⎥\n", - " ⎥\n", - ") + (a₂ - bₐ₂)⋅(2⋅q_w⋅q_y + 2⋅qₓ⋅q_z) ⎥\n", - " ⎥\n", - " ⎥\n", - " + (a₂ - bₐ₂)⋅(-2⋅q_w⋅qₓ + 2⋅q_y⋅q_z) ⎥\n", - " ⎥\n", - " ⎛ 2 2 ⎞ ⎥\n", - " (a₂ - bₐ₂)⋅⎝- 2⋅qₓ - 2⋅q_y + 1⎠ + 9.8⎥\n", - " ⎥\n", - " ⎥\n", - " ⎥\n", - " ⎥\n", - " ⎥\n", - " ⎥\n", - " ⎥\n", - " ⎥\n", - " ⎥\n", - " ⎥\n", - " ⎥\n", - " ⎥\n", - " ⎥\n", - " ⎥\n", - " ⎥\n", - " ⎥\n", - " ⎥\n", - " ⎥\n", - " ⎥\n", - " ⎥\n", - " ⎥\n", - " ⎥\n", - " ⎥\n", - " ⎥\n", - " ⎥\n", - " ⎥\n", - " ⎥\n", - " ⎥\n", - " ⎥\n", - " ⎥\n", - " ⎥\n", - " ⎥\n", - " ⎥\n", - " ⎥\n", - " ⎥\n", - " ⎦" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "f_pred = compute_mean(state, u, dT)\n", - "f_pred" - ] - }, - { - "cell_type": "code", - "execution_count": 18, - "metadata": {}, - "outputs": [], - "source": [ - "def compute_measurement( state: sf.matrix_type_from_shape((28,1)), epsilon: sf.Scalar = 0)\\\n", - " -> sf.matrix_type_from_shape((15,1)):\n", - " q = sf.Quaternion(xyz=state[0:3], w=state[3])\n", - " p = state[4:7]\n", - " v = state[7:10]\n", - " b_g = state[10:13]\n", - " b_a = state[13:16]\n", - " s1 = state[16:19]\n", - " s2 = state[19:22]\n", - " s3 = state[22:25]\n", - " s4 = state[25:28]\n", - " R = sf.Rot3(q).to_rotation_matrix()\n", - " z1 = R.T*v\n", - " z2 = R.T*(s1-p)\n", - " z3 = R.T*(s2-p)\n", - " z4 = R.T*(s3-p)\n", - " z5 = R.T*(s4-p)\n", - " h = sf.Matrix.block_matrix([[z1],\n", - " [z2],\n", - " [z3],\n", - " [z4],\n", - " [z5]])\n", - " return h" - ] - }, - { - "cell_type": "code", - "execution_count": 19, - "metadata": {}, - "outputs": [ - { - "data": { - "text/latex": [ - "$\\displaystyle \\left[\\begin{matrix}v_{0} \\left(- 2 q_{y}^{2} - 2 q_{z}^{2} + 1\\right) + v_{1} \\cdot \\left(2 q_{w} q_{z} + 2 q_{x} q_{y}\\right) + v_{2} \\left(- 2 q_{w} q_{y} + 2 q_{x} q_{z}\\right)\\\\v_{0} \\left(- 2 q_{w} q_{z} + 2 q_{x} q_{y}\\right) + v_{1} \\left(- 2 q_{x}^{2} - 2 q_{z}^{2} + 1\\right) + v_{2} \\cdot \\left(2 q_{w} q_{x} + 2 q_{y} q_{z}\\right)\\\\v_{0} \\cdot \\left(2 q_{w} q_{y} + 2 q_{x} q_{z}\\right) + v_{1} \\left(- 2 q_{w} q_{x} + 2 q_{y} q_{z}\\right) + v_{2} \\left(- 2 q_{x}^{2} - 2 q_{y}^{2} + 1\\right)\\\\\\left(- p_{0} + s_{FR}0\\right) \\left(- 2 q_{y}^{2} - 2 q_{z}^{2} + 1\\right) + \\left(- p_{1} + s_{FR}1\\right) \\left(2 q_{w} q_{z} + 2 q_{x} q_{y}\\right) + \\left(- p_{2} + s_{FR}2\\right) \\left(- 2 q_{w} q_{y} + 2 q_{x} q_{z}\\right)\\\\\\left(- p_{0} + s_{FR}0\\right) \\left(- 2 q_{w} q_{z} + 2 q_{x} q_{y}\\right) + \\left(- p_{1} + s_{FR}1\\right) \\left(- 2 q_{x}^{2} - 2 q_{z}^{2} + 1\\right) + \\left(- p_{2} + s_{FR}2\\right) \\left(2 q_{w} q_{x} + 2 q_{y} q_{z}\\right)\\\\\\left(- p_{0} + s_{FR}0\\right) \\left(2 q_{w} q_{y} + 2 q_{x} q_{z}\\right) + \\left(- p_{1} + s_{FR}1\\right) \\left(- 2 q_{w} q_{x} + 2 q_{y} q_{z}\\right) + \\left(- p_{2} + s_{FR}2\\right) \\left(- 2 q_{x}^{2} - 2 q_{y}^{2} + 1\\right)\\\\\\left(- p_{0} + s_{FL}0\\right) \\left(- 2 q_{y}^{2} - 2 q_{z}^{2} + 1\\right) + \\left(- p_{1} + s_{FL}1\\right) \\left(2 q_{w} q_{z} + 2 q_{x} q_{y}\\right) + \\left(- p_{2} + s_{FL}2\\right) \\left(- 2 q_{w} q_{y} + 2 q_{x} q_{z}\\right)\\\\\\left(- p_{0} + s_{FL}0\\right) \\left(- 2 q_{w} q_{z} + 2 q_{x} q_{y}\\right) + \\left(- p_{1} + s_{FL}1\\right) \\left(- 2 q_{x}^{2} - 2 q_{z}^{2} + 1\\right) + \\left(- p_{2} + s_{FL}2\\right) \\left(2 q_{w} q_{x} + 2 q_{y} q_{z}\\right)\\\\\\left(- p_{0} + s_{FL}0\\right) \\left(2 q_{w} q_{y} + 2 q_{x} q_{z}\\right) + \\left(- p_{1} + s_{FL}1\\right) \\left(- 2 q_{w} q_{x} + 2 q_{y} q_{z}\\right) + \\left(- p_{2} + s_{FL}2\\right) \\left(- 2 q_{x}^{2} - 2 q_{y}^{2} + 1\\right)\\\\\\left(- p_{0} + s_{RR}0\\right) \\left(- 2 q_{y}^{2} - 2 q_{z}^{2} + 1\\right) + \\left(- p_{1} + s_{RR}1\\right) \\left(2 q_{w} q_{z} + 2 q_{x} q_{y}\\right) + \\left(- p_{2} + s_{RR}2\\right) \\left(- 2 q_{w} q_{y} + 2 q_{x} q_{z}\\right)\\\\\\left(- p_{0} + s_{RR}0\\right) \\left(- 2 q_{w} q_{z} + 2 q_{x} q_{y}\\right) + \\left(- p_{1} + s_{RR}1\\right) \\left(- 2 q_{x}^{2} - 2 q_{z}^{2} + 1\\right) + \\left(- p_{2} + s_{RR}2\\right) \\left(2 q_{w} q_{x} + 2 q_{y} q_{z}\\right)\\\\\\left(- p_{0} + s_{RR}0\\right) \\left(2 q_{w} q_{y} + 2 q_{x} q_{z}\\right) + \\left(- p_{1} + s_{RR}1\\right) \\left(- 2 q_{w} q_{x} + 2 q_{y} q_{z}\\right) + \\left(- p_{2} + s_{RR}2\\right) \\left(- 2 q_{x}^{2} - 2 q_{y}^{2} + 1\\right)\\\\\\left(- p_{0} + s_{RL}0\\right) \\left(- 2 q_{y}^{2} - 2 q_{z}^{2} + 1\\right) + \\left(- p_{1} + s_{RL}1\\right) \\left(2 q_{w} q_{z} + 2 q_{x} q_{y}\\right) + \\left(- p_{2} + s_{RL}2\\right) \\left(- 2 q_{w} q_{y} + 2 q_{x} q_{z}\\right)\\\\\\left(- p_{0} + s_{RL}0\\right) \\left(- 2 q_{w} q_{z} + 2 q_{x} q_{y}\\right) + \\left(- p_{1} + s_{RL}1\\right) \\left(- 2 q_{x}^{2} - 2 q_{z}^{2} + 1\\right) + \\left(- p_{2} + s_{RL}2\\right) \\left(2 q_{w} q_{x} + 2 q_{y} q_{z}\\right)\\\\\\left(- p_{0} + s_{RL}0\\right) \\left(2 q_{w} q_{y} + 2 q_{x} q_{z}\\right) + \\left(- p_{1} + s_{RL}1\\right) \\left(- 2 q_{w} q_{x} + 2 q_{y} q_{z}\\right) + \\left(- p_{2} + s_{RL}2\\right) \\left(- 2 q_{x}^{2} - 2 q_{y}^{2} + 1\\right)\\end{matrix}\\right]$" - ], - "text/plain": [ - "⎡ ⎛ 2 2 ⎞ \n", - "⎢ v₀⋅⎝- 2⋅q_y - 2⋅q_z + 1⎠ + v₁⋅(2⋅q_w⋅q_z + 2⋅qₓ⋅q_y) + v\n", - "⎢ \n", - "⎢ ⎛ 2 2 ⎞ \n", - "⎢ v₀⋅(-2⋅q_w⋅q_z + 2⋅qₓ⋅q_y) + v₁⋅⎝- 2⋅qₓ - 2⋅q_z + 1⎠ + \n", - "⎢ \n", - "⎢ \n", - "⎢ v₀⋅(2⋅q_w⋅q_y + 2⋅qₓ⋅q_z) + v₁⋅(-2⋅q_w⋅qₓ + 2⋅q_y⋅q_z) + \n", - "⎢ \n", - "⎢ ⎛ 2 2 ⎞ \n", - "⎢(-p₀ + s_{FR}0)⋅⎝- 2⋅q_y - 2⋅q_z + 1⎠ + (-p₁ + s_{FR}1)⋅(2⋅q_w⋅q_z + 2⋅qₓ⋅q\n", - "⎢ \n", - "⎢ ⎛ 2 2 \n", - "⎢(-p₀ + s_{FR}0)⋅(-2⋅q_w⋅q_z + 2⋅qₓ⋅q_y) + (-p₁ + s_{FR}1)⋅⎝- 2⋅qₓ - 2⋅q_z +\n", - "⎢ \n", - "⎢ \n", - "⎢(-p₀ + s_{FR}0)⋅(2⋅q_w⋅q_y + 2⋅qₓ⋅q_z) + (-p₁ + s_{FR}1)⋅(-2⋅q_w⋅qₓ + 2⋅q_y⋅q\n", - "⎢ \n", - "⎢ ⎛ 2 2 ⎞ \n", - "⎢(-p₀ + s_{FL}0)⋅⎝- 2⋅q_y - 2⋅q_z + 1⎠ + (-p₁ + s_{FL}1)⋅(2⋅q_w⋅q_z + 2⋅qₓ⋅q\n", - "⎢ \n", - "⎢ ⎛ 2 2 \n", - "⎢(-p₀ + s_{FL}0)⋅(-2⋅q_w⋅q_z + 2⋅qₓ⋅q_y) + (-p₁ + s_{FL}1)⋅⎝- 2⋅qₓ - 2⋅q_z +\n", - "⎢ \n", - "⎢ \n", - "⎢(-p₀ + s_{FL}0)⋅(2⋅q_w⋅q_y + 2⋅qₓ⋅q_z) + (-p₁ + s_{FL}1)⋅(-2⋅q_w⋅qₓ + 2⋅q_y⋅q\n", - "⎢ \n", - "⎢ ⎛ 2 2 ⎞ \n", - "⎢(-p₀ + s_{RR}0)⋅⎝- 2⋅q_y - 2⋅q_z + 1⎠ + (-p₁ + s_{RR}1)⋅(2⋅q_w⋅q_z + 2⋅qₓ⋅q\n", - "⎢ \n", - "⎢ ⎛ 2 2 \n", - "⎢(-p₀ + s_{RR}0)⋅(-2⋅q_w⋅q_z + 2⋅qₓ⋅q_y) + (-p₁ + s_{RR}1)⋅⎝- 2⋅qₓ - 2⋅q_z +\n", - "⎢ \n", - "⎢ \n", - "⎢(-p₀ + s_{RR}0)⋅(2⋅q_w⋅q_y + 2⋅qₓ⋅q_z) + (-p₁ + s_{RR}1)⋅(-2⋅q_w⋅qₓ + 2⋅q_y⋅q\n", - "⎢ \n", - "⎢ ⎛ 2 2 ⎞ \n", - "⎢(-p₀ + s_{RL}0)⋅⎝- 2⋅q_y - 2⋅q_z + 1⎠ + (-p₁ + s_{RL}1)⋅(2⋅q_w⋅q_z + 2⋅qₓ⋅q\n", - "⎢ \n", - "⎢ ⎛ 2 2 \n", - "⎢(-p₀ + s_{RL}0)⋅(-2⋅q_w⋅q_z + 2⋅qₓ⋅q_y) + (-p₁ + s_{RL}1)⋅⎝- 2⋅qₓ - 2⋅q_z +\n", - "⎢ \n", - "⎢ \n", - "⎣(-p₀ + s_{RL}0)⋅(2⋅q_w⋅q_y + 2⋅qₓ⋅q_z) + (-p₁ + s_{RL}1)⋅(-2⋅q_w⋅qₓ + 2⋅q_y⋅q\n", - "\n", - " ⎤\n", - "₂⋅(-2⋅q_w⋅q_y + 2⋅qₓ⋅q_z) ⎥\n", - " ⎥\n", - " ⎥\n", - "v₂⋅(2⋅q_w⋅qₓ + 2⋅q_y⋅q_z) ⎥\n", - " ⎥\n", - " ⎛ 2 2 ⎞ ⎥\n", - "v₂⋅⎝- 2⋅qₓ - 2⋅q_y + 1⎠ ⎥\n", - " ⎥\n", - " ⎥\n", - "_y) + (-p₂ + s_{FR}2)⋅(-2⋅q_w⋅q_y + 2⋅qₓ⋅q_z)⎥\n", - " ⎥\n", - " ⎞ ⎥\n", - " 1⎠ + (-p₂ + s_{FR}2)⋅(2⋅q_w⋅qₓ + 2⋅q_y⋅q_z) ⎥\n", - " ⎥\n", - " ⎛ 2 2 ⎞ ⎥\n", - "_z) + (-p₂ + s_{FR}2)⋅⎝- 2⋅qₓ - 2⋅q_y + 1⎠ ⎥\n", - " ⎥\n", - " ⎥\n", - "_y) + (-p₂ + s_{FL}2)⋅(-2⋅q_w⋅q_y + 2⋅qₓ⋅q_z)⎥\n", - " ⎥\n", - " ⎞ ⎥\n", - " 1⎠ + (-p₂ + s_{FL}2)⋅(2⋅q_w⋅qₓ + 2⋅q_y⋅q_z) ⎥\n", - " ⎥\n", - " ⎛ 2 2 ⎞ ⎥\n", - "_z) + (-p₂ + s_{FL}2)⋅⎝- 2⋅qₓ - 2⋅q_y + 1⎠ ⎥\n", - " ⎥\n", - " ⎥\n", - "_y) + (-p₂ + s_{RR}2)⋅(-2⋅q_w⋅q_y + 2⋅qₓ⋅q_z)⎥\n", - " ⎥\n", - " ⎞ ⎥\n", - " 1⎠ + (-p₂ + s_{RR}2)⋅(2⋅q_w⋅qₓ + 2⋅q_y⋅q_z) ⎥\n", - " ⎥\n", - " ⎛ 2 2 ⎞ ⎥\n", - "_z) + (-p₂ + s_{RR}2)⋅⎝- 2⋅qₓ - 2⋅q_y + 1⎠ ⎥\n", - " ⎥\n", - " ⎥\n", - "_y) + (-p₂ + s_{RL}2)⋅(-2⋅q_w⋅q_y + 2⋅qₓ⋅q_z)⎥\n", - " ⎥\n", - " ⎞ ⎥\n", - " 1⎠ + (-p₂ + s_{RL}2)⋅(2⋅q_w⋅qₓ + 2⋅q_y⋅q_z) ⎥\n", - " ⎥\n", - " ⎛ 2 2 ⎞ ⎥\n", - "_z) + (-p₂ + s_{RL}2)⋅⎝- 2⋅qₓ - 2⋅q_y + 1⎠ ⎦" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "compute_measurement(state)" - ] - }, - { - "cell_type": "code", - "execution_count": 20, - "metadata": {}, - "outputs": [], - "source": [ - "from symforce import codegen\n", - "from symforce.codegen import codegen_util\n", - "from symforce.notebook_util import display\n", - "from symforce.notebook_util import display_code_file\n", - "from symforce.values import Values" - ] - }, - { - "cell_type": "code", - "execution_count": 21, - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "codegen.__init__():141 WARNING -- \n", - " Generating code with epsilon set to 0 - This is dangerous! You may get NaNs, Infs,\n", - " or numerically unstable results from calling generated functions near singularities.\n", - "\n", - " In order to safely generate code, you should set epsilon to either a symbol\n", - " (recommended) or a small numerical value like `sf.numeric_epsilon`. You should do\n", - " this before importing any other code from symforce, e.g. with\n", - "\n", - " import symforce\n", - " symforce.set_epsilon_to_symbol()\n", - "\n", - " or\n", - "\n", - " import symforce\n", - " symforce.set_epsilon_to_number()\n", - "\n", - " For more information on use of epsilon to prevent singularities, take a look at the\n", - " Epsilon Tutorial: https://symforce.org/tutorials/epsilon_tutorial.html\n", - "\n", - "codegen.__init__():141 WARNING -- \n", - " Generating code with epsilon set to 0 - This is dangerous! You may get NaNs, Infs,\n", - " or numerically unstable results from calling generated functions near singularities.\n", - "\n", - " In order to safely generate code, you should set epsilon to either a symbol\n", - " (recommended) or a small numerical value like `sf.numeric_epsilon`. You should do\n", - " this before importing any other code from symforce, e.g. with\n", - "\n", - " import symforce\n", - " symforce.set_epsilon_to_symbol()\n", - "\n", - " or\n", - "\n", - " import symforce\n", - " symforce.set_epsilon_to_number()\n", - "\n", - " For more information on use of epsilon to prevent singularities, take a look at the\n", - " Epsilon Tutorial: https://symforce.org/tutorials/epsilon_tutorial.html\n", - "\n" - ] - }, - { - "data": { - "text/html": [ - "
// -----------------------------------------------------------------------------\n",
-       "// This file was autogenerated by symforce from template:\n",
-       "//     function/FUNCTION.h.jinja\n",
-       "// Do NOT modify by hand.\n",
-       "// -----------------------------------------------------------------------------\n",
-       "\n",
-       "#pragma once\n",
-       "\n",
-       "#include <Eigen/Dense>\n",
-       "\n",
-       "namespace sym {\n",
-       "\n",
-       "/**\n",
-       " * This function was autogenerated from a symbolic function. Do not modify by hand.\n",
-       " *\n",
-       " * Symbolic function: compute_measurement\n",
-       " *\n",
-       " * Args:\n",
-       " *     state: Matrix28_1\n",
-       " *     epsilon: Scalar\n",
-       " *\n",
-       " * Outputs:\n",
-       " *     res: Matrix15_1\n",
-       " *     res_D_state: (15x28) jacobian of res (15) wrt arg state (28)\n",
-       " */\n",
-       "template <typename Scalar>\n",
-       "Eigen::Matrix<Scalar, 15, 1> ComputeMeasurementWithJacobian0(\n",
-       "    const Eigen::Matrix<Scalar, 28, 1>& state, const Scalar epsilon,\n",
-       "    Eigen::Matrix<Scalar, 15, 28>* const res_D_state = nullptr) {\n",
-       "  // Total ops: 339\n",
-       "\n",
-       "  // Unused inputs\n",
-       "  (void)epsilon;\n",
-       "\n",
-       "  // Input arrays\n",
-       "\n",
-       "  // Intermediate terms (99)\n",
-       "  const Scalar _tmp0 = 2 * state(1, 0);\n",
-       "  const Scalar _tmp1 = _tmp0 * state(0, 0);\n",
-       "  const Scalar _tmp2 = 2 * state(2, 0);\n",
-       "  const Scalar _tmp3 = _tmp2 * state(3, 0);\n",
-       "  const Scalar _tmp4 = _tmp1 + _tmp3;\n",
-       "  const Scalar _tmp5 = _tmp2 * state(0, 0);\n",
-       "  const Scalar _tmp6 = _tmp0 * state(3, 0);\n",
-       "  const Scalar _tmp7 = _tmp5 - _tmp6;\n",
-       "  const Scalar _tmp8 = 2 * std::pow(state(1, 0), Scalar(2));\n",
-       "  const Scalar _tmp9 = 2 * std::pow(state(2, 0), Scalar(2)) - 1;\n",
-       "  const Scalar _tmp10 = _tmp8 + _tmp9;\n",
-       "  const Scalar _tmp11 = -_tmp10;\n",
-       "  const Scalar _tmp12 = _tmp1 - _tmp3;\n",
-       "  const Scalar _tmp13 = 2 * state(3, 0);\n",
-       "  const Scalar _tmp14 = _tmp13 * state(0, 0);\n",
-       "  const Scalar _tmp15 = _tmp0 * state(2, 0);\n",
-       "  const Scalar _tmp16 = _tmp14 + _tmp15;\n",
-       "  const Scalar _tmp17 = 2 * std::pow(state(0, 0), Scalar(2));\n",
-       "  const Scalar _tmp18 = _tmp17 + _tmp9;\n",
-       "  const Scalar _tmp19 = -_tmp18;\n",
-       "  const Scalar _tmp20 = _tmp5 + _tmp6;\n",
-       "  const Scalar _tmp21 = _tmp14 - _tmp15;\n",
-       "  const Scalar _tmp22 = -_tmp21;\n",
-       "  const Scalar _tmp23 = _tmp17 + _tmp8 - 1;\n",
-       "  const Scalar _tmp24 = -_tmp23;\n",
-       "  const Scalar _tmp25 = -state(5, 0);\n",
-       "  const Scalar _tmp26 = _tmp25 + state(17, 0);\n",
-       "  const Scalar _tmp27 = -state(6, 0);\n",
-       "  const Scalar _tmp28 = _tmp27 + state(18, 0);\n",
-       "  const Scalar _tmp29 = -state(4, 0);\n",
-       "  const Scalar _tmp30 = _tmp29 + state(16, 0);\n",
-       "  const Scalar _tmp31 = _tmp25 + state(20, 0);\n",
-       "  const Scalar _tmp32 = _tmp27 + state(21, 0);\n",
-       "  const Scalar _tmp33 = _tmp29 + state(19, 0);\n",
-       "  const Scalar _tmp34 = _tmp25 + state(23, 0);\n",
-       "  const Scalar _tmp35 = _tmp27 + state(24, 0);\n",
-       "  const Scalar _tmp36 = _tmp29 + state(22, 0);\n",
-       "  const Scalar _tmp37 = _tmp25 + state(26, 0);\n",
-       "  const Scalar _tmp38 = _tmp27 + state(27, 0);\n",
-       "  const Scalar _tmp39 = _tmp29 + state(25, 0);\n",
-       "  const Scalar _tmp40 = _tmp0 * state(8, 0);\n",
-       "  const Scalar _tmp41 = _tmp2 * state(9, 0);\n",
-       "  const Scalar _tmp42 = 4 * state(0, 0);\n",
-       "  const Scalar _tmp43 = _tmp13 * state(9, 0);\n",
-       "  const Scalar _tmp44 = -_tmp2 * state(7, 0);\n",
-       "  const Scalar _tmp45 = _tmp13 * state(8, 0);\n",
-       "  const Scalar _tmp46 = _tmp0 * _tmp26;\n",
-       "  const Scalar _tmp47 = _tmp2 * _tmp28;\n",
-       "  const Scalar _tmp48 = _tmp13 * _tmp28;\n",
-       "  const Scalar _tmp49 = -_tmp2 * _tmp30;\n",
-       "  const Scalar _tmp50 = _tmp13 * _tmp26;\n",
-       "  const Scalar _tmp51 = _tmp0 * _tmp31;\n",
-       "  const Scalar _tmp52 = _tmp2 * _tmp32;\n",
-       "  const Scalar _tmp53 = _tmp13 * _tmp32;\n",
-       "  const Scalar _tmp54 = -_tmp2 * _tmp33;\n",
-       "  const Scalar _tmp55 = _tmp13 * _tmp31;\n",
-       "  const Scalar _tmp56 = _tmp0 * _tmp34;\n",
-       "  const Scalar _tmp57 = _tmp2 * _tmp35;\n",
-       "  const Scalar _tmp58 = _tmp13 * _tmp35;\n",
-       "  const Scalar _tmp59 = -_tmp2 * _tmp36;\n",
-       "  const Scalar _tmp60 = _tmp13 * _tmp34;\n",
-       "  const Scalar _tmp61 = _tmp0 * _tmp37;\n",
-       "  const Scalar _tmp62 = _tmp2 * _tmp38;\n",
-       "  const Scalar _tmp63 = _tmp13 * _tmp38;\n",
-       "  const Scalar _tmp64 = -_tmp2 * _tmp39;\n",
-       "  const Scalar _tmp65 = _tmp13 * _tmp37;\n",
-       "  const Scalar _tmp66 = 2 * state(0, 0);\n",
-       "  const Scalar _tmp67 = _tmp66 * state(8, 0);\n",
-       "  const Scalar _tmp68 = 4 * state(1, 0);\n",
-       "  const Scalar _tmp69 = _tmp66 * state(7, 0);\n",
-       "  const Scalar _tmp70 = _tmp13 * state(7, 0);\n",
-       "  const Scalar _tmp71 = _tmp26 * _tmp66;\n",
-       "  const Scalar _tmp72 = _tmp30 * _tmp66;\n",
-       "  const Scalar _tmp73 = _tmp13 * _tmp30;\n",
-       "  const Scalar _tmp74 = _tmp31 * _tmp66;\n",
-       "  const Scalar _tmp75 = _tmp33 * _tmp66;\n",
-       "  const Scalar _tmp76 = _tmp13 * _tmp33;\n",
-       "  const Scalar _tmp77 = _tmp34 * _tmp66;\n",
-       "  const Scalar _tmp78 = _tmp36 * _tmp66;\n",
-       "  const Scalar _tmp79 = _tmp13 * _tmp36;\n",
-       "  const Scalar _tmp80 = _tmp37 * _tmp66;\n",
-       "  const Scalar _tmp81 = _tmp39 * _tmp66;\n",
-       "  const Scalar _tmp82 = _tmp13 * _tmp39;\n",
-       "  const Scalar _tmp83 = _tmp66 * state(9, 0);\n",
-       "  const Scalar _tmp84 = 4 * state(2, 0);\n",
-       "  const Scalar _tmp85 = _tmp0 * state(9, 0);\n",
-       "  const Scalar _tmp86 = _tmp28 * _tmp66;\n",
-       "  const Scalar _tmp87 = _tmp0 * _tmp28;\n",
-       "  const Scalar _tmp88 = _tmp32 * _tmp66;\n",
-       "  const Scalar _tmp89 = _tmp0 * _tmp32;\n",
-       "  const Scalar _tmp90 = _tmp35 * _tmp66;\n",
-       "  const Scalar _tmp91 = _tmp0 * _tmp35;\n",
-       "  const Scalar _tmp92 = _tmp38 * _tmp66;\n",
-       "  const Scalar _tmp93 = _tmp0 * _tmp38;\n",
-       "  const Scalar _tmp94 = -_tmp12;\n",
-       "  const Scalar _tmp95 = -_tmp20;\n",
-       "  const Scalar _tmp96 = -_tmp4;\n",
-       "  const Scalar _tmp97 = -_tmp7;\n",
-       "  const Scalar _tmp98 = -_tmp16;\n",
-       "\n",
-       "  // Output terms (2)\n",
-       "  Eigen::Matrix<Scalar, 15, 1> _res;\n",
-       "\n",
-       "  _res(0, 0) = _tmp11 * state(7, 0) + _tmp4 * state(8, 0) + _tmp7 * state(9, 0);\n",
-       "  _res(1, 0) = _tmp12 * state(7, 0) + _tmp16 * state(9, 0) + _tmp19 * state(8, 0);\n",
-       "  _res(2, 0) = _tmp20 * state(7, 0) + _tmp22 * state(8, 0) + _tmp24 * state(9, 0);\n",
-       "  _res(3, 0) = _tmp11 * _tmp30 + _tmp26 * _tmp4 + _tmp28 * _tmp7;\n",
-       "  _res(4, 0) = _tmp12 * _tmp30 + _tmp16 * _tmp28 + _tmp19 * _tmp26;\n",
-       "  _res(5, 0) = _tmp20 * _tmp30 + _tmp22 * _tmp26 + _tmp24 * _tmp28;\n",
-       "  _res(6, 0) = _tmp11 * _tmp33 + _tmp31 * _tmp4 + _tmp32 * _tmp7;\n",
-       "  _res(7, 0) = _tmp12 * _tmp33 + _tmp16 * _tmp32 + _tmp19 * _tmp31;\n",
-       "  _res(8, 0) = _tmp20 * _tmp33 + _tmp22 * _tmp31 + _tmp24 * _tmp32;\n",
-       "  _res(9, 0) = _tmp11 * _tmp36 + _tmp34 * _tmp4 + _tmp35 * _tmp7;\n",
-       "  _res(10, 0) = _tmp12 * _tmp36 + _tmp16 * _tmp35 + _tmp19 * _tmp34;\n",
-       "  _res(11, 0) = _tmp20 * _tmp36 + _tmp22 * _tmp34 + _tmp24 * _tmp35;\n",
-       "  _res(12, 0) = _tmp11 * _tmp39 + _tmp37 * _tmp4 + _tmp38 * _tmp7;\n",
-       "  _res(13, 0) = _tmp12 * _tmp39 + _tmp16 * _tmp38 + _tmp19 * _tmp37;\n",
-       "  _res(14, 0) = _tmp20 * _tmp39 + _tmp22 * _tmp37 + _tmp24 * _tmp38;\n",
-       "\n",
-       "  if (res_D_state != nullptr) {\n",
-       "    Eigen::Matrix<Scalar, 15, 28>& _res_D_state = (*res_D_state);\n",
-       "\n",
-       "    _res_D_state.setZero();\n",
-       "\n",
-       "    _res_D_state(0, 0) = _tmp40 + _tmp41;\n",
-       "    _res_D_state(1, 0) = _tmp0 * state(7, 0) - _tmp42 * state(8, 0) + _tmp43;\n",
-       "    _res_D_state(2, 0) = -_tmp42 * state(9, 0) - _tmp44 - _tmp45;\n",
-       "    _res_D_state(3, 0) = _tmp46 + _tmp47;\n",
-       "    _res_D_state(4, 0) = _tmp0 * _tmp30 - _tmp26 * _tmp42 + _tmp48;\n",
-       "    _res_D_state(5, 0) = -_tmp28 * _tmp42 - _tmp49 - _tmp50;\n",
-       "    _res_D_state(6, 0) = _tmp51 + _tmp52;\n",
-       "    _res_D_state(7, 0) = _tmp0 * _tmp33 - _tmp31 * _tmp42 + _tmp53;\n",
-       "    _res_D_state(8, 0) = -_tmp32 * _tmp42 - _tmp54 - _tmp55;\n",
-       "    _res_D_state(9, 0) = _tmp56 + _tmp57;\n",
-       "    _res_D_state(10, 0) = _tmp0 * _tmp36 - _tmp34 * _tmp42 + _tmp58;\n",
-       "    _res_D_state(11, 0) = -_tmp35 * _tmp42 - _tmp59 - _tmp60;\n",
-       "    _res_D_state(12, 0) = _tmp61 + _tmp62;\n",
-       "    _res_D_state(13, 0) = _tmp0 * _tmp39 - _tmp37 * _tmp42 + _tmp63;\n",
-       "    _res_D_state(14, 0) = -_tmp38 * _tmp42 - _tmp64 - _tmp65;\n",
-       "    _res_D_state(0, 1) = -_tmp43 + _tmp67 - _tmp68 * state(7, 0);\n",
-       "    _res_D_state(1, 1) = _tmp41 + _tmp69;\n",
-       "    _res_D_state(2, 1) = _tmp2 * state(8, 0) - _tmp68 * state(9, 0) + _tmp70;\n",
-       "    _res_D_state(3, 1) = -_tmp30 * _tmp68 - _tmp48 + _tmp71;\n",
-       "    _res_D_state(4, 1) = _tmp47 + _tmp72;\n",
-       "    _res_D_state(5, 1) = _tmp2 * _tmp26 - _tmp28 * _tmp68 + _tmp73;\n",
-       "    _res_D_state(6, 1) = -_tmp33 * _tmp68 - _tmp53 + _tmp74;\n",
-       "    _res_D_state(7, 1) = _tmp52 + _tmp75;\n",
-       "    _res_D_state(8, 1) = _tmp2 * _tmp31 - _tmp32 * _tmp68 + _tmp76;\n",
-       "    _res_D_state(9, 1) = -_tmp36 * _tmp68 - _tmp58 + _tmp77;\n",
-       "    _res_D_state(10, 1) = _tmp57 + _tmp78;\n",
-       "    _res_D_state(11, 1) = _tmp2 * _tmp34 - _tmp35 * _tmp68 + _tmp79;\n",
-       "    _res_D_state(12, 1) = -_tmp39 * _tmp68 - _tmp63 + _tmp80;\n",
-       "    _res_D_state(13, 1) = _tmp62 + _tmp81;\n",
-       "    _res_D_state(14, 1) = _tmp2 * _tmp37 - _tmp38 * _tmp68 + _tmp82;\n",
-       "    _res_D_state(0, 2) = _tmp45 + _tmp83 - _tmp84 * state(7, 0);\n",
-       "    _res_D_state(1, 2) = -_tmp70 - _tmp84 * state(8, 0) + _tmp85;\n",
-       "    _res_D_state(2, 2) = _tmp40 + _tmp69;\n",
-       "    _res_D_state(3, 2) = -_tmp30 * _tmp84 + _tmp50 + _tmp86;\n",
-       "    _res_D_state(4, 2) = -_tmp26 * _tmp84 - _tmp73 + _tmp87;\n",
-       "    _res_D_state(5, 2) = _tmp46 + _tmp72;\n",
-       "    _res_D_state(6, 2) = -_tmp33 * _tmp84 + _tmp55 + _tmp88;\n",
-       "    _res_D_state(7, 2) = -_tmp31 * _tmp84 - _tmp76 + _tmp89;\n",
-       "    _res_D_state(8, 2) = _tmp51 + _tmp75;\n",
-       "    _res_D_state(9, 2) = -_tmp36 * _tmp84 + _tmp60 + _tmp90;\n",
-       "    _res_D_state(10, 2) = -_tmp34 * _tmp84 - _tmp79 + _tmp91;\n",
-       "    _res_D_state(11, 2) = _tmp56 + _tmp78;\n",
-       "    _res_D_state(12, 2) = -_tmp39 * _tmp84 + _tmp65 + _tmp92;\n",
-       "    _res_D_state(13, 2) = -_tmp37 * _tmp84 - _tmp82 + _tmp93;\n",
-       "    _res_D_state(14, 2) = _tmp61 + _tmp81;\n",
-       "    _res_D_state(0, 3) = -_tmp85 + 2 * state(2, 0) * state(8, 0);\n",
-       "    _res_D_state(1, 3) = _tmp44 + _tmp83;\n",
-       "    _res_D_state(2, 3) = -_tmp67 + 2 * state(1, 0) * state(7, 0);\n",
-       "    _res_D_state(3, 3) = 2 * _tmp26 * state(2, 0) - _tmp87;\n",
-       "    _res_D_state(4, 3) = _tmp49 + _tmp86;\n",
-       "    _res_D_state(5, 3) = 2 * _tmp30 * state(1, 0) - _tmp71;\n",
-       "    _res_D_state(6, 3) = 2 * _tmp31 * state(2, 0) - _tmp89;\n",
-       "    _res_D_state(7, 3) = _tmp54 + _tmp88;\n",
-       "    _res_D_state(8, 3) = 2 * _tmp33 * state(1, 0) - _tmp74;\n",
-       "    _res_D_state(9, 3) = 2 * _tmp34 * state(2, 0) - _tmp91;\n",
-       "    _res_D_state(10, 3) = _tmp59 + _tmp90;\n",
-       "    _res_D_state(11, 3) = 2 * _tmp36 * state(1, 0) - _tmp77;\n",
-       "    _res_D_state(12, 3) = 2 * _tmp37 * state(2, 0) - _tmp93;\n",
-       "    _res_D_state(13, 3) = _tmp64 + _tmp92;\n",
-       "    _res_D_state(14, 3) = 2 * _tmp39 * state(1, 0) - _tmp80;\n",
-       "    _res_D_state(3, 4) = _tmp10;\n",
-       "    _res_D_state(4, 4) = _tmp94;\n",
-       "    _res_D_state(5, 4) = _tmp95;\n",
-       "    _res_D_state(6, 4) = _tmp10;\n",
-       "    _res_D_state(7, 4) = _tmp94;\n",
-       "    _res_D_state(8, 4) = _tmp95;\n",
-       "    _res_D_state(9, 4) = _tmp10;\n",
-       "    _res_D_state(10, 4) = _tmp94;\n",
-       "    _res_D_state(11, 4) = _tmp95;\n",
-       "    _res_D_state(12, 4) = _tmp10;\n",
-       "    _res_D_state(13, 4) = _tmp94;\n",
-       "    _res_D_state(14, 4) = _tmp95;\n",
-       "    _res_D_state(3, 5) = _tmp96;\n",
-       "    _res_D_state(4, 5) = _tmp18;\n",
-       "    _res_D_state(5, 5) = _tmp21;\n",
-       "    _res_D_state(6, 5) = _tmp96;\n",
-       "    _res_D_state(7, 5) = _tmp18;\n",
-       "    _res_D_state(8, 5) = _tmp21;\n",
-       "    _res_D_state(9, 5) = _tmp96;\n",
-       "    _res_D_state(10, 5) = _tmp18;\n",
-       "    _res_D_state(11, 5) = _tmp21;\n",
-       "    _res_D_state(12, 5) = _tmp96;\n",
-       "    _res_D_state(13, 5) = _tmp18;\n",
-       "    _res_D_state(14, 5) = _tmp21;\n",
-       "    _res_D_state(3, 6) = _tmp97;\n",
-       "    _res_D_state(4, 6) = _tmp98;\n",
-       "    _res_D_state(5, 6) = _tmp23;\n",
-       "    _res_D_state(6, 6) = _tmp97;\n",
-       "    _res_D_state(7, 6) = _tmp98;\n",
-       "    _res_D_state(8, 6) = _tmp23;\n",
-       "    _res_D_state(9, 6) = _tmp97;\n",
-       "    _res_D_state(10, 6) = _tmp98;\n",
-       "    _res_D_state(11, 6) = _tmp23;\n",
-       "    _res_D_state(12, 6) = _tmp97;\n",
-       "    _res_D_state(13, 6) = _tmp98;\n",
-       "    _res_D_state(14, 6) = _tmp23;\n",
-       "    _res_D_state(0, 7) = _tmp11;\n",
-       "    _res_D_state(1, 7) = _tmp12;\n",
-       "    _res_D_state(2, 7) = _tmp20;\n",
-       "    _res_D_state(0, 8) = _tmp4;\n",
-       "    _res_D_state(1, 8) = _tmp19;\n",
-       "    _res_D_state(2, 8) = _tmp22;\n",
-       "    _res_D_state(0, 9) = _tmp7;\n",
-       "    _res_D_state(1, 9) = _tmp16;\n",
-       "    _res_D_state(2, 9) = _tmp24;\n",
-       "    _res_D_state(3, 16) = _tmp11;\n",
-       "    _res_D_state(4, 16) = _tmp12;\n",
-       "    _res_D_state(5, 16) = _tmp20;\n",
-       "    _res_D_state(3, 17) = _tmp4;\n",
-       "    _res_D_state(4, 17) = _tmp19;\n",
-       "    _res_D_state(5, 17) = _tmp22;\n",
-       "    _res_D_state(3, 18) = _tmp7;\n",
-       "    _res_D_state(4, 18) = _tmp16;\n",
-       "    _res_D_state(5, 18) = _tmp24;\n",
-       "    _res_D_state(6, 19) = _tmp11;\n",
-       "    _res_D_state(7, 19) = _tmp12;\n",
-       "    _res_D_state(8, 19) = _tmp20;\n",
-       "    _res_D_state(6, 20) = _tmp4;\n",
-       "    _res_D_state(7, 20) = _tmp19;\n",
-       "    _res_D_state(8, 20) = _tmp22;\n",
-       "    _res_D_state(6, 21) = _tmp7;\n",
-       "    _res_D_state(7, 21) = _tmp16;\n",
-       "    _res_D_state(8, 21) = _tmp24;\n",
-       "    _res_D_state(9, 22) = _tmp11;\n",
-       "    _res_D_state(10, 22) = _tmp12;\n",
-       "    _res_D_state(11, 22) = _tmp20;\n",
-       "    _res_D_state(9, 23) = _tmp4;\n",
-       "    _res_D_state(10, 23) = _tmp19;\n",
-       "    _res_D_state(11, 23) = _tmp22;\n",
-       "    _res_D_state(9, 24) = _tmp7;\n",
-       "    _res_D_state(10, 24) = _tmp16;\n",
-       "    _res_D_state(11, 24) = _tmp24;\n",
-       "    _res_D_state(12, 25) = _tmp11;\n",
-       "    _res_D_state(13, 25) = _tmp12;\n",
-       "    _res_D_state(14, 25) = _tmp20;\n",
-       "    _res_D_state(12, 26) = _tmp4;\n",
-       "    _res_D_state(13, 26) = _tmp19;\n",
-       "    _res_D_state(14, 26) = _tmp22;\n",
-       "    _res_D_state(12, 27) = _tmp7;\n",
-       "    _res_D_state(13, 27) = _tmp16;\n",
-       "    _res_D_state(14, 27) = _tmp24;\n",
-       "  }\n",
-       "\n",
-       "  return _res;\n",
-       "}  // NOLINT(readability/fn_size)\n",
-       "\n",
-       "// NOLINTNEXTLINE(readability/fn_size)\n",
-       "}  // namespace sym\n",
-       "
\n" - ], - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "compute_measurement_codegen = codegen.Codegen.function(\n", - " func=compute_measurement,\n", - " config=codegen.CppConfig(),\n", - ")\n", - "\n", - "codegen_with_jacobians = compute_measurement_codegen.with_jacobians(\n", - " # Just compute wrt the pose and point, not epsilon\n", - " which_args=[\"state\"],\n", - " # Include value, not just jacobians\n", - " include_results=True,\n", - ")\n", - "\n", - "data = codegen_with_jacobians.generate_function()\n", - "\n", - "display_code_file(data.generated_files[0], \"C++\")\n" - ] - }, - { - "cell_type": "code", - "execution_count": 22, - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "codegen.__init__():141 WARNING -- \n", - " Generating code with epsilon set to 0 - This is dangerous! You may get NaNs, Infs,\n", - " or numerically unstable results from calling generated functions near singularities.\n", - "\n", - " In order to safely generate code, you should set epsilon to either a symbol\n", - " (recommended) or a small numerical value like `sf.numeric_epsilon`. You should do\n", - " this before importing any other code from symforce, e.g. with\n", - "\n", - " import symforce\n", - " symforce.set_epsilon_to_symbol()\n", - "\n", - " or\n", - "\n", - " import symforce\n", - " symforce.set_epsilon_to_number()\n", - "\n", - " For more information on use of epsilon to prevent singularities, take a look at the\n", - " Epsilon Tutorial: https://symforce.org/tutorials/epsilon_tutorial.html\n", - "\n", - "codegen.__init__():141 WARNING -- \n", - " Generating code with epsilon set to 0 - This is dangerous! You may get NaNs, Infs,\n", - " or numerically unstable results from calling generated functions near singularities.\n", - "\n", - " In order to safely generate code, you should set epsilon to either a symbol\n", - " (recommended) or a small numerical value like `sf.numeric_epsilon`. You should do\n", - " this before importing any other code from symforce, e.g. with\n", - "\n", - " import symforce\n", - " symforce.set_epsilon_to_symbol()\n", - "\n", - " or\n", - "\n", - " import symforce\n", - " symforce.set_epsilon_to_number()\n", - "\n", - " For more information on use of epsilon to prevent singularities, take a look at the\n", - " Epsilon Tutorial: https://symforce.org/tutorials/epsilon_tutorial.html\n", - "\n" - ] - }, - { - "data": { - "text/html": [ - "
// -----------------------------------------------------------------------------\n",
-       "// This file was autogenerated by symforce from template:\n",
-       "//     function/FUNCTION.h.jinja\n",
-       "// Do NOT modify by hand.\n",
-       "// -----------------------------------------------------------------------------\n",
-       "\n",
-       "#pragma once\n",
-       "\n",
-       "#include <Eigen/Dense>\n",
-       "\n",
-       "namespace sym {\n",
-       "\n",
-       "/**\n",
-       " * This function was autogenerated from a symbolic function. Do not modify by hand.\n",
-       " *\n",
-       " * Symbolic function: compute_mean\n",
-       " *\n",
-       " * Args:\n",
-       " *     state: Matrix28_1\n",
-       " *     u: Matrix61\n",
-       " *     dT: Scalar\n",
-       " *     epsilon: Scalar\n",
-       " *\n",
-       " * Outputs:\n",
-       " *     res: Matrix28_1\n",
-       " *     res_D_state: (28x28) jacobian of res (28) wrt arg state (28)\n",
-       " */\n",
-       "template <typename Scalar>\n",
-       "Eigen::Matrix<Scalar, 28, 1> ComputeMeanWithJacobian0(\n",
-       "    const Eigen::Matrix<Scalar, 28, 1>& state, const Eigen::Matrix<Scalar, 6, 1>& u,\n",
-       "    const Scalar dT, const Scalar epsilon,\n",
-       "    Eigen::Matrix<Scalar, 28, 28>* const res_D_state = nullptr) {\n",
-       "  // Total ops: 150\n",
-       "\n",
-       "  // Unused inputs\n",
-       "  (void)epsilon;\n",
-       "\n",
-       "  // Input arrays\n",
-       "\n",
-       "  // Intermediate terms (49)\n",
-       "  const Scalar _tmp0 = dT * (-state(12, 0) + u(2, 0));\n",
-       "  const Scalar _tmp1 = dT * (-state(10, 0) + u(0, 0));\n",
-       "  const Scalar _tmp2 = dT * (-state(11, 0) + u(1, 0));\n",
-       "  const Scalar _tmp3 = -state(14, 0) + u(4, 0);\n",
-       "  const Scalar _tmp4 = 2 * state(1, 0);\n",
-       "  const Scalar _tmp5 = _tmp4 * state(0, 0);\n",
-       "  const Scalar _tmp6 = 2 * state(2, 0);\n",
-       "  const Scalar _tmp7 = _tmp6 * state(3, 0);\n",
-       "  const Scalar _tmp8 = _tmp5 - _tmp7;\n",
-       "  const Scalar _tmp9 = -state(15, 0) + u(5, 0);\n",
-       "  const Scalar _tmp10 = _tmp6 * state(0, 0);\n",
-       "  const Scalar _tmp11 = _tmp4 * state(3, 0);\n",
-       "  const Scalar _tmp12 = _tmp10 + _tmp11;\n",
-       "  const Scalar _tmp13 = -state(13, 0) + u(3, 0);\n",
-       "  const Scalar _tmp14 = 2 * std::pow(state(1, 0), Scalar(2));\n",
-       "  const Scalar _tmp15 = 2 * std::pow(state(2, 0), Scalar(2)) - 1;\n",
-       "  const Scalar _tmp16 = _tmp14 + _tmp15;\n",
-       "  const Scalar _tmp17 = _tmp5 + _tmp7;\n",
-       "  const Scalar _tmp18 = 2 * state(3, 0);\n",
-       "  const Scalar _tmp19 = _tmp18 * state(0, 0);\n",
-       "  const Scalar _tmp20 = _tmp6 * state(1, 0);\n",
-       "  const Scalar _tmp21 = _tmp19 - _tmp20;\n",
-       "  const Scalar _tmp22 = 2 * std::pow(state(0, 0), Scalar(2));\n",
-       "  const Scalar _tmp23 = _tmp15 + _tmp22;\n",
-       "  const Scalar _tmp24 = _tmp10 - _tmp11;\n",
-       "  const Scalar _tmp25 = _tmp19 + _tmp20;\n",
-       "  const Scalar _tmp26 = _tmp14 + _tmp22 - 1;\n",
-       "  const Scalar _tmp27 = -_tmp0;\n",
-       "  const Scalar _tmp28 = -_tmp1;\n",
-       "  const Scalar _tmp29 = _tmp3 * _tmp4;\n",
-       "  const Scalar _tmp30 = _tmp6 * _tmp9;\n",
-       "  const Scalar _tmp31 = 4 * state(0, 0);\n",
-       "  const Scalar _tmp32 = -_tmp13 * _tmp4;\n",
-       "  const Scalar _tmp33 = _tmp18 * _tmp9;\n",
-       "  const Scalar _tmp34 = _tmp18 * _tmp3;\n",
-       "  const Scalar _tmp35 = -_tmp2;\n",
-       "  const Scalar _tmp36 = 2 * state(0, 0);\n",
-       "  const Scalar _tmp37 = _tmp3 * _tmp36;\n",
-       "  const Scalar _tmp38 = 4 * state(1, 0);\n",
-       "  const Scalar _tmp39 = _tmp13 * _tmp36;\n",
-       "  const Scalar _tmp40 = -_tmp3 * _tmp6;\n",
-       "  const Scalar _tmp41 = _tmp13 * _tmp18;\n",
-       "  const Scalar _tmp42 = _tmp36 * _tmp9;\n",
-       "  const Scalar _tmp43 = 4 * state(2, 0);\n",
-       "  const Scalar _tmp44 = _tmp4 * _tmp9;\n",
-       "  const Scalar _tmp45 = -dT * state(3, 0);\n",
-       "  const Scalar _tmp46 = dT * state(2, 0);\n",
-       "  const Scalar _tmp47 = dT * state(1, 0);\n",
-       "  const Scalar _tmp48 = dT * state(0, 0);\n",
-       "\n",
-       "  // Output terms (2)\n",
-       "  Eigen::Matrix<Scalar, 28, 1> _res;\n",
-       "\n",
-       "  _res(0, 0) =\n",
-       "      _tmp0 * state(1, 0) + _tmp1 * state(3, 0) - _tmp2 * state(2, 0) + Scalar(1.0) * state(0, 0);\n",
-       "  _res(1, 0) =\n",
-       "      -_tmp0 * state(0, 0) + _tmp1 * state(2, 0) + _tmp2 * state(3, 0) + Scalar(1.0) * state(1, 0);\n",
-       "  _res(2, 0) =\n",
-       "      _tmp0 * state(3, 0) - _tmp1 * state(1, 0) + _tmp2 * state(0, 0) + Scalar(1.0) * state(2, 0);\n",
-       "  _res(3, 0) =\n",
-       "      -_tmp0 * state(2, 0) - _tmp1 * state(0, 0) - _tmp2 * state(1, 0) + Scalar(1.0) * state(3, 0);\n",
-       "  _res(4, 0) = dT * state(7, 0) + state(4, 0);\n",
-       "  _res(5, 0) = dT * state(8, 0) + state(5, 0);\n",
-       "  _res(6, 0) = dT * state(9, 0) + state(6, 0);\n",
-       "  _res(7, 0) = _tmp12 * _tmp9 - _tmp13 * _tmp16 + _tmp3 * _tmp8 + state(7, 0);\n",
-       "  _res(8, 0) = _tmp13 * _tmp17 - _tmp21 * _tmp9 - _tmp23 * _tmp3 + state(8, 0);\n",
-       "  _res(9, 0) =\n",
-       "      _tmp13 * _tmp24 + _tmp25 * _tmp3 - _tmp26 * _tmp9 + state(9, 0) + Scalar(9.8000000000000007);\n",
-       "  _res(10, 0) = state(10, 0);\n",
-       "  _res(11, 0) = state(11, 0);\n",
-       "  _res(12, 0) = state(12, 0);\n",
-       "  _res(13, 0) = state(13, 0);\n",
-       "  _res(14, 0) = state(14, 0);\n",
-       "  _res(15, 0) = state(15, 0);\n",
-       "  _res(16, 0) = state(16, 0);\n",
-       "  _res(17, 0) = state(17, 0);\n",
-       "  _res(18, 0) = state(18, 0);\n",
-       "  _res(19, 0) = state(19, 0);\n",
-       "  _res(20, 0) = state(20, 0);\n",
-       "  _res(21, 0) = state(21, 0);\n",
-       "  _res(22, 0) = state(22, 0);\n",
-       "  _res(23, 0) = state(23, 0);\n",
-       "  _res(24, 0) = state(24, 0);\n",
-       "  _res(25, 0) = state(25, 0);\n",
-       "  _res(26, 0) = state(26, 0);\n",
-       "  _res(27, 0) = state(27, 0);\n",
-       "\n",
-       "  if (res_D_state != nullptr) {\n",
-       "    Eigen::Matrix<Scalar, 28, 28>& _res_D_state = (*res_D_state);\n",
-       "\n",
-       "    _res_D_state.setZero();\n",
-       "\n",
-       "    _res_D_state(0, 0) = Scalar(1.0);\n",
-       "    _res_D_state(1, 0) = _tmp27;\n",
-       "    _res_D_state(2, 0) = _tmp2;\n",
-       "    _res_D_state(3, 0) = _tmp28;\n",
-       "    _res_D_state(7, 0) = _tmp29 + _tmp30;\n",
-       "    _res_D_state(8, 0) = -_tmp3 * _tmp31 - _tmp32 - _tmp33;\n",
-       "    _res_D_state(9, 0) = _tmp13 * _tmp6 - _tmp31 * _tmp9 + _tmp34;\n",
-       "    _res_D_state(0, 1) = _tmp0;\n",
-       "    _res_D_state(1, 1) = Scalar(1.0);\n",
-       "    _res_D_state(2, 1) = _tmp28;\n",
-       "    _res_D_state(3, 1) = _tmp35;\n",
-       "    _res_D_state(7, 1) = -_tmp13 * _tmp38 + _tmp33 + _tmp37;\n",
-       "    _res_D_state(8, 1) = _tmp30 + _tmp39;\n",
-       "    _res_D_state(9, 1) = -_tmp38 * _tmp9 - _tmp40 - _tmp41;\n",
-       "    _res_D_state(0, 2) = _tmp35;\n",
-       "    _res_D_state(1, 2) = _tmp1;\n",
-       "    _res_D_state(2, 2) = Scalar(1.0);\n",
-       "    _res_D_state(3, 2) = _tmp27;\n",
-       "    _res_D_state(7, 2) = -_tmp13 * _tmp43 - _tmp34 + _tmp42;\n",
-       "    _res_D_state(8, 2) = -_tmp3 * _tmp43 + _tmp41 + _tmp44;\n",
-       "    _res_D_state(9, 2) = _tmp29 + _tmp39;\n",
-       "    _res_D_state(0, 3) = _tmp1;\n",
-       "    _res_D_state(1, 3) = _tmp2;\n",
-       "    _res_D_state(2, 3) = _tmp0;\n",
-       "    _res_D_state(3, 3) = Scalar(1.0);\n",
-       "    _res_D_state(7, 3) = _tmp40 + _tmp44;\n",
-       "    _res_D_state(8, 3) = 2 * _tmp13 * state(2, 0) - _tmp42;\n",
-       "    _res_D_state(9, 3) = _tmp32 + _tmp37;\n",
-       "    _res_D_state(4, 4) = 1;\n",
-       "    _res_D_state(5, 5) = 1;\n",
-       "    _res_D_state(6, 6) = 1;\n",
-       "    _res_D_state(4, 7) = dT;\n",
-       "    _res_D_state(7, 7) = 1;\n",
-       "    _res_D_state(5, 8) = dT;\n",
-       "    _res_D_state(8, 8) = 1;\n",
-       "    _res_D_state(6, 9) = dT;\n",
-       "    _res_D_state(9, 9) = 1;\n",
-       "    _res_D_state(0, 10) = _tmp45;\n",
-       "    _res_D_state(1, 10) = -_tmp46;\n",
-       "    _res_D_state(2, 10) = _tmp47;\n",
-       "    _res_D_state(3, 10) = _tmp48;\n",
-       "    _res_D_state(10, 10) = 1;\n",
-       "    _res_D_state(0, 11) = _tmp46;\n",
-       "    _res_D_state(1, 11) = _tmp45;\n",
-       "    _res_D_state(2, 11) = -_tmp48;\n",
-       "    _res_D_state(3, 11) = _tmp47;\n",
-       "    _res_D_state(11, 11) = 1;\n",
-       "    _res_D_state(0, 12) = -_tmp47;\n",
-       "    _res_D_state(1, 12) = _tmp48;\n",
-       "    _res_D_state(2, 12) = _tmp45;\n",
-       "    _res_D_state(3, 12) = _tmp46;\n",
-       "    _res_D_state(12, 12) = 1;\n",
-       "    _res_D_state(7, 13) = _tmp16;\n",
-       "    _res_D_state(8, 13) = -_tmp17;\n",
-       "    _res_D_state(9, 13) = -_tmp24;\n",
-       "    _res_D_state(13, 13) = 1;\n",
-       "    _res_D_state(7, 14) = -_tmp8;\n",
-       "    _res_D_state(8, 14) = _tmp23;\n",
-       "    _res_D_state(9, 14) = -_tmp25;\n",
-       "    _res_D_state(14, 14) = 1;\n",
-       "    _res_D_state(7, 15) = -_tmp12;\n",
-       "    _res_D_state(8, 15) = _tmp21;\n",
-       "    _res_D_state(9, 15) = _tmp26;\n",
-       "    _res_D_state(15, 15) = 1;\n",
-       "    _res_D_state(16, 16) = 1;\n",
-       "    _res_D_state(17, 17) = 1;\n",
-       "    _res_D_state(18, 18) = 1;\n",
-       "    _res_D_state(19, 19) = 1;\n",
-       "    _res_D_state(20, 20) = 1;\n",
-       "    _res_D_state(21, 21) = 1;\n",
-       "    _res_D_state(22, 22) = 1;\n",
-       "    _res_D_state(23, 23) = 1;\n",
-       "    _res_D_state(24, 24) = 1;\n",
-       "    _res_D_state(25, 25) = 1;\n",
-       "    _res_D_state(26, 26) = 1;\n",
-       "    _res_D_state(27, 27) = 1;\n",
-       "  }\n",
-       "\n",
-       "  return _res;\n",
-       "}  // NOLINT(readability/fn_size)\n",
-       "\n",
-       "// NOLINTNEXTLINE(readability/fn_size)\n",
-       "}  // namespace sym\n",
-       "
\n" - ], - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "compute_mean_codegen = codegen.Codegen.function(\n", - " func=compute_mean,\n", - " config=codegen.CppConfig(),\n", - ")\n", - "\n", - "codegen_with_jacobians = compute_mean_codegen.with_jacobians(\n", - " # Just compute wrt the pose and point, not epsilon\n", - " which_args=[\"state\"],\n", - " # Include value, not just jacobians\n", - " include_results=True,\n", - ")\n", - "\n", - "data = codegen_with_jacobians.generate_function()\n", - "\n", - "display_code_file(data.generated_files[0], \"C++\")\n" - ] - }, - { - "cell_type": "code", - "execution_count": 28, - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "codegen.__init__():141 WARNING -- \n", - " Generating code with epsilon set to 0 - This is dangerous! You may get NaNs, Infs,\n", - " or numerically unstable results from calling generated functions near singularities.\n", - "\n", - " In order to safely generate code, you should set epsilon to either a symbol\n", - " (recommended) or a small numerical value like `sf.numeric_epsilon`. You should do\n", - " this before importing any other code from symforce, e.g. with\n", - "\n", - " import symforce\n", - " symforce.set_epsilon_to_symbol()\n", - "\n", - " or\n", - "\n", - " import symforce\n", - " symforce.set_epsilon_to_number()\n", - "\n", - " For more information on use of epsilon to prevent singularities, take a look at the\n", - " Epsilon Tutorial: https://symforce.org/tutorials/epsilon_tutorial.html\n", - "\n" - ] - }, - { - "data": { - "text/html": [ - "
# -----------------------------------------------------------------------------\n",
-       "# This file was autogenerated by symforce from template:\n",
-       "#     function/FUNCTION.py.jinja\n",
-       "# Do NOT modify by hand.\n",
-       "# -----------------------------------------------------------------------------\n",
-       "\n",
-       "# pylint: disable=too-many-locals,too-many-lines,too-many-statements,unused-argument,unused-import\n",
-       "\n",
-       "import math\n",
-       "import typing as T\n",
-       "\n",
-       "import numpy\n",
-       "\n",
-       "import sym\n",
-       "\n",
-       "\n",
-       "def double_pendulum(state, u, dT, epsilon):\n",
-       "    # type: (numpy.ndarray, numpy.ndarray, float, float) -> numpy.ndarray\n",
-       "    """\n",
-       "    This function was autogenerated from a symbolic function. Do not modify by hand.\n",
-       "\n",
-       "    Symbolic function: compute_mean\n",
-       "\n",
-       "    Args:\n",
-       "        state: Matrix28_1\n",
-       "        u: Matrix61\n",
-       "        dT: Scalar\n",
-       "        epsilon: Scalar\n",
-       "\n",
-       "    Outputs:\n",
-       "        res: Matrix28_1\n",
-       "    """\n",
-       "\n",
-       "    # Total ops: 92\n",
-       "\n",
-       "    # Input arrays\n",
-       "    if state.shape == (28,):\n",
-       "        state = state.reshape((28, 1))\n",
-       "    elif state.shape != (28, 1):\n",
-       "        raise IndexError(\n",
-       "            "state is expected to have shape (28, 1) or (28,); instead had shape {}".format(\n",
-       "                state.shape\n",
-       "            )\n",
-       "        )\n",
-       "\n",
-       "    if u.shape == (6,):\n",
-       "        u = u.reshape((6, 1))\n",
-       "    elif u.shape != (6, 1):\n",
-       "        raise IndexError(\n",
-       "            "u is expected to have shape (6, 1) or (6,); instead had shape {}".format(u.shape)\n",
-       "        )\n",
-       "\n",
-       "    # Intermediate terms (16)\n",
-       "    _tmp0 = dT * (-state[12, 0] + u[2, 0])\n",
-       "    _tmp1 = dT * (-state[10, 0] + u[0, 0])\n",
-       "    _tmp2 = dT * (-state[11, 0] + u[1, 0])\n",
-       "    _tmp3 = -state[14, 0] + u[4, 0]\n",
-       "    _tmp4 = 2 * state[1, 0]\n",
-       "    _tmp5 = _tmp4 * state[0, 0]\n",
-       "    _tmp6 = 2 * state[2, 0]\n",
-       "    _tmp7 = _tmp6 * state[3, 0]\n",
-       "    _tmp8 = -state[15, 0] + u[5, 0]\n",
-       "    _tmp9 = _tmp6 * state[0, 0]\n",
-       "    _tmp10 = _tmp4 * state[3, 0]\n",
-       "    _tmp11 = -state[13, 0] + u[3, 0]\n",
-       "    _tmp12 = 2 * state[1, 0] ** 2\n",
-       "    _tmp13 = 2 * state[2, 0] ** 2 - 1\n",
-       "    _tmp14 = 2 * state[0, 0] * state[3, 0]\n",
-       "    _tmp15 = 2 * state[0, 0] ** 2\n",
-       "\n",
-       "    # Output terms\n",
-       "    _res = numpy.zeros(28)\n",
-       "    _res[0] = _tmp0 * state[1, 0] + _tmp1 * state[3, 0] - _tmp2 * state[2, 0] + 1.0 * state[0, 0]\n",
-       "    _res[1] = -_tmp0 * state[0, 0] + _tmp1 * state[2, 0] + _tmp2 * state[3, 0] + 1.0 * state[1, 0]\n",
-       "    _res[2] = _tmp0 * state[3, 0] - _tmp1 * state[1, 0] + _tmp2 * state[0, 0] + 1.0 * state[2, 0]\n",
-       "    _res[3] = -_tmp0 * state[2, 0] - _tmp1 * state[0, 0] - _tmp2 * state[1, 0] + 1.0 * state[3, 0]\n",
-       "    _res[4] = dT * state[7, 0] + state[4, 0]\n",
-       "    _res[5] = dT * state[8, 0] + state[5, 0]\n",
-       "    _res[6] = dT * state[9, 0] + state[6, 0]\n",
-       "    _res[7] = (\n",
-       "        _tmp11 * (-_tmp12 - _tmp13)\n",
-       "        + _tmp3 * (_tmp5 - _tmp7)\n",
-       "        + _tmp8 * (_tmp10 + _tmp9)\n",
-       "        + state[7, 0]\n",
-       "    )\n",
-       "    _res[8] = (\n",
-       "        _tmp11 * (_tmp5 + _tmp7)\n",
-       "        + _tmp3 * (-_tmp13 - _tmp15)\n",
-       "        + _tmp8 * (-_tmp14 + 2 * state[1, 0] * state[2, 0])\n",
-       "        + state[8, 0]\n",
-       "    )\n",
-       "    _res[9] = (\n",
-       "        _tmp11 * (-_tmp10 + _tmp9)\n",
-       "        + _tmp3 * (_tmp14 + _tmp6 * state[1, 0])\n",
-       "        + _tmp8 * (-_tmp12 - _tmp15 + 1)\n",
-       "        + state[9, 0]\n",
-       "        + 9.8\n",
-       "    )\n",
-       "    _res[10] = state[10, 0]\n",
-       "    _res[11] = state[11, 0]\n",
-       "    _res[12] = state[12, 0]\n",
-       "    _res[13] = state[13, 0]\n",
-       "    _res[14] = state[14, 0]\n",
-       "    _res[15] = state[15, 0]\n",
-       "    _res[16] = state[16, 0]\n",
-       "    _res[17] = state[17, 0]\n",
-       "    _res[18] = state[18, 0]\n",
-       "    _res[19] = state[19, 0]\n",
-       "    _res[20] = state[20, 0]\n",
-       "    _res[21] = state[21, 0]\n",
-       "    _res[22] = state[22, 0]\n",
-       "    _res[23] = state[23, 0]\n",
-       "    _res[24] = state[24, 0]\n",
-       "    _res[25] = state[25, 0]\n",
-       "    _res[26] = state[26, 0]\n",
-       "    _res[27] = state[27, 0]\n",
-       "    return _res\n",
-       "
\n" - ], - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "codegen.__init__():141 WARNING -- \n", - " Generating code with epsilon set to 0 - This is dangerous! You may get NaNs, Infs,\n", - " or numerically unstable results from calling generated functions near singularities.\n", - "\n", - " In order to safely generate code, you should set epsilon to either a symbol\n", - " (recommended) or a small numerical value like `sf.numeric_epsilon`. You should do\n", - " this before importing any other code from symforce, e.g. with\n", - "\n", - " import symforce\n", - " symforce.set_epsilon_to_symbol()\n", - "\n", - " or\n", - "\n", - " import symforce\n", - " symforce.set_epsilon_to_number()\n", - "\n", - " For more information on use of epsilon to prevent singularities, take a look at the\n", - " Epsilon Tutorial: https://symforce.org/tutorials/epsilon_tutorial.html\n", - "\n" - ] - } - ], - "source": [ - "namespace = \"double_pendulum\"\n", - "double_pendulum_python = codegen.Codegen.function(\n", - " func = compute_mean,\n", - " config=codegen.PythonConfig(use_eigen_types=False),\n", - " name=\"double_pendulum\",\n", - " return_key=\"ddang\",\n", - ")\n", - "double_pendulum_python_data = double_pendulum_python.generate_function(\n", - " namespace=namespace,\n", - ")\n", - "\n", - "# print(\"Files generated in {}:\\n\".format(double_pendulum_python_data.output_dir))\n", - "# for f in double_pendulum_python_data.generated_files:\n", - "# print(\" |- {}\".format(f.relative_to(double_pendulum_python_data.output_dir)))\n", - "\n", - "display_code_file(\n", - " double_pendulum_python_data.function_dir / \"double_pendulum.py\",\n", - " \"python\",\n", - ")\n", - "\n", - "codegen_with_jacobians = compute_mean_codegen.with_jacobians(\n", - " # Just compute wrt the pose and point, not epsilon\n", - " which_args=[\"state\"],\n", - " # Include value, not just jacobians\n", - " include_results=True,\n", - ")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.8.10" - } - }, - "nbformat": 4, - "nbformat_minor": 4 -} diff --git a/examples/velocity_estimator.ipynb b/examples/velocity_estimator.ipynb deleted file mode 100644 index a94a91b..0000000 --- a/examples/velocity_estimator.ipynb +++ /dev/null @@ -1,147 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [], - "source": [ - "from Go2Py.sim.mujoco import Go2Sim\n", - "from Go2Py.robot.model import Go2Model\n", - "import pinocchio as pin \n", - "import numpy as np\n", - "import time" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "[0.3868 0. 0. ]\n" - ] - } - ], - "source": [ - "model = Go2Model()" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [], - "source": [ - "robot = Go2Sim()" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": {}, - "outputs": [], - "source": [ - "robot.step()" - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "metadata": {}, - "outputs": [], - "source": [ - "omega = robot.getIMU()['gyro']\n", - "def hat(w):\n", - " return np.array([[0., -w[2], w[1]],\n", - " [w[2], 0., -w[0]],\n", - " [-w[1], w[0], 0.]])" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "robot.standUpReset()\n", - "while True:\n", - " time.sleep(0.001)\n", - " robot.setCommands(robot.standing_q, np.zeros(12), np.ones(12)*100, np.ones(12)*0.1, np.zeros(12))\n", - " robot.step() \n", - " trans, quat = robot.getPose()\n", - " state = robot.getJointStates()\n", - " quat = pin.Quaternion(np.hstack([quat[1:],quat[0]]))\n", - " R = quat.matrix()\n", - " T = np.eye(4)\n", - " T[0:3,0:3] = R\n", - " vel = np.zeros(6)\n", - " model.update(state['q'], state['dq'],T,vel)\n", - "\n", - " J = model.getInfo()['J']['FR_foot'][:,6:]\n", - " nle = model.getInfo()['nle'][6:]\n", - " # tau = (robot.data.qfrc_smooth+robot.data.qfrc_constraint)[6:]\n", - " tau = state['tau_est'].squeeze()\n", - " print(np.linalg.pinv(J.T)[0:3]@(tau - nle))" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "question: What exactly is the difference between the local world aligned and local jacobians in the pinocchio? Why it fits my expectations for the FR3 and not the Go2?" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "robot.getJointStates()\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "J[3:,:].T" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.8.10" - } - }, - "nbformat": 4, - "nbformat_minor": 2 -} diff --git a/examples/vicon2gt-dataset-collector.ipynb b/examples/vicon2gt-dataset-collector.ipynb deleted file mode 100644 index 1da2f39..0000000 --- a/examples/vicon2gt-dataset-collector.ipynb +++ /dev/null @@ -1,140 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Lowlevel Interface Test" - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "pygame 2.5.2 (SDL 2.28.2, Python 3.8.18)\n", - "Hello from the pygame community. https://www.pygame.org/contribute.html\n" - ] - } - ], - "source": [ - "from Go2Py.robot.interface.ros2 import GO2Real, ros2_init, ROS2ExecutorManager\n", - "from Go2Py.robot.interface.ros2 import ROS2TFInterface\n", - "import time\n", - "ros2_init()\n", - "vicon = ROS2TFInterface('vicon/World', 'vicon/GO2/GO2', 'vicon')\n", - "robot = GO2Real(mode='highlevel')\n", - "ros2_exec_manager = ROS2ExecutorManager()\n", - "ros2_exec_manager.add_node(robot)\n", - "ros2_exec_manager.add_node(vicon)\n", - "ros2_exec_manager.start()" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [], - "source": [ - "for i in range(1000):\n", - " time.sleep(0.01)\n", - " imu = robot.getIMU()\n", - " accel = imu['accel']\n", - " gyro = imu['gyro']\n", - " q = imu['quat']\n", - " pose = vicon.get_pose()\n", - " stamp = time.time()" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [], - "source": [ - "import time\n", - "import numpy as np\n", - "im = []\n", - "acc = []\n", - "gy = []\n", - "quaternion = []\n", - "pos = []\n", - "stamps = []\n", - "for i in range(2000):\n", - " time.sleep(0.01)\n", - " imu = robot.getIMU()\n", - " accel = imu['accel']\n", - " gyro = imu['gyro']\n", - " q = imu['quat']\n", - " pose = vicon.get_pose()\n", - " stamp = time.time()\n", - " im.append(imu)\n", - " acc.append(accel)\n", - " gy.append(gyro)\n", - " quaternion.append(q)\n", - " pos.append(pose)\n", - " stamps.append(stamp)\n", - "\n", - "imu = np.array(im)\n", - "accel = np.array(acc)\n", - "gyro = np.array(gy)\n", - "q = np.array(quaternion)\n", - "pose = np.array(pos)\n", - "stamp = np.array(stamps)" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [], - "source": [ - "import pickle \n", - "with open('vicon2gt_5.pkl', 'wb') as f:\n", - " pickle.dump(\n", - " {\n", - " 'imu':imu,\n", - " 'accel':accel,\n", - " 'gyro':gyro,\n", - " 'q':q,\n", - " 'pose':pose,\n", - " 'stamp':stamp\n", - " }\n", - " ,f\n", - " )" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.8.18" - } - }, - "nbformat": 4, - "nbformat_minor": 4 -} diff --git a/examples/vicon2gt.pkl b/examples/vicon2gt.pkl deleted file mode 100644 index 8213aa9..0000000 Binary files a/examples/vicon2gt.pkl and /dev/null differ diff --git a/examples/vicon2gt_1.pkl b/examples/vicon2gt_1.pkl deleted file mode 100644 index 624169d..0000000 Binary files a/examples/vicon2gt_1.pkl and /dev/null differ diff --git a/examples/vicon2gt_3.pkl b/examples/vicon2gt_3.pkl deleted file mode 100644 index e0139d3..0000000 Binary files a/examples/vicon2gt_3.pkl and /dev/null differ diff --git a/examples/vicon2gt_4.pkl b/examples/vicon2gt_4.pkl deleted file mode 100644 index c021bac..0000000 Binary files a/examples/vicon2gt_4.pkl and /dev/null differ diff --git a/examples/vicon2gt_5.pkl b/examples/vicon2gt_5.pkl deleted file mode 100644 index 6f5ffa2..0000000 Binary files a/examples/vicon2gt_5.pkl and /dev/null differ diff --git a/examples/vicon2gt_recorder.py b/examples/vicon2gt_recorder.py deleted file mode 100644 index ed2f11a..0000000 --- a/examples/vicon2gt_recorder.py +++ /dev/null @@ -1,4 +0,0 @@ -from Go2Py.robot.interface.ros2 import GO2Real, ros2_init, ROS2ExecutorManager -import time -ros2_init() -robot = GO2Real(mode='highlevel') diff --git a/examples/walk_these_ways_sim.ipynb b/examples/walk_these_ways_sim.ipynb deleted file mode 100644 index 7a77f33..0000000 --- a/examples/walk_these_ways_sim.ipynb +++ /dev/null @@ -1,263 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Basic Test" - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [], - "source": [ - "from Go2Py.sim.mujoco import Go2Sim\n", - "import numpy as np" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [], - "source": [ - "robot = Go2Sim()\n", - "robot.standUpReset()" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [], - "source": [ - "from Go2Py.control.walk_these_ways import *\n", - "# checkpoint_path = \"/home/rstaion/projects/rooholla/locomotion/Go2Py/Go2Py/assets/checkpoints/walk_these_ways/\"\n", - "checkpoint_path = \"/home/rstaion/projects/rooholla/walk-these-ways/runs/gait-conditioned-agility/pretrain-v0/train/025417.456545\"\n", - "\n", - "\n", - "cfg = loadParameters(checkpoint_path)\n", - "policy = Policy(checkpoint_path)\n", - "command_profile = CommandInterface()" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "p_gains: [20. 20. 20. 20. 20. 20. 20. 20. 20. 20. 20. 20.]\n" - ] - } - ], - "source": [ - "agent = WalkTheseWaysAgent(cfg, command_profile, robot)\n", - "agent = HistoryWrapper(agent)" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": {}, - "outputs": [], - "source": [ - "control_dt = cfg[\"control\"][\"decimation\"] * cfg[\"sim\"][\"dt\"]\n", - "simulation_dt = robot.dt\n", - "obs = agent.reset()" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "frq: 15.967047985229458 Hz\n", - "frq: 42.47353444522081 Hz\n", - "frq: 43.69977078558033 Hz\n", - "frq: 40.20806211954177 Hz\n" - ] - } - ], - "source": [ - "robot.reset()\n", - "obs = agent.reset()\n", - "for i in range(50000):\n", - " policy_info = {}\n", - " action = policy(obs, policy_info)\n", - " if i % (control_dt // simulation_dt) == 0:\n", - " obs, ret, done, info = agent.step(action)\n", - " robot.step()\n", - " command_profile.yaw_vel_cmd = 0.0\n", - " command_profile.x_vel_cmd = 0.0\n", - " command_profile.y_vel_cmd = 0.0\n", - " time.sleep(robot.dt/4)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Full System With FSM" - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [], - "source": [ - "from Go2Py.robot.fsm import FSM\n", - "from Go2Py.robot.remote import KeyboardRemote\n", - "from Go2Py.robot.safety import SafetyHypervisor\n", - "from Go2Py.sim.mujoco import Go2Sim\n", - "from Go2Py.control.walk_these_ways import *\n", - "import numpy as np" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [], - "source": [ - "robot = Go2Sim()" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [], - "source": [ - "class walkTheseWaysController:\n", - " def __init__(self, robot, remote, checkpoint):\n", - " self.remote = remote\n", - " self.robot = robot\n", - " self.cfg = loadParameters(checkpoint)\n", - " self.policy = Policy(checkpoint)\n", - " self.command_profile = CommandInterface()\n", - " self.agent = WalkTheseWaysAgent(self.cfg, self.command_profile, self.robot)\n", - " self.agent = HistoryWrapper(self.agent)\n", - " self.init()\n", - "\n", - " def init(self):\n", - " self.obs = self.agent.reset()\n", - " self.policy_info = {}\n", - " self.command_profile.yaw_vel_cmd = 0.0\n", - " self.command_profile.x_vel_cmd = 0.0\n", - " self.command_profile.y_vel_cmd = 0.0\n", - " self.command_profile.stance_width_cmd=0.25\n", - " self.command_profile.footswing_height_cmd=0.08\n", - " self.command_profile.step_frequency_cmd = 3.0\n", - " self.command_profile.body_height_cmd = 0.5\n", - "\n", - " def update(self, robot, remote):\n", - " action = self.policy(self.obs, self.policy_info)\n", - " self.obs, self.ret, self.done, self.info = self.agent.step(action)\n" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": {}, - "outputs": [], - "source": [ - "remote = KeyboardRemote()\n", - "robot.standUpReset()\n", - "safety_hypervisor = SafetyHypervisor(robot)" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "p_gains: [20. 20. 20. 20. 20. 20. 20. 20. 20. 20. 20. 20.]\n" - ] - } - ], - "source": [ - "checkpoint = \"/home/rstaion/projects/rooholla/locomotion/Go2Py/Go2Py/assets/checkpoints/walk_these_ways/\"\n", - "# checkpoint = \"/home/rstaion/projects/rooholla/walk-these-ways/runs/gait-conditioned-agility/pretrain-v0/train/025417.456545\"\n", - "controller = walkTheseWaysController(robot, remote, checkpoint)\n", - "fsm = FSM(robot, remote, safety_hypervisor, user_controller_callback=controller.update)" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "metadata": {}, - "outputs": [], - "source": [ - "controller.command_profile.pitch_cmd=0.0\n", - "controller.command_profile.body_height_cmd=0.0\n", - "controller.command_profile.footswing_height_cmd=0.08\n", - "controller.command_profile.roll_cmd=0.0\n", - "controller.command_profile.stance_width_cmd=0.2\n", - "controller.command_profile.x_vel_cmd=-0.2\n", - "controller.command_profile.y_vel_cmd=0.01\n", - "controller.command_profile.setGaitType(\"trotting\")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "controller.command_profile.pitch_cmd=0.0\n", - "controller.command_profile.body_height_cmd=0.0\n", - "controller.command_profile.footswing_height_cmd=0.08\n", - "controller.command_profile.roll_cmd=0.0\n", - "controller.command_profile.stance_width_cmd=0.2\n", - "controller.command_profile.x_vel_cmd=-0.2\n", - "controller.command_profile.y_vel_cmd=0.01\n", - "controller.command_profile.setGaitType(\"trotting\")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "fsm.close()" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "b1-env", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.8.18" - } - }, - "nbformat": 4, - "nbformat_minor": 2 -}