diff --git a/CMakeLists.txt b/CMakeLists.txt index f06996e..8cb7a67 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -3,10 +3,13 @@ project(benchmark_gazebo) enable_testing() include(FindBoost) + find_package(PkgConfig REQUIRED) pkg_check_modules(zstd REQUIRED IMPORTED_TARGET libzstd) pkg_check_modules(lz4 REQUIRED IMPORTED_TARGET liblz4) + find_package(protobuf CONFIG) + if(NOT Protobuf_FOUND) find_package(Protobuf REQUIRED) endif() @@ -23,27 +26,44 @@ if (NOT GAZEBO_FOUND) message (STATUS "Looking for gazebo - not found") message (FATAL_ERROR "Missing: Gazebo version 11.") endif() + include_directories(${GAZEBO_INCLUDE_DIRS} ${PROJECT_SOURCE_DIR}/gtest/include ${PROJECT_SOURCE_DIR}/gtest ) link_directories(${GAZEBO_LIBRARY_DIRS}) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${GAZEBO_CXX_FLAGS}") # Build gtest add_library(gtest STATIC gtest/src/gtest-all.cc) add_library(gtest_main STATIC gtest/src/gtest_main.cc) target_link_libraries(gtest_main gtest tbb) -set(PROTO_FILES proto/boxes_msg.proto) -include(${PROJECT_SOURCE_DIR}/tools/TestMacro.cmake) -set(MCAP_DEPENDENCIES PkgConfig::lz4 PkgConfig::zstd) + +set(TEST_TYPE "BENCHMARK") set(WORLDS_DIR_PATH "${PROJECT_SOURCE_DIR}/worlds") set(TEST_RESULT_DIR "${PROJECT_SOURCE_DIR}/test_results") -set(TEST_TYPE "BENCHMARK") + +include(${PROJECT_SOURCE_DIR}/tools/TestMacro.cmake) + +set(MCAP_DEPENDENCIES PkgConfig::lz4 PkgConfig::zstd) + +set(PROTO_FILES proto/boxes_msg.proto proto/triball_msg.proto + proto/Accel.proto proto/Pose.proto proto/Quaternion.proto + proto/Twist.proto proto/Vector3.proto proto/Wrench.proto) + include_directories(${Protobuf_INCLUDE_DIRS}) + protobuf_generate_cpp(PROTO_SRCS PROTO_HDRS ${PROTO_FILES}) + configure_file(${PROJECT_SOURCE_DIR}/PathConfig.h.in PathConfig.h) +set(PROTOBUF_DESCRIPTION_DIR ${CMAKE_SOURCE_DIR}/mcap/cpp/examples/protobuf/) +set(PROTOBUF_DESCRIPTION_SRC + ${PROTOBUF_DESCRIPTION_DIR}/BuildFileDescriptorSet.cpp +) + +set(TEST_NAME boxes) # Boxes tests set(BOXES_TEST_FILES boxes_dt.cc @@ -52,20 +72,22 @@ set(BOXES_TEST_FILES set(GZ_BUILD_TESTS_EXTRA_EXE_SRCS boxes.cc ) -set(PROTOBUF_DESCRIPTION_DIR ${CMAKE_SOURCE_DIR}/mcap/cpp/examples/protobuf/) -set(PROTOBUF_DESCRIPTION_SRC - ${PROTOBUF_DESCRIPTION_DIR}/BuildFileDescriptorSet.cpp -) + gz_build_tests(${BOXES_TEST_FILES}) set_tests_properties(BENCHMARK_boxes_dt PROPERTIES TIMEOUT 500) set_tests_properties(BENCHMARK_boxes_model_count PROPERTIES TIMEOUT 3000) -# # Collide sphere tests -# set(COLLIDE_SPHERES_TEST_FILES -# collide_spheres_dt.cc -# ) -# set(GZ_BUILD_TESTS_EXTRA_EXE_SRCS -# collide_spheres.cc -# ) -# gz_build_tests(${COLLIDE_SPHERES_TEST_FILES}) +set(TEST_NAME triball) +set(TRIBALL_TEST_FILES + triball_configuration.cc + triball_sliding.cc +) + +set(GZ_BUILD_TESTS_EXTRA_EXE_SRCS + triball.cc +) + +gz_build_tests(${TRIBALL_TEST_FILES}) + +set_tests_properties(BENCHMARK_triball_configuration PROPERTIES TIMEOUT 500) diff --git a/README.md b/README.md index 40ec1be..36ee1ef 100644 --- a/README.md +++ b/README.md @@ -11,6 +11,8 @@ or on your own machine following the instructions given below: ![boxes benchmark animation: simple trajectory](img/boxes_5_simple.gif) ![boxes benchmark animation: complex trajectory](img/boxes_5_complex.gif) +* [Triball: rigid bodies in contact](triball_description.ipynb) + These benchmarks can be run for the physics engines supported by gazebo: * [Open Dynamics Engine (ODE)](http://ode.org), (source code on [bitbucket](https://bitbucket.org/odedevs/ode)) @@ -37,7 +39,8 @@ and then clone and build the benchmarks: ~~~ git clone https://github.com/scpeters/benchmark -pip install lz4 protobuf zstandard +pip install lz4 protobuf zstandard pandas +sudo apt-get install python3-gz-math7 cd benchmark git submodule update --init --recursive mkdir build diff --git a/boxes.cc b/boxes.cc index 6baa462..340f7e0 100644 --- a/boxes.cc +++ b/boxes.cc @@ -173,13 +173,13 @@ void BoxesTest::Boxes(const std::string &_physicsEngine, double _dt, auto model = models[model_no]; link = model->GetLink(); - // linear velocity + // linear velocity in world frame ignition::math::Vector3d v = link->WorldCoGLinearVel(); - // angular velocity + // angular velocity in world frame ignition::math::Vector3d a = link->WorldAngularVel(); log.recordTwist(model_no, v, a); - - // linear position + + // linear position in world frame ignition::math::Pose3d pose = link->WorldInertialPose(); log.recordPose(model_no, pose); } diff --git a/boxes.hh b/boxes.hh index bdb2e2f..f42ce48 100644 --- a/boxes.hh +++ b/boxes.hh @@ -36,6 +36,7 @@ namespace gazebo , bool , bool > char1double1int1bool2; + class BoxesTest : public ServerFixture, public testing::WithParamInterface { diff --git a/boxes_post_processing.py b/boxes_post_processing.py new file mode 100644 index 0000000..a9092a2 --- /dev/null +++ b/boxes_post_processing.py @@ -0,0 +1,258 @@ +import sys +import os +import pandas as pd +import time +import numpy as np +from gz.math7 import Quaterniond, Vector3d +import matplotlib.pyplot as plt +import csv +import time + +SOURCE_FOLDER = os.path.dirname(os.path.abspath(__file__)) + +BENCHMARK_NAME = sys.argv[1] + +class PostProcessing: + + def __init__(self, test_name: str): + self.m = 10 + self.g = 9.8 + self.box_x = 0.1 + self.box_y = 0.4 + self.box_z = 0.9 + Ixx = self.m/12.0 * (self.box_y**2 + self.box_z**2) + Iyy = self.m/12.0 * (self.box_z**2 + self.box_x**2) + Izz = self.m/12.0 * (self.box_x**2 + self.box_y**2) + self.I = np.diag([Ixx, Iyy, Izz]) + self.sim_duration = 10 + + timestr = time.strftime("%Y%m%d-%H%M%S") + metrics_filename = test_name + "_" + timestr + ".csv" + self.metrics_path = os.path.join(SOURCE_FOLDER, "test_results", metrics_filename) + print(f"metrics path is {self.metrics_path}") + + self.csv_file = open(self.metrics_path, mode='w', newline='') + self.csv_writer = csv.writer(self.csv_file) + + metrics = ["angMomentum0", "angMomentumErr_maxAbs","angPositionErr_x_maxAbs", + "angPositionErr_y_maxAbs", "angPositionErr_z_maxAbs", "collision", + "dt", "energyError_maxAbs", "engine", "isComplex", "linPositionErr_maxAbs", + "linVelocityErr_maxAbs", "modelCount", "simTime", "time", "timeRatio", "classname"] + self.csv_writer.writerow(metrics) + + + + def read_file(self,file_path: str): + benchmark_config = pd.read_csv(file_path, nrows=1).to_numpy() + states = pd.read_csv(file_path,skiprows=2).to_numpy() + return benchmark_config, states + + def get_file_names(self, result_folder: str): + '''Method to obtain the file names and file paths of benchmark result''' + result_dir = os.path.join(SOURCE_FOLDER, "test_results", BENCHMARK_NAME, "CSV") + file_names = os.listdir(result_dir) + return result_dir, file_names + + def set_test_parameters(self, physic_engine, dt, complex, + collision, no_of_models, computation_time, + class_name): + self.physics_engine = physic_engine + self.dt = dt + self.complex = complex + self.collision = collision + self.no_of_models = no_of_models + self.computation_time = computation_time + self.class_name = class_name + + def get_analytical_sol(self, sim_time: np.ndarray, model_no: int): + '''method to get the analytical solution for box benchmark''' + + if not self.complex: + v0 = np.array([-0.9, 0.4, 0.1]) + self.w0 = np.array([0.5, 0.0, 0.0]) + self.gravity = np.array([0, 0, 0]) + else: + v0 = np.array([-2.0, 2.0, 8.0]) + self.w0 = np.array([0.1, 5.0, 0.1]) + self.gravity = np.array([0, 0, -self.g]) + + self.pos0 = np.array([0,2*self.box_z*model_no,0]) + print(f" Initial position is {self.pos0} \n") + + self.N = len(sim_time) + self.pos_a = np.zeros((self.N,3)) + self.v_a = np.zeros((self.N,3)) + + # calculation of initial energy and angular momentum + self.L0 = self.I.dot(self.w0) + self.L0_mag = np.linalg.norm(self.L0) + + T0 = 0.5*self.m*v0.dot(v0) + 0.5*self.w0.dot(self.I.dot(self.w0)) + V0 = - self.m*self.gravity.dot(self.pos0) + self.E0 = T0 + V0 + self.E0_mag = np.linalg.norm(self.E0) + + # calculation of velocity and position profile with time + for i, t in enumerate(sim_time): + self.v_a[i] = v0 + self.gravity*t + self.pos_a[i] = self.pos0 + v0*t + 0.5*self.gravity*t**2 + + def cal_metrics(self,states: np.ndarray): + '''Method for calculating the various error/metrics''' + sim_time = states[:,0] + v = states[:,2:5] + omega = states[:, 5:8] + pos = states[:, 8:11] + rot = states[:, 11:] + + # calculation of energy and angular momentum error + E = np.zeros(self.N) + L = np.zeros((self.N,3)) + for i in range(self.N): + # angular velocity in body frame + omega_w = omega[i].tolist() + quat = rot[i].tolist() + quat = Quaterniond(quat[0], quat[1], quat[2], quat[3]) + omega_b = quat.rotate_vector_reverse(Vector3d(omega_w[0], omega_w[1], omega_w[2])) + omega_b = np.array([omega_b[0], omega_b[1], omega_b[2]]) + + # translation energy + rotational energy + potential energy + tran_E = 0.5*self.m*v[i].dot(v[i]) + rot_E = 0.5*omega_b.dot(self.I.dot(omega_b)) + V = - self.m*self.gravity.dot(pos[i]) + E[i] = tran_E + rot_E + V + + # angular momentum in body frame + l_b = self.I.dot(omega_b).tolist() + + # angular momentum in world frame + l_vector = Vector3d(l_b[0], l_b[1],l_b[2]) + l_w = quat.rotate_vector(l_vector) + L[i] = np.array([l_w[0], l_w[1], l_w[2]]) + + # calculation of velocity and postion error and their magnitude + v_error = (v - self.v_a) + self.v_error_mag = np.array([np.linalg.norm(x) for x in v_error]) + + pos_error = (pos - self.pos_a) + self.pos_error_mag = np.array([np.linalg.norm(p) for p in pos_error]) + + self.energy_error = (E - self.E0)/self.E0_mag + self.energy_error_mag = np.array([np.linalg.norm(e) for e in self.energy_error]) + + angmomentum_error = (L - self.L0)/self.L0_mag + self.angmomentum_error_mag = np.array([np.linalg.norm(l) for l in angmomentum_error]) + + # calculating angle error + self.angle_error = np.zeros((self.N,3)) + if not self.complex: + w0 = np.array([0.5, 0.0, 0.0]) + for i in range(self.N): + quat = rot[i].tolist() + euler_angle = Quaterniond(quat[0], quat[1], quat[2], quat[3]).euler() + true_angle = Quaterniond(w0[0]*sim_time[i], w0[1]*sim_time[i], w0[2]*sim_time[i]).euler() + error = (euler_angle - true_angle) + self.angle_error[i] = np.array([error.x(), error.y(), error.z()]) + self.angle_error_mag = np.absolute(self.angle_error) + + # calculating computional time for simulation + self.total_sim_time = sim_time[-1] + self.time_ratio = self.computation_time/self.total_sim_time + print(f" Time ratio: {self.time_ratio} \n") + + def get_maxabs_error(self): + '''Method for calculation of maximum absolute error''' + + self.v_maxabs_error = np.max(self.v_error_mag) + self.p_maxabs_error = np.max(self.pos_error_mag) + self.E_maxabs_error = np.max(self.energy_error_mag) + self.L_maxabs_error = np.max(self.angmomentum_error_mag) + self.a_maxabs_error_x = np.max(self.angle_error_mag[:, 0]) + self.a_maxabs_error_y = np.max(self.angle_error_mag[:, 1]) + self.a_maxabs_error_z = np.max(self.angle_error_mag[:, 2]) + + print(" -> Max absolute error") + print(" ----------------------------------") + print(f" Linear velocity: {self.v_maxabs_error} \n Position: {self.p_maxabs_error} \ + \n Energy: {self.E_maxabs_error} \n Angular momentum: {self.L_maxabs_error} \ + \n Angle_maxabs_x: {self.a_maxabs_error_x} \n Angle_maxabs_y: {self.a_maxabs_error_y} \ + \n Angle_maxabs_x {self.a_maxabs_error_z}") + print(" ---------------------------------- \n") + + def get_avgabs_error(self): + '''Method for calculation of avg absolute error''' + + v_avgabs_error = np.sum(self.v_error_mag)/self.N + p_avgabs_error = np.sum(self.pos_error_mag)/self.N + E_avgabs_error = np.sum(self.energy_error_mag)/self.N + L_avgabs_error = np.sum(self.angmomentum_error_mag)/self.N + a_avgabs_error_x = np.sum(self.angle_error_mag[:, 0])/self.N + a_avgabs_error_y = np.sum(self.angle_error_mag[:, 1])/self.N + a_avgabs_error_z = np.sum(self.angle_error_mag[:, 2])/self.N + + + print(" -> Average absolute error") + print(" ----------------------------------") + print(f" Linear velocity: {v_avgabs_error} \n Position: {p_avgabs_error} \ + \n Energy: {E_avgabs_error} \n Angular momentum: {L_avgabs_error} ") + print(" ---------------------------------- \n") + + def save_metrics(self): + + '''Save the current test metrics to csv file''' + self.get_maxabs_error() + + self.csv_writer.writerow([self.L0_mag, self.L_maxabs_error, self.a_maxabs_error_x, + self.a_maxabs_error_y, self.a_maxabs_error_z, self.collision, + self.dt, self.E_maxabs_error, self.physics_engine, self.complex, + self.p_maxabs_error, self.v_maxabs_error, self.no_of_models, + self.total_sim_time, self.computation_time, self.time_ratio, + self.class_name]) + + + +if __name__ == "__main__": + dir = BENCHMARK_NAME + print(f"BENCHMARK: {dir}") + + post_processing = PostProcessing(dir) + result_dir , file_names = post_processing.get_file_names(dir) + file_names = sorted(file_names, reverse=True) + + for file in file_names: + print(f"TEST: {file}") + file_path = os.path.join(result_dir,file) + config, states = post_processing.read_file(file_path) + physic_engine = config[0,0] + dt = config[0,1] + complex = bool(config[0,2]) + collision = bool(config[0,3]) + modelCount = config[0,4] + computation_time = config[0,5] + log_multiple = bool(config[0,6]) + class_name = config[0,7] + + print(f" Physics engines: {physic_engine} \n Timestep: {dt} \n Complex: {complex} \n Number of models: {modelCount}") + post_processing.set_test_parameters(physic_engine, dt, complex, collision, modelCount, computation_time, class_name) + + if log_multiple: + no_of_models = modelCount + else: + no_of_models = 1 + states_per_model = int(len(states[:,0])/no_of_models) + states = states.reshape(no_of_models, states_per_model,-1) + + for i in range(no_of_models): + print(f" => Model number: {i+1}") + model_states = states[i] + sim_time = model_states[:,0] + + post_processing.get_analytical_sol(sim_time, i) + post_processing.cal_metrics(model_states) + post_processing.save_metrics() + + post_processing.csv_file.close() + print(f"final metrics path {post_processing.metrics_path}") + data = pd.read_csv(post_processing.metrics_path) + storted_data = data.sort_values(by='dt') + storted_data.to_csv(post_processing.metrics_path, index=False) diff --git a/boxes_results.ipynb b/boxes_results.ipynb index 276bfe9..bea1fed 100644 --- a/boxes_results.ipynb +++ b/boxes_results.ipynb @@ -55,18 +55,22 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 11, "id": "6ecac817", "metadata": {}, "outputs": [], "source": [ "import matplotlib as mpl\n", "import matplotlib.pyplot as plt\n", + "import os\n", + "import sys\n", "%matplotlib inline\n", "%config InlineBackend.figure_format = 'png'\n", "mpl.rcParams.update({'font.size': 16})\n", + "path = os.path.abspath(\"tools\")\n", + "sys.path.append(path)\n", "import csv_dictionary\n", - "import plot_helpers as ph" + "import boxes.plot_helpers as ph" ] }, { @@ -178,10 +182,24 @@ } ], "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, "language_info": { - "name": "python" + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.12" } }, "nbformat": 4, "nbformat_minor": 5 -} \ No newline at end of file +} diff --git a/img/triball/cone_pyramid.png b/img/triball/cone_pyramid.png new file mode 100644 index 0000000..ca0178f Binary files /dev/null and b/img/triball/cone_pyramid.png differ diff --git a/img/triball/triball_friction_cone.gif b/img/triball/triball_friction_cone.gif new file mode 100644 index 0000000..3f90619 Binary files /dev/null and b/img/triball/triball_friction_cone.gif differ diff --git a/img/triball/triball_friction_pyramid.gif b/img/triball/triball_friction_pyramid.gif new file mode 100644 index 0000000..98722ee Binary files /dev/null and b/img/triball/triball_friction_pyramid.gif differ diff --git a/img/triball/triball_static.jpg b/img/triball/triball_static.jpg new file mode 100644 index 0000000..72a36d1 Binary files /dev/null and b/img/triball/triball_static.jpg differ diff --git a/log.hh b/log.hh index 10e9c4b..5ef0305 100644 --- a/log.hh +++ b/log.hh @@ -2,6 +2,7 @@ #include "mcap/writer.hpp" #include "protobuf/BuildFileDescriptorSet.h" #include +#include #include #include #include @@ -51,6 +52,49 @@ class Log msg.add_data()->set_model_no(1); } + public: void setTriballMsg(const std::string &_physicsEngine, + double &_slope, float &_frictionCoefficient, + bool &_complex, const std::string &_frictionModel, + double _cogH, bool _equalKE) + { + mcap::Schema schema("benchmark_proto.TriballsMsg", "protobuf", + foxglove::BuildFileDescriptorSet(benchmark_proto::TriballsMsg::descriptor()).SerializeAsString()); + + writer.addSchema(schema); + mcap::Channel channel("model_states", "protobuf", schema.id); + writer.addChannel(channel); + channelId = channel.id; + msg.set_physics_engine(_physicsEngine); + msg.set_slope(_slope); + msg.set_friction_coefficient(_frictionCoefficient); + msg.set_complex(_complex); + msg.set_friction_model(_frictionModel); + msg.set_cog_h(_cogH); + msg.set_equal_ke(_equalKE); + + int modelCount; + if(_complex) + { + modelCount = 32; + } + else + { + modelCount = 5; + } + + for(int i = 0; i < modelCount; i++) + { + msg.add_data()->set_model_no(i); + + for(int j = 0; j < 3; j++) + { + msg.mutable_data(i)->add_contact_info(); + } + + } + + } + public: void stop() { std::string serialized = msg.SerializeAsString(); @@ -131,7 +175,91 @@ class Log twist->mutable_angular()->set_z(_angVelocity.Z()); } + public: void recordAccel(int &_modelIdx, const std::vector &_linAccel, + const std::vector &_angAccel) + { + auto accel = msg.mutable_data(_modelIdx)->add_acceleration(); + + accel->mutable_linear()->set_x(_linAccel[0]); + accel->mutable_linear()->set_y(_linAccel[1]); + accel->mutable_linear()->set_z(_linAccel[3]); + + accel->mutable_angular()->set_x(_angAccel[0]); + accel->mutable_angular()->set_y(_angAccel[1]); + accel->mutable_angular()->set_z(_angAccel[3]); + } + + public: void recordAccel(int &_modelIdx, const ignition::math::Vector3d &_linAccel, + const ignition::math::Vector3d &_angAccel) + { + auto accel = msg.mutable_data(_modelIdx)->add_acceleration(); + + accel->mutable_linear()->set_x(_linAccel.X()); + accel->mutable_linear()->set_y(_linAccel.Y()); + accel->mutable_linear()->set_z(_linAccel.Z()); + + accel->mutable_angular()->set_x(_angAccel.X()); + accel->mutable_angular()->set_y(_angAccel.Y()); + accel->mutable_angular()->set_z(_angAccel.Z()); + } + + public: void recordContactInfo(int &_modelIdx, int &_contactIdx, bool contactStatus, + const std::vector &_position, const std::vector &_normal, + const std::vector &_force, const std::vector &_torque) + { + auto contact_status = msg.mutable_data(_modelIdx)->mutable_contact_info(_contactIdx); + auto contact_pos = msg.mutable_data(_modelIdx)->mutable_contact_info(_contactIdx)->add_contact_position(); + auto contact_normal = msg.mutable_data(_modelIdx)->mutable_contact_info(_contactIdx)->add_contact_normal(); + auto contact_wrench = msg.mutable_date(_modelIdx)->mutable_contact_info(_contactIdx)->add_contact_wrench(); + + contact_status->add_contact_status(contactStatus); + contact_pos->set_x(_position[0]); + contact_pos->set_y(_position[1]); + contact_pos->set_z(_position[2]); + + contact_normal->set_x(_normal[0]); + contact_normal->set_y(_normal[1]); + contact_normal->set_z(_normal[2]); + + contact_wrench->mutale_forces()->set_x(_force[0]); + contact_wrench->mutale_forces()->set_y(_force[1]); + contact_wrench->mutale_forces()->set_z(_force[2]); + + contact_wrench->mutale_torques()->set_x(_torque[0]); + contact_wrench->mutale_torques()->set_y(_torque[2]); + contact_wrench->mutale_torques()->set_z(_torque[3]); + } + + public: void recordContactInfo(int &_modelIdx, int &_contactIdx, bool contactStatus, + const ignition::math::Vector3d &_position, const ignition::math::Vector3d &_normal, + const ignition::math::Vector3d &_force, const ignition::math::Vector3d &_torque) + { + auto contact_status = msg.mutable_data(_modelIdx)->mutable_contact_info(_contactIdx); + auto contact_pos = msg.mutable_data(_modelIdx)->mutable_contact_info(_contactIdx)->add_contact_position(); + auto contact_normal = msg.mutable_data(_modelIdx)->mutable_contact_info(_contactIdx)->add_contact_normal(); + auto contact_wrench = msg.mutable_data(_modelIdx)->mutable_contact_info(_contactIdx)->add_contact_wrench(); + + contact_status->add_contact_status(contactStatus); + contact_pos->set_x(_position.X()); + contact_pos->set_y(_position.Y()); + contact_pos->set_z(_position.Z()); + + contact_normal->set_x(_normal.X()); + contact_normal->set_y(_normal.Y()); + contact_normal->set_z(_normal.Z()); + + contact_wrench->mutable_forces()->set_x(_force.X()); + contact_wrench->mutable_forces()->set_y(_force.Y()); + contact_wrench->mutable_forces()->set_z(_force.Z()); + + contact_wrench->mutable_torques()->set_x(_torque.X()); + contact_wrench->mutable_torques()->set_y(_torque.Y()); + contact_wrench->mutable_torques()->set_z(_torque.Z()); + } + + + private: mcap::McapWriter writer; private: mcap::ChannelId channelId; - private: T msg; + private: T msg; }; \ No newline at end of file diff --git a/proto/Accel.proto b/proto/Accel.proto new file mode 100644 index 0000000..4cc9f97 --- /dev/null +++ b/proto/Accel.proto @@ -0,0 +1,13 @@ +syntax = "proto3"; +import "Vector3.proto"; + +package benchmark_proto; + + +message Accel{ + // linear acceleration in world frame + benchmark_proto.Vector3 linear = 1; + + // angular acceleration in world frame + benchmark_proto.Vector3 angular = 2; +} \ No newline at end of file diff --git a/proto/Pose.proto b/proto/Pose.proto new file mode 100644 index 0000000..b702031 --- /dev/null +++ b/proto/Pose.proto @@ -0,0 +1,15 @@ +syntax = "proto3"; + +import "Quaternion.proto"; +import "Vector3.proto"; + +package benchmark_proto; + +// A position and orientation for an object or reference frame in 3D space +message Pose { + // Point denoting position in 3D space + benchmark_proto.Vector3 position = 1; + + // Quaternion denoting orientation in 3D space + benchmark_proto.Quaternion orientation = 2; +} \ No newline at end of file diff --git a/proto/Quaternion.proto b/proto/Quaternion.proto new file mode 100644 index 0000000..78da979 --- /dev/null +++ b/proto/Quaternion.proto @@ -0,0 +1,17 @@ +syntax = "proto3"; + +package benchmark_proto; + +message Quaternion { + // x value + double x = 1; + + // y value + double y = 2; + + // z value + double z = 3; + + // w value + double w = 4; +} \ No newline at end of file diff --git a/proto/Twist.proto b/proto/Twist.proto new file mode 100644 index 0000000..07baee7 --- /dev/null +++ b/proto/Twist.proto @@ -0,0 +1,13 @@ +syntax = "proto3"; +import "Vector3.proto"; + +package benchmark_proto; + + +message Twist{ + // linear velocity in world frame + benchmark_proto.Vector3 linear = 1; + + //angular velocity in world frame + benchmark_proto.Vector3 angular = 2; +} \ No newline at end of file diff --git a/proto/Vector3.proto b/proto/Vector3.proto new file mode 100644 index 0000000..3bb7f9e --- /dev/null +++ b/proto/Vector3.proto @@ -0,0 +1,15 @@ +syntax = "proto3"; + +package benchmark_proto; + +// A vector in 3D space that represents a direction only +message Vector3 { + // x coordinate length + double x = 1; + + // y coordinate length + double y = 2; + + // z coordinate length + double z = 3; +} diff --git a/proto/Wrench.proto b/proto/Wrench.proto new file mode 100644 index 0000000..7f516b5 --- /dev/null +++ b/proto/Wrench.proto @@ -0,0 +1,12 @@ +syntax = "proto3"; +import "Vector3.proto"; + +package benchmark_proto; + +message Wrench{ + // forces in world frame + benchmark_proto.Vector3 forces = 1; + + // torques in world frame + benchmark_proto.Vector3 torques = 2; +} \ No newline at end of file diff --git a/proto/boxes_msg.proto b/proto/boxes_msg.proto index f476b46..20c7155 100644 --- a/proto/boxes_msg.proto +++ b/proto/boxes_msg.proto @@ -1,45 +1,8 @@ syntax = "proto3"; +import "Pose.proto"; +import "Twist.proto"; package benchmark_proto; -message Pose{ - // position in world frame - Vector3 position = 1; - - // orientation of boyd wrt world frame - Quaternion orientation = 2; -} - -message Twist{ - // linear velocity in world frame - Vector3 linear = 1; - - //angular velocity in world frame - Vector3 angular = 2; -} - -message Vector3 { - // x coordinate length - double x = 1; - - // y coordinate length - double y = 2; - - // z coordinate length - double z = 3; - } -message Quaternion { - // x value - double x = 1; - - // y value - double y = 2; - - // z value - double z = 3; - - // w value - double w = 4; - } message BoxesMsg { @@ -65,10 +28,10 @@ message BoxesMsg { // model number int32 model_no = 1; // model pose in world frame - repeated Pose poses = 4; + repeated benchmark_proto.Pose poses = 4; // model twist in world frame - repeated Twist twists = 5; + repeated benchmark_proto.Twist twists = 5; } // simulation time repeated double sim_time = 7; diff --git a/proto/triball_msg.proto b/proto/triball_msg.proto new file mode 100644 index 0000000..3ee092f --- /dev/null +++ b/proto/triball_msg.proto @@ -0,0 +1,70 @@ + +syntax = "proto3"; + +import "Pose.proto"; +import "Vector3.proto"; +import "Wrench.proto"; +import "Twist.proto"; +import "Accel.proto"; + +package benchmark_proto; + +message ContactInfo{ + // contact on + repeated bool contact_status = 1; + + // model contact position + repeated benchmark_proto.Vector3 contact_position = 2; + + // model contact normal + repeated benchmark_proto.Vector3 contact_normal = 3; + + // model Wrench + repeated benchmark_proto.Wrench contact_wrench = 4; +} + +message TriballsMsg { + // name of physics engine + string physics_engine = 1; + + // gravity option + double slope = 2; + + // collision check + double friction_coefficient = 3; + + // fixed configuration + bool complex = 4; + + // friction model pyramid or cone + string friction_model = 5; + + // centre of gravity height + double cog_h = 6; + + // log if models have equal kinetic energy + bool equal_ke = 7; + + message TriballMsg{ + // model number + int32 model_no = 1; + // model pose in world frame + repeated benchmark_proto.Pose poses = 2; + + // model twist in world frame + repeated benchmark_proto.Twist twists = 3; + + // model acceleration + repeated benchmark_proto.Accel acceleration = 4; + + // model contact information + repeated ContactInfo contact_info = 5; + } + // simulation time + repeated double sim_time = 8; + + // computational time + double computation_time = 9; + // array of box msg + repeated TriballMsg data = 10; +} diff --git a/test_results/BENCHMARK_triball_configuration_20240817-194729.csv b/test_results/BENCHMARK_triball_configuration_20240817-194729.csv new file mode 100644 index 0000000..f417079 --- /dev/null +++ b/test_results/BENCHMARK_triball_configuration_20240817-194729.csv @@ -0,0 +1,81 @@ +energy0,energyErr_maxabs,contactForceErr_a_maxAbs,contactForceErr_b_maxAbs,contactForceErr_c_maxAbs,frictionForceMagErr_a_maxAbs,frictionForceMagErr_b_maxAbs,frictionForceMagErr_c_maxAbs,frictionForceDirErr_a_maxAbs,frictionForceDirErr_b_maxAbs,frictionForceDirErr_c_maxAbs,face_angle,dt,engine,friction_coefficient,friction_model,cog_h,surface_slope,isComplex,modelCount,simTime,time,timeRatio,classname +0.01543352874652126,0,0.002687564649866747,0.0025145998624614974,0.002514599861967698,0,0,0,0,0,0,30,0.001,ode,0.8999999761581421,pyramid_model,0.0,0.0,False,5,1.0,0.272716952,0.272716952,static +0.015969363513895395,0,0.002720202914760661,0.0026322394213476596,0.002632239421347604,0,0,0,0,0,0,45,0.001,ode,0.8999999761581421,pyramid_model,0.0,0.0,False,5,1.0,0.272716952,0.272716952,static +0.01182244147375615,0,0.08195895887506097,0.0819589588750608,0.08195895887506097,0,0,0,0,0,0,60,0.001,ode,0.8999999761581421,pyramid_model,0.0,0.0,False,5,1.0,0.272716952,0.272716952,static +0.01744123985262436,0,0.0028435628505660837,0.0029385285380506554,0.002938528538050822,0,0,0,0,0,0,75,0.001,ode,0.8999999761581421,pyramid_model,0.0,0.0,False,5,1.0,0.272716952,0.272716952,static +0.018511948945339248,0,0.0029500626002950114,0.0031529559364791293,0.003152955936472801,0,0,0,0,0,0,90,0.001,ode,0.8999999761581421,pyramid_model,0.0,0.0,False,5,1.0,0.272716952,0.272716952,static +0.023150293119980594,0,0.002687564649948959,0.002514599903153003,0.002514599862052491,0,0,0,0,0,0,30,0.001,ode,0.8999999761581421,pyramid_model,0.0099999997764825,0.0,False,5,1.0,0.304009632,0.304009632,static +0.02395404527105569,0,0.002720202914764158,0.00263223942148616,0.002632239421486493,0,0,0,0,0,0,45,0.001,ode,0.8999999761581421,pyramid_model,0.0099999997764825,0.0,False,5,1.0,0.304009632,0.304009632,static +0.017733662210750706,0,0.08195895887520385,0.0819589588752038,0.08195895887519908,0,0,0,0,0,0,60,0.001,ode,0.8999999761581421,pyramid_model,0.0099999997764825,0.0,False,5,1.0,0.304009632,0.304009632,static +0.02616185977919014,0,0.0028435628505799615,0.002938528538139751,0.0029385285381474113,0,0,0,0,0,0,75,0.001,ode,0.8999999761581421,pyramid_model,0.0099999997764825,0.0,False,5,1.0,0.304009632,0.304009632,static +0.027767923418294743,0,0.0029500626004234087,0.0031529559365984228,0.0031529559365976456,0,0,0,0,0,0,90,0.001,ode,0.8999999761581421,pyramid_model,0.0099999997764825,0.0,False,5,1.0,0.304009632,0.304009632,static +-3.973902234879915e-13,2.677290465720573e-18,0.0026875646498965566,0.0025145998620108023,0.002514599862008693,0,0,0,0,0,0,30,0.001,ode,0.8999999761581421,pyramid_model,-0.0199999995529651,0.0,False,5,1.0,0.269482128,0.269482128,static +-4.2513533868973394e-13,1.5146129380243427e-27,0.0027202029148588602,0.002632239421510252,0.0026322394215101963,0,0,0,0,0,0,45,0.001,ode,0.8999999761581421,pyramid_model,-0.0199999995529651,0.0,False,5,1.0,0.269482128,0.269482128,static +-2.329497423538392e-13,8.582806648804608e-28,0.08195895887512986,0.0819589588751298,0.08195895887512997,0,0,0,0,0,0,60,0.001,ode,0.8999999761581421,pyramid_model,-0.0199999995529651,0.0,False,5,1.0,0.269482128,0.269482128,static +-5.071132351775702e-13,0,0.0028435628506461863,0.0029385285381643422,0.0029385285381642867,0,0,0,0,0,0,75,0.001,ode,0.8999999761581421,pyramid_model,-0.0199999995529651,0.0,False,5,1.0,0.269482128,0.269482128,static +-5.717001065232354e-13,0,0.0029500626003602926,0.0031529559365137683,0.0031529559365129356,0,0,0,0,0,0,90,0.001,ode,0.8999999761581421,pyramid_model,-0.0199999995529651,0.0,False,5,1.0,0.269482128,0.269482128,static +0.0077167643730619235,0,0.0026875646499609496,0.0025145998619338916,0.0025145998619330034,0,0,0,0,0,0,30,0.001,ode,0.8999999761581421,pyramid_model,-0.0099999997764825,0.0,False,5,1.0,0.269069996,0.269069996,static +0.007984681756735106,0,0.0027202029147688767,0.0026322394214248757,0.0026322394214227107,0,0,0,0,0,0,45,0.001,ode,0.8999999761581421,pyramid_model,-0.0099999997764825,0.0,False,5,1.0,0.269069996,0.269069996,static +0.0059112207367615945,0,0.08195895887506086,0.08195895887506069,0.08195895887506097,0,0,0,0,0,0,60,0.001,ode,0.8999999761581421,pyramid_model,-0.0099999997764825,0.0,False,5,1.0,0.269069996,0.269069996,static +0.008720619926058585,0,0.0028435628506545685,0.0029385285381594572,0.0029385285381592907,0,0,0,0,0,0,75,0.001,ode,0.8999999761581421,pyramid_model,-0.0099999997764825,0.0,False,5,1.0,0.269069996,0.269069996,static +0.009255974472383752,0,0.002950062600360903,0.003152955936491564,0.003152955936572943,0,0,0,0,0,0,90,0.001,ode,0.8999999761581421,pyramid_model,-0.0099999997764825,0.0,False,5,1.0,0.269069996,0.269069996,static +0.014920628910586986,0,0.041463597944216696,0.017167143354699932,0.017167143367196352,0,0,0,0,0,0,30,0.001,ode,0.8999999761581421,pyramid_model,0.0,0.3926990816987241,False,5,1.0,0.443758473,0.443758473,static +0.015090389813596014,0,0.04284711498178695,0.017735141804895688,0.017735141805055005,0,0,0,0,0,0,45,0.001,ode,0.8999999761581421,pyramid_model,0.0,0.3926990816987241,False,5,1.0,0.443758473,0.443758473,static +0.010922511701929536,0,0.1055802590048873,0.06079016826540945,0.0607901682654097,0,0,0,0,0,0,60,0.001,ode,0.8999999761581421,pyramid_model,0.0,0.3926990816987241,False,5,1.0,0.443758473,0.443758473,static +0.01575018656868999,0,0.04667861733641157,0.019310939321256715,0.019310939456682663,0,0,0,0,0,0,75,0.001,ode,0.8999999761581421,pyramid_model,0.0,0.3926990816987241,False,5,1.0,0.443758473,0.443758473,static +0.01632637155456518,6.938893903907228e-17,0.04948131552997906,0.020464995599521918,0.020464996337430152,0,0,0,0,0,0,90,0.001,ode,0.8999999761581421,pyramid_model,0.0,0.3926990816987241,False,5,1.0,0.443758473,0.443758473,static +0.022049989572433825,2.3592239273284576e-16,0.060953908090010694,0.02691229881045301,0.026912299271470957,0,0,0,0,0,0,30,0.001,ode,0.8999999761581421,pyramid_model,0.0099999997764825,0.3926990816987241,False,5,1.0,0.560379103,0.560379103,static +0.02246727386264717,0,0.06301410678403674,0.02781863837627771,0.02781863837812734,0,0,0,0,0,0,45,0.001,ode,0.8999999761581421,pyramid_model,0.0099999997764825,0.3926990816987241,False,5,1.0,0.560379103,0.560379103,static +0.016383767552991656,0,0.1205102892515113,0.053325153241277734,0.053325153272079706,0,0,0,0,0,0,60,0.001,ode,0.8999999761581421,pyramid_model,0.0099999997764825,0.3926990816987241,False,5,1.0,0.560379103,0.560379103,static +0.02380631678906888,3.5957150144108607e-06,0.3549815008971037,0.6539527366281477,0.6539527467934396,0,0,0,0,0,0,75,0.001,ode,0.8999999761581421,pyramid_model,0.0099999997764825,0.3926990816987241,False,5,1.0,0.560379103,0.560379103,static +0.0248770951664992,3.7755858138706355e-06,0.27255024559475927,0.7096611389782546,0.7096611601817124,0,0,0,0,0,0,90,0.001,ode,0.8999999761581421,pyramid_model,0.0099999997764825,0.3926990816987241,False,5,1.0,0.560379103,0.560379103,static +0.000661907586886465,0,0.002482977653829377,0.002323179561661254,0.0023231795616611706,0,0,0,0,0,0,30,0.001,ode,0.8999999761581421,pyramid_model,-0.0199999995529651,0.3926990816987241,False,5,1.0,0.492118075,0.492118075,static +0.0003366217154864576,2.5478751053409354e-18,0.0025131313777311537,0.0024318639787956897,0.0024318639787960783,0,0,0,0,0,0,45,0.001,ode,0.8999999761581421,pyramid_model,-0.0199999995529651,0.3926990816987241,False,5,1.0,0.492118075,0.492118075,static +-1.9883545836735189e-13,1.8887693972841785e-18,0.07572019851184991,0.07572019851184963,0.07572019851185,0,0,0,0,0,0,60,0.001,ode,0.8999999761581421,pyramid_model,-0.0199999995529651,0.3926990816987241,False,5,1.0,0.492118075,0.492118075,static +-0.0003634179532303531,0,0.0026271007157262494,0.0027148372767689666,0.002714837276768911,0,0,0,0,0,0,75,0.001,ode,0.8999999761581421,pyramid_model,-0.0199999995529651,0.3926990816987241,False,5,1.0,0.492118075,0.492118075,static +-0.0007764391834391927,3.0357660829594124e-18,0.0027254933250826507,0.002912941697632676,0.0029129416976318434,0,0,0,0,0,0,90,0.001,ode,0.8999999761581421,pyramid_model,-0.0199999995529651,0.3926990816987241,False,5,1.0,0.492118075,0.492118075,static +0.0077912682487379144,0,0.02197328779903468,0.007421987791608131,0.007421987792162826,0,0,0,0,0,0,30,0.001,ode,0.8999999761581421,pyramid_model,-0.0099999997764825,0.3926990816987241,False,5,1.0,0.744436769,0.744436769,static +0.007713505764542493,0,0.022680123179781658,0.007651645358290798,0.007651645358295517,0,0,0,0,0,0,45,0.001,ode,0.8999999761581421,pyramid_model,-0.0099999997764825,0.3926990816987241,False,5,1.0,0.744436769,0.744436769,static +0.005461255850866029,0,0.09065022875842771,0.06825518338863684,0.06825518338863712,0,0,0,0,0,0,60,0.001,ode,0.8999999761581421,pyramid_model,-0.0099999997764825,0.3926990816987241,False,5,1.0,0.744436769,0.744436769,static +0.007693384307731499,0,0.024652859025950963,0.00829805856800886,0.008298058568008693,0,0,0,0,0,0,75,0.001,ode,0.8999999761581421,pyramid_model,-0.0099999997764825,0.3926990816987241,False,5,1.0,0.744436769,0.744436769,static +0.00777496618556788,0,0.026103402049984653,0.008776031840988519,0.00877603184098913,0,0,0,0,0,0,90,0.001,ode,0.8999999761581421,pyramid_model,-0.0099999997764825,0.3926990816987241,False,5,1.0,0.744436769,0.744436769,static +0.015355309819531041,0,0.02895956498489355,0.010752922828588751,0.010752922836306356,0,0,0,0,0,0,30,0.001,ode,0.8999999761581421,pyramid_model,0.0,0.2617993877991494,False,5,1.0,0.541448457,0.541448457,static +0.015652886921192027,2.0816681711721685e-17,0.029906405481638892,0.011096951481865014,0.011096951481905426,0,0,0,0,0,0,45,0.001,ode,0.8999999761581421,pyramid_model,0.0,0.2617993877991494,False,5,1.0,0.541448457,0.541448457,static +0.011419601549298464,0,0.09936138815227008,0.06906868916506376,0.06906868916506403,0,0,0,0,0,0,60,0.001,ode,0.8999999761581421,pyramid_model,0.0,0.2617993877991494,False,5,1.0,0.541448457,0.541448457,static +0.01660115473039717,0,0.03253982471317343,0.012058237372977176,0.01205823737297712,0,0,0,0,0,0,75,0.001,ode,0.8999999761581421,pyramid_model,0.0,0.2617993877991494,False,5,1.0,0.541448457,0.541448457,static +0.017356042985971477,0,0.03447168323937394,0.012765615547965126,0.012765615547965403,0,0,0,0,0,0,90,0.001,ode,0.8999999761581421,pyramid_model,0.0,0.2617993877991494,False,5,1.0,0.541448457,0.541448457,static +0.022809131823241027,5.898059818321144e-17,0.04214136677784344,0.01734382399500095,0.01734382426357317,0,0,0,0,0,0,30,0.001,ode,0.8999999761581421,pyramid_model,0.0099999997764825,0.2617993877991494,False,5,1.0,0.669525263,0.669525263,static +0.02336549724512996,0,0.043545864613193375,0.017916681495562026,0.01791668149670711,0,0,0,0,0,0,45,0.001,ode,0.8999999761581421,pyramid_model,0.0099999997764825,0.2617993877991494,False,5,1.0,0.669525263,0.669525263,static +0.017129402324055444,0,0.10945895448138149,0.06401990600062085,0.06401990600062113,0,0,0,0,0,0,60,0.001,ode,0.8999999761581421,pyramid_model,0.0099999997764825,0.2617993877991494,False,5,1.0,0.669525263,0.669525263,static +0.0250246267387142,0,0.047436415799439524,0.019506533492008593,0.01950653349200926,0,0,0,0,0,0,75,0.001,ode,0.8999999761581421,pyramid_model,0.0099999997764825,0.2617993877991494,False,5,1.0,0.669525263,0.669525263,static +0.026296627776866463,0,0.05028276868862977,0.020671158942346002,0.020671158942348,0,0,0,0,0,0,90,0.001,ode,0.8999999761581421,pyramid_model,0.0099999997764825,0.2617993877991494,False,5,1.0,0.669525263,0.669525263,static +0.0004476658121079386,0,0.0025959613999603226,0.0024288919628224492,0.002428891962822338,0,0,0,0,0,0,30,0.001,ode,0.8999999761581421,pyramid_model,-0.0199999995529651,0.2617993877991494,False,5,1.0,0.6304898280000001,0.6304898280000001,static +0.00022766627331277908,0,0.0026274872186292653,0.002542521882606563,0.0025425218826066187,0,0,0,0,0,0,45,0.001,ode,0.8999999761581421,pyramid_model,-0.0199999995529651,0.2617993877991494,False,5,1.0,0.6304898280000001,0.6304898280000001,static +-2.173457602035996e-13,1.9807860381685035e-18,0.07916625549410189,0.07916625549410167,0.07916625549410194,0,0,0,0,0,0,60,0.001,ode,0.8999999761581421,pyramid_model,-0.0199999995529651,0.2617993877991494,False,5,1.0,0.6304898280000001,0.6304898280000001,static +-0.00024578928624088684,2.927345865710862e-18,0.0027466425407742245,0.002838371407402618,0.0028383714074023403,0,0,0,0,0,0,75,0.001,ode,0.8999999761581421,pyramid_model,-0.0199999995529651,0.2617993877991494,False,5,1.0,0.6304898280000001,0.6304898280000001,static +-0.0005251265958229948,0,0.0028495123412822787,0.003045490238676063,0.003045490238675286,0,0,0,0,0,0,90,0.001,ode,0.8999999761581421,pyramid_model,-0.0199999995529651,0.2617993877991494,False,5,1.0,0.6304898280000001,0.6304898280000001,static +0.007901487815819999,0,0.015777763192373756,0.004162021606392369,0.004162021606625765,0,0,0,0,0,0,30,0.001,ode,0.8999999761581421,pyramid_model,-0.0099999997764825,0.2617993877991494,False,5,1.0,0.489866508,0.489866508,static +0.00794027659725296,2.0816681711721685e-17,0.016266946350116995,0.004277221550319732,0.004277221550322785,0,0,0,0,0,0,45,0.001,ode,0.8999999761581421,pyramid_model,-0.0099999997764825,0.2617993877991494,False,5,1.0,0.489866508,0.489866508,static +0.005709800774540858,0,0.08926382182324949,0.07411747232965765,0.07411747232965896,0,0,0,0,0,0,60,0.001,ode,0.8999999761581421,pyramid_model,-0.0099999997764825,0.2617993877991494,False,5,1.0,0.489866508,0.489866508,static +0.008177682722078765,0,0.01764323362686493,0.004609941367190118,0.0046099413671907286,0,0,0,0,0,0,75,0.001,ode,0.8999999761581421,pyramid_model,-0.0099999997764825,0.2617993877991494,False,5,1.0,0.489866508,0.489866508,static +0.008415458195074969,0,0.018660597790356948,0.004860072289030015,0.004860072289030681,0,0,0,0,0,0,90,0.001,ode,0.8999999761581421,pyramid_model,-0.0099999997764825,0.2617993877991494,False,5,1.0,0.489866508,0.489866508,static +0.015527257120171065,8.673617379884035e-18,0.015960179988355083,0.004154714544230331,0.004154714547207061,0,0,0,0,0,0,30,0.001,ode,0.8999999761581421,pyramid_model,0.0,0.1308996938995747,False,5,1.0,0.461740275,0.461740275,static +0.015947558793770897,0,0.016454147345032033,0.004268886272520089,0.00426888627254135,0,0,0,0,0,0,45,0.001,ode,0.8999999761581421,pyramid_model,0.0,0.1308996938995747,False,5,1.0,0.461740275,0.461740275,static +0.011721298848049767,0,0.09144253266542432,0.0761654282885946,0.07616542828859468,0,0,0,0,0,0,60,0.001,ode,0.8999999761581421,pyramid_model,0.0,0.1308996938995747,False,5,1.0,0.461740275,0.461740275,static +0.017168072531962793,0,0.01784443688738052,0.00459921200674257,0.004599212006742404,0,0,0,0,0,0,75,0.001,ode,0.8999999761581421,pyramid_model,0.0,0.1308996938995747,False,5,1.0,0.461740275,0.461740275,static +0.018088747709883755,0,0.018872414916608404,0.004847815361599339,0.004847815361600338,0,0,0,0,0,0,90,0.001,ode,0.8999999761581421,pyramid_model,0.0,0.1308996938995747,False,5,1.0,0.461740275,0.461740275,static +0.023178003504669604,0,0.022607978586511313,0.007478613995801853,0.007478614067487954,0,0,0,0,0,0,30,0.001,ode,0.8999999761581421,pyramid_model,0.0099999997764825,0.1308996938995747,False,5,1.0,0.687388348,0.687388348,static +0.023863930491612145,1.3877787807814457e-17,0.023332750036833022,0.007708187836148572,0.007708187836812652,0,0,0,0,0,0,45,0.001,ode,0.8999999761581421,pyramid_model,0.0099999997764825,0.1308996938995747,False,5,1.0,0.687388348,0.687388348,static +0.017581948272188935,0,0.09653490079101862,0.07361924422588531,0.07361924422588556,0,0,0,0,0,0,60,0.001,ode,0.8999999761581421,pyramid_model,0.0099999997764825,0.1308996938995747,False,5,1.0,0.687388348,0.687388348,static +0.025814086346149297,0,0.025357031819213227,0.008355509772403735,0.008355509772404235,0,0,0,0,0,0,75,0.001,ode,0.8999999761581421,pyramid_model,0.0099999997764825,0.1308996938995747,False,5,1.0,0.687388348,0.687388348,static +0.027265536038100984,0,0.02684620433758883,0.008834710431220305,0.008834710431221138,0,0,0,0,0,0,90,0.001,ode,0.8999999761581421,pyramid_model,0.0099999997764825,0.1308996938995747,False,5,1.0,0.687388348,0.687388348,static +0.0002257643511732162,0,0.0026645827923860166,0.0024930970579158662,0.002493097057916255,0,0,0,0,0,0,30,0.001,ode,0.8999999761581421,pyramid_model,-0.0199999995529651,0.1308996938995747,False,5,1.0,0.50439544,0.50439544,static +0.00011481539808745786,2.7376104855258987e-18,0.0026969419615886503,0.0026097306600034176,0.0026097306600036396,0,0,0,0,0,0,45,0.001,ode,0.8999999761581421,pyramid_model,-0.0199999995529651,0.1308996938995747,False,5,1.0,0.50439544,0.50439544,static +-2.289824701360427e-13,2.0333044982457628e-18,0.0812577964141668,0.08125779641416661,0.08125779641416708,0,0,0,0,0,0,60,0.001,ode,0.8999999761581421,pyramid_model,-0.0199999995529651,0.1308996938995747,False,5,1.0,0.50439544,0.50439544,static +-0.00012395509641130033,0,0.002819247023879534,0.0029134006424947345,0.0029134006424086922,0,0,0,0,0,0,75,0.001,ode,0.8999999761581421,pyramid_model,-0.0199999995529651,0.1308996938995747,False,5,1.0,0.50439544,0.50439544,static +-0.00026482894655192743,0,0.0029248360747323177,0.00312599443289846,0.0031259944328969613,0,0,0,0,0,0,90,0.001,ode,0.8999999761581421,pyramid_model,-0.0199999995529651,0.1308996938995747,False,5,1.0,0.50439544,0.50439544,static +0.007876510735672266,0,0.009312381390320923,0.0008308150894459354,0.0008308150896490507,0,0,0,0,0,0,30,0.001,ode,0.8999999761581421,pyramid_model,-0.0099999997764825,0.1308996938995747,False,5,1.0,0.480640821,0.480640821,static +0.008031187095929272,0,0.009575544653254608,0.0008295847468903772,0.000829584746891876,0,0,0,0,0,0,45,0.001,ode,0.8999999761581421,pyramid_model,-0.0099999997764825,0.1308996938995747,False,5,1.0,0.480640821,0.480640821,static +0.005860649423910447,0,0.08635016453975561,0.07871161235130991,0.07871161235130977,0,0,0,0,0,0,60,0.001,ode,0.8999999761581421,pyramid_model,-0.0099999997764825,0.1308996938995747,False,5,1.0,0.480640821,0.480640821,static +0.008522058717775845,0,0.010331841955577292,0.0008429143018370278,0.0008429143018366947,0,0,0,0,0,0,75,0.001,ode,0.8999999761581421,pyramid_model,-0.0099999997764825,0.1308996938995747,False,5,1.0,0.480640821,0.480640821,static +0.008911959381666048,0,0.010898625495668723,0.0008609203689557976,0.0008609203689564637,0,0,0,0,0,0,90,0.001,ode,0.8999999761581421,pyramid_model,-0.0099999997764825,0.1308996938995747,False,5,1.0,0.480640821,0.480640821,static diff --git a/tools/TestMacro.cmake b/tools/TestMacro.cmake index b316fcb..d7f7b2d 100644 --- a/tools/TestMacro.cmake +++ b/tools/TestMacro.cmake @@ -63,8 +63,14 @@ macro (gz_build_tests) # ${CMAKE_BINARY_DIR}/test_results/${BINARY_NAME}.xml) # Convert junit file to csv and place in test_results in source folder. - add_test(NAME csv_${BINARY_NAME} - COMMAND python3 ${PROJECT_SOURCE_DIR}/tools/mcap_to_csv.py ${BINARY_NAME} + add_test(NAME mcap2csv_${BINARY_NAME} + COMMAND python3 ${PROJECT_SOURCE_DIR}/tools/${TEST_NAME}/mcap_to_csv.py + ${BINARY_NAME} + ) + + add_test(NAME post_processing_${BINARY_NAME} + COMMAND python3 ${PROJECT_SOURCE_DIR}/boxes_post_processing.py + ${BINARY_NAME} ) install(TARGETS ${BINARY_NAME} @@ -73,4 +79,5 @@ macro (gz_build_tests) endforeach() set(GZ_BUILD_TESTS_EXTRA_EXE_SRCS "") + set(TEST_NAME "") endmacro() diff --git a/tools/boxes/mcap_to_csv.py b/tools/boxes/mcap_to_csv.py new file mode 100644 index 0000000..0c11fc0 --- /dev/null +++ b/tools/boxes/mcap_to_csv.py @@ -0,0 +1,113 @@ + +import os +import sys +tools_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) +benchmark_dir = os.path.dirname(tools_dir) +print(f"the path is {benchmark_dir}") +sys.path.append(os.path.join(benchmark_dir,"mcap/python/mcap")) +sys.path.append(os.path.join(benchmark_dir, "mcap/python/mcap-protobuf-support")) +from mcap_protobuf.decoder import DecoderFactory +from mcap.reader import make_reader +import csv + +BENCHMARK_NAME = sys.argv[1] + +STATES_NAMES = ["sim_time", + "model_no", + "linear_velocity_x", + "linear_velocity_y", + "linear_velocity_z", + "angular_velocity_x", + "angular_velocity_y", + "angular_velocity_z", + "position_x", + "position_y", + "position_z", + "quaternion_w", + "quaternion_x", + "quaternion_y", + "quaternion_z",] + +CONFIGURATION = ["physics_engine", "time_step", "complex", + "collisiion", "model_count","wall_time", + "log_multiple", "classname"] + + + +def get_file_names(result_folder): + result_dir = os.path.join(benchmark_dir,"test_results", result_folder) + mcap_dir = os.path.join(result_dir, "MCAP") + file_names = os.listdir(mcap_dir) + csv_dir = os.path.join(result_dir,"CSV") + if not os.path.isdir(csv_dir): + os.mkdir(csv_dir) + return result_dir, file_names + + +def MCAP_to_CSV(result_dir, file_name): + + csv_filename = file_name.split('.mcap')[0] + '.csv' + + csv_filepath = os.path.join(result_dir,"CSV",csv_filename) + mcap_filepath = os.path.join(result_dir,"MCAP",file_name) + + csv_file = open(csv_filepath, mode='w', newline='') + csv_writer = csv.writer(csv_file) + csv_writer.writerow(CONFIGURATION) + + + with open(mcap_filepath, "rb") as f: + reader = make_reader(f, decoder_factories=[DecoderFactory()]) + + for schema, channel, message, proto_msg in reader.iter_decoded_messages(): + time_steps = proto_msg.sim_time + physics_engine = proto_msg.physics_engine + dt = proto_msg.dt + complex = proto_msg.complex + collision = proto_msg.collision + model_count = proto_msg.model_count + wall_time = proto_msg.computation_time + log_multiple = proto_msg.log_multiple + + if complex: + class_name = "DtComplex" + else: + class_name = "DtSimple" + + if "dartsim-plugin" in physics_engine: + engine = "dart" + elif "bullet-featherstone-plugin" in physics_engine: + engine = "bullet-featherstone" + elif "bullet-plugin" in physics_engine: + engine = "bullet" + else: + engine = physics_engine + + csv_writer.writerow([engine, dt, complex, collision, model_count, + wall_time, log_multiple, class_name]) + + csv_writer.writerow(STATES_NAMES) + for data in proto_msg.data: + for t in range(len(time_steps)): + row = [ time_steps[t], data.model_no, + data.twists[t].linear.x, data.twists[t].linear.y, + data.twists[t].linear.z, data.twists[t].angular.x, + data.twists[t].angular.y, data.twists[t].angular.z, + data.poses[t].position.x, data.poses[t].position.y, + data.poses[t].position.z, data.poses[t].orientation.w, + data.poses[t].orientation.x, data.poses[t].orientation.y, + data.poses[t].orientation.z] + + csv_writer.writerow(row) + + csv_file.close() + + + +print("Started converting files from MCAP to CSV") + +result_dir,file_names = get_file_names(BENCHMARK_NAME) +for file_name in file_names: + MCAP_to_CSV(result_dir, file_name) + +print("Successfully !! converted all files from MCAP to CSV") diff --git a/plot_helpers.py b/tools/boxes/plot_helpers.py similarity index 98% rename from plot_helpers.py rename to tools/boxes/plot_helpers.py index ac362bd..3225435 100644 --- a/plot_helpers.py +++ b/tools/boxes/plot_helpers.py @@ -53,14 +53,16 @@ def plotEnginesDt(params, yname if not skipDart: engines['dart'] = ['$d$', 'g--'] engines['ode'] = ['$O$', 'r--'] - engines['simbody'] = ['$S$', 'k--'] + # engines['simbody'] = ['$S$', 'k--'] fig = plt.figure() xdata = {} ydata = {} for e in sorted(engines.keys()): params['engine'] = e ii = np.array(list(query(csvDict, params))) + print(f"here here {ii} {e}") xdata[e] = csvDict[xname][ii] + ydata[e] = csvDict[yname][ii] color = engines[e][1][0] plt.plot(xdata[e] diff --git a/tools/triball/mcap_to_csv.py b/tools/triball/mcap_to_csv.py new file mode 100644 index 0000000..f0f0632 --- /dev/null +++ b/tools/triball/mcap_to_csv.py @@ -0,0 +1,148 @@ + +import os +import sys +tools_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) +benchmark_dir = os.path.dirname(tools_dir) +sys.path.append(os.path.join(benchmark_dir,"mcap/python/mcap")) +sys.path.append(os.path.join(benchmark_dir, "mcap/python/mcap-protobuf-support")) +from mcap_protobuf.decoder import DecoderFactory +from mcap.reader import make_reader +import csv + +DIRECTORY_NAME = sys.argv[1] + +STATES_NAMES = ["sim_time", "model_no", "linear_accel_x", "linear_accel_y", + "linear_accel_z", "angular_accel_x", "angular_accel_y", + "angular_accel_z", "linear_vel_x", "linear_vel_y", + "linear_vel_z", "angular_vel_x", "angular_vel_y", + "angular_vel_z", "pos_x", "pos_y", "pos_z", "quat_w", + "quat_x", "quat_y", "quat_z"] + +for i in range(1,4): + contact_info = [] + status = ["{}{}{}".format("contact", str(i), "_status")] + contact_info += status + for j in ["_pos_", "_normal_", "force", "_torque_"]: + x = ["{}{}{}".format("contact", str(i), j + "x")] + y = ["{}{}{}".format("contact", str(i), j + "y")] + z = ["{}{}{}".format("contact", str(i), j + "z")] + contact_info += x + y + z + STATES_NAMES = STATES_NAMES + contact_info + +CONFIGURATION = ["physics_engine", "time_step", "complex", + "slope", "friction coefficeint","friction model", + "cog height", "cog_h", "wall_time", "equal_KE"] + + + +def get_file_names(result_folder): + result_dir = os.path.join(benchmark_dir,"test_results", result_folder) + result_dir = os.path.expanduser(result_dir) + mcap_dir = os.path.join(result_dir, "MCAP") + file_names = os.listdir(mcap_dir) + csv_dir = os.path.join(result_dir,"CSV") + if not os.path.isdir(csv_dir): + os.mkdir(csv_dir) + return result_dir, file_names + +def add_twist(data, t): + return [data.twists[t].linear.x, data.twists[t].linear.y, + data.twists[t].linear.z, data.twists[t].angular.x, + data.twists[t].angular.y, data.twists[t].angular.z] + +def add_pose(data, t): + return [data.poses[t].position.x, data.poses[t].position.y, + data.poses[t].position.z, data.poses[t].orientation.w, + data.poses[t].orientation.x, data.poses[t].orientation.y, + data.poses[t].orientation.z] + +def add_acceleration(data, t): + return [data.acceleration[t].linear.x, data.acceleration[t].linear.y, + data.acceleration[t].linear.z, data.acceleration[t].angular.x, + data.acceleration[t].angular.y, data.acceleration[t].angular.z] + +def add_contact_status(data, t, idx): + return [data.contact_info[idx].contact_status[t]] + +def add_contact_position(data, t, idx): + return [data.contact_info[idx].contact_position[t].x, + data.contact_info[idx].contact_position[t].y, + data.contact_info[idx].contact_position[t].z] + +def add_contact_normal(data, t ,idx): + return [data.contact_info[idx].contact_normal[t].x, + data.contact_info[idx].contact_normal[t].y, + data.contact_info[idx].contact_normal[t].z] + +def add_contact_wrench(data, t, idx): + return [data.contact_info[idx].contact_wrench[t].forces.x, + data.contact_info[idx].contact_wrench[t].forces.y, + data.contact_info[idx].contact_wrench[t].forces.z, + data.contact_info[idx].contact_wrench[t].torques.x, + data.contact_info[idx].contact_wrench[t].torques.y, + data.contact_info[idx].contact_wrench[t].torques.z] + +def MCAP_to_CSV(result_dir, file_name): + + csv_filename = file_name.split('.mcap')[0] + '.csv' + + csv_filepath = os.path.join(result_dir,"CSV",csv_filename) + mcap_filepath = os.path.join(result_dir,"MCAP",file_name) + + csv_file = open(csv_filepath, mode='w', newline='') + csv_writer = csv.writer(csv_file) + csv_writer.writerow(CONFIGURATION) + + + with open(mcap_filepath, "rb") as f: + reader = make_reader(f, decoder_factories=[DecoderFactory()]) + + for schema, channel, message, proto_msg in reader.iter_decoded_messages(): + time_steps = proto_msg.sim_time + physics_engine = proto_msg.physics_engine + slope = proto_msg.slope + complex = proto_msg.complex + friction_model = proto_msg.friction_model + friction_coefficeint = proto_msg.friction_coefficient + wall_time = proto_msg.computation_time + cog_h = proto_msg.cog_h + equal_KE = proto_msg.equal_ke + dt = 1e-3 + + + if "dartsim-plugin" in physics_engine: + engine = "dart" + elif "bullet-featherstone-plugin" in physics_engine: + engine = "bullet-featherstone" + elif "bullet-plugin" in physics_engine: + engine = "bullet" + else: + engine = physics_engine + + csv_writer.writerow([engine, dt, complex, slope, friction_coefficeint, + friction_model, cog_h, wall_time, equal_KE]) + + csv_writer.writerow(STATES_NAMES) + for data in proto_msg.data: + for t in range(len(time_steps)): + row = [time_steps[t], data.model_no] + add_acceleration(data, t) +\ + add_twist(data, t) + add_pose(data, t) + + for idx in range(3): + row = row + add_contact_status(data, t, idx) + add_contact_position(data, t , idx) +\ + add_contact_normal(data, t, idx) + add_contact_wrench(data, t, idx) + + csv_writer.writerow(row) + + csv_file.close() + + + +print("Started converting files from MCAP to CSV") + +result_dir,file_names = get_file_names(DIRECTORY_NAME) +for file_name in file_names: + MCAP_to_CSV(result_dir, file_name) + print(file_name) + +print("Successfully !! converted all files from MCAP to CSV") diff --git a/triball.cc b/triball.cc new file mode 100644 index 0000000..7d3823c --- /dev/null +++ b/triball.cc @@ -0,0 +1,198 @@ +/* + * Copyright (C) 2024 Open Source Robotics Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * +*/ +#include +#include +#include + +#include "PathConfig.h" +#include "triball.hh" +#include "gazebo/common/common.hh" +#include "gazebo/msgs/msgs.hh" +#include "gazebo/physics/physics.hh" +#include "gazebo/physics/ContactManager.hh" +#include +#include +#include "log.hh" + +using namespace gazebo; +using namespace benchmark; + +void TriballTest::Triball(const std::string &_physicsEngine, const std::string &_frictionModel, + bool _complex, double _surfaceSlope, float _frictionCoefficient + , double _cogH, bool _equalKE) +{ + + // logging result directory location + std::string result_name = boost::str(boost::format("%1%/%2%/MCAP/triball_frictionModel" + "%3%_complex%4%_surfaceSlope%5%_frictionCoefficient%6%_cogH%7%_equalKE%8%_%9%.mcap") + % RESULT_DIR_PATH % TEST_NAME % _frictionModel % _complex + % _surfaceSlope % _frictionCoefficient % _cogH % _equalKE % + _physicsEngine); + + Log log(result_name); + // setting benchmark parameters + log.setTriballMsg(_physicsEngine, _surfaceSlope, _frictionCoefficient, + _complex, _frictionModel, _cogH, _equalKE); + + // World creation based on test parameters using boxes.world.erb file. + std::string world_erb_path = + boost::str(boost::format("%1%/triball_contact.world.erb") % WORLDS_DIR_PATH); + + std::string worldPath = boost::str( + boost::format( + "%1%/%2%/" + "triball_frictionModel%3%_complex%4%_surfaceSlope%5%_frictionCoefficient%6%_cogH%7%_equalKE%8%.world") % + WORLDS_DIR_PATH % TEST_NAME % _frictionModel % _complex % _surfaceSlope % _frictionCoefficient % + _cogH % _equalKE); + + // Final world sdf path + std::string command = boost::str( + boost::format( + "erb frictionModel=%1% complex=%2% surfaceSlope=%3% fritionCoefficient=%4% cogH=%5% %6% > %7%") % + _frictionModel % _complex % _surfaceSlope % _frictionCoefficient % _cogH % world_erb_path % worldPath); + + // execute command + auto commandCheck = system(command.c_str()); + ASSERT_EQ(commandCheck, 0); + + Load(worldPath, true, _physicsEngine); + + physics::WorldPtr world = physics::get_world("default"); + ASSERT_NE(world, nullptr); + + physics::PhysicsEnginePtr physics = world->Physics(); + ASSERT_NE(physics, nullptr); + ASSERT_EQ(physics->GetType(), _physicsEngine); + physics->SetRealTimeUpdateRate(0.0); + + physics::ContactManager *mgr = physics->GetContactManager(); + mgr->SetNeverDropContacts(true); + world->Step(1); + + ASSERT_TRUE(mgr->NeverDropContacts()); + ASSERT_GT(mgr->GetContactCount(), 0); + + // initial time + common::Time t0 = world->SimTime(); + + ignition::math::Vector3d gravity = world->Gravity(); + + std::size_t modelCount = world->ModelCount(); + // checking if number of model spwaned are correct. + if(!_complex) + { + ASSERT_EQ(modelCount, 6); + } + else + { + ASSERT_EQ(modelCount, 20); + } + + auto contacts = mgr->GetContacts(); + auto models = world->Models(); + int contactCount = 3; + EXPECT_EQ(mgr->GetContactCount(), contactCount*(modelCount - 1)); + + physics::LinkPtr link; + + double _dt = 0.001; + const double simDuration = 1; + int steps = ceil(simDuration/_dt); + + std::vector collisionNames{"collision_a", "collision_b", "collision_c"}; + collisionNames.reserve(3); + + common::Time startTime = common::Time::GetWallTime(); + + for(int i = 0; iStep(1); + EXPECT_EQ(mgr->GetContactCount(), contactCount*(modelCount - 1)); + double t = (world->SimTime() - t0).Double(); + log.recordSimTime(t); + + for(int model_no = 1; model_no < modelCount; model_no++) + { + auto model = models[model_no]; + link = model->GetLink(); + auto modelIdx = model_no - 1; + + ignition::math::Pose3d pose = link->WorldInertialPose(); + log.recordPose(modelIdx, pose); + + ignition::math::Vector3d linearVelocity = link->WorldLinearVel(); + ignition::math::Vector3d angularVelocity = link->WorldAngularVel(); + log.recordTwist(modelIdx, linearVelocity, angularVelocity); + + ignition::math::Vector3d linearAcceleration = link->WorldLinearAccel(); + ignition::math::Vector3d angularAcceleration = link->WorldAngularAccel(); + log.recordAccel(modelIdx, linearAcceleration, angularAcceleration); + + for(int contactIdx = 0; contactIdx < collisionNames.size(); contactIdx++) + { + bool contactStatus = false; + ignition::math::Vector3d contactPosition; + ignition::math::Vector3d contactNormal; + ignition::math::Vector3d contactForce; + ignition::math::Vector3d contactTorque; + + for(auto contact : contacts) + { + std::string scopedName(contact->collision1->GetScopedName()); + std::string collisionName(scopedName.substr(scopedName.rfind("::") +2)); + + if(collisionName == collisionNames[contactIdx] && + contact->collision1->GetLink() == link) + { + contactStatus = true; + contactPosition = contact->positions[0]; + contactNormal = contact->normals[0]; + contactForce = contact->wrench[0].body1Force; + contactTorque = contact->wrench[0].body1Torque; + } + } + log.recordContactInfo(modelIdx, contactIdx, contactStatus, contactPosition, + contactNormal, contactForce, contactTorque); + } + } + } + + double elapsedTime = (common::Time::GetWallTime() - startTime).Double(); + log.recordComputationTime(elapsedTime); + + common::Time simTime = (world->SimTime() - t0).Double(); + ASSERT_NEAR(simTime.Double(), simDuration, _dt * 1.1); + + log.stop(); +} + +///////////////////////////////////////////////// +TEST_P(TriballTest, Triball) { + std::string physicsEngine = std::tr1::get<0>(GetParam()); + std::string frictionModel = std::tr1::get<1>(GetParam()); + bool complex = std::tr1::get<2>(GetParam()); + double surfaceSlope = std::tr1::get<3>(GetParam()); + float frictionCoefficient = std::tr1::get<4>(GetParam()); + float cogH = std::tr1::get<5>(GetParam()); + float equalKE = std::tr1::get<6>(GetParam()); + + gzdbg << physicsEngine << ", friction model: " << frictionModel << ", complex: " << complex + << ", surface slope: " << surfaceSlope << ", friction coefficient: " << frictionCoefficient + << " center of gravity of height" << cogH << std::endl << " equal kinetic energy" << equalKE; + + Triball(physicsEngine, frictionModel, complex, surfaceSlope, frictionCoefficient, cogH, equalKE); +} diff --git a/triball.hh b/triball.hh new file mode 100644 index 0000000..8772a66 --- /dev/null +++ b/triball.hh @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2024 Open Source Robotics Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * +*/ + +#ifndef BENCHMARK_GAZEBO_TRIBALL_HH_ +#define BENCHMARK_GAZEBO_TRIBALL_HH_ + +#include +#include "gazebo/test/ServerFixture.hh" + +namespace gazebo +{ + namespace benchmark + { + // physics engine + // dt + // number of boxes to spawn + // collision shape on / off + // complex trajectory on / off + typedef std::tr1::tuple < const char * + , const char * + , bool + , double + , float + , double + , bool + > char1double1int1bool2; + + class TriballTest : public ServerFixture, + public testing::WithParamInterface + { + /// \brief Test accuracy of unconstrained rigid body motion. + /// \param[in] _physicsEngine Physics engine to use. + /// \param[in] _frictionModel Max time step size. + /// \param[in] _complex Number of boxes to spawn. + /// \param[in] _surfaceSlope Flag for collision shape on / off. + /// \param[in] _frictionCoefficient Flag for complex trajectory on / off. + /// \param[in] _cogH + /// \param[in] _equalKE + public: void Triball(const std::string &_physicsEngine + , const std::string &_frictionModel + , bool _complex + , double _surfaceSlope + , float _frictionCoefficient + , double _cogH + , bool _equalKE); + }; + } +} +#endif \ No newline at end of file diff --git a/triball_configuration.cc b/triball_configuration.cc new file mode 100644 index 0000000..df48a62 --- /dev/null +++ b/triball_configuration.cc @@ -0,0 +1,40 @@ +#include + +#include "triball.hh" +#include "gazebo/test/helper_physics_generator.hh" +#include + + +using namespace gazebo; +using namespace benchmark; + + +const double slope_min = 0; +const double slope_max = IGN_PI/6; +const double slope_step = IGN_PI/24; +const float friction_coefficient = 0.9; + +// cog height with respect to link frame +const double cog_h_max = 0.02; +const double cog_h_min = -0.02; +const double cog_h_step = 0.01; + +INSTANTIATE_TEST_CASE_P( + OdeTriball, TriballTest, + ::testing::Combine(::testing::Values("ode"), ::testing::Values("pyramid_model"), + ::testing::Values(false), ::testing::Range(slope_min, slope_max, slope_step), + ::testing::Values(friction_coefficient), + ::testing::Range(cog_h_min, cog_h_max, cog_h_step), ::testing::Values(true))); + +// INSTANTIATE_TEST_CASE_P( +// BulletTriball, TriballTest, +// ::testing::Combine(::testing::Values("bullet"), ::testing::Values("pyramid"), +// ::testing::Values(false), ::testing::Range(slope_min, slope_max, slope_step), +// ::testing::Values(friction_coefficient), +// ::testing::Range(cog_h_min, cog_h_max, cog_h_step))); +///////////////////////////////////////////////// +int main(int argc, char **argv) +{ + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} \ No newline at end of file diff --git a/triball_description.ipynb b/triball_description.ipynb new file mode 100644 index 0000000..4526fba --- /dev/null +++ b/triball_description.ipynb @@ -0,0 +1,368 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Triball: a benchmark for rigid bodies in contact.\n", + "\n", + "This test simulates a rigid body that is in contact with the ground plane and verifies the contact forces experienced at each contact point.\n", + "\n", + "The model consists of three solid spheres connected by rods in a triangular configuration. This benchmark varies both triball configurations as well as the velocity of the center of mass(com). \n", + "The model doesn't consist of any joints.\n", + "\n", + "Two scenarios have been chosen to validate the simulated solutions and to represent simple and complex scenarios.\n", + "\n", + "In **simple** scenario the triball model is at rest and no external is applied except \n", + "gravitational and contact forces, here the test parameter being the configuration in which balls are arranged (eg: equilateral or isosceles triangle).\n", + "The normal/contact force experience at the contact point is a function of triball configuration, which forces can be computed analytically \n", + "and can be used to compare against the simulated/ numerical solution.\n", + "\n", + "In **complex** scenario the triball model has been given a specific initial velocity (both linear and angular). Possible metric for comparision here can be checking if total energy exceeds inital energy at t=0 and difference between friction cone and pyramid model.\n", + "\n", + "## Simple scenario\n", + "\n", + "As the rigid body is at rest. The forces experienced by it are a contact forces and gravitational force in the downward direction. In an equilibrium state, any rigid body should have a zero net force and torque about any point.\n", + "\n", + "![triball_static_case](img/triball/triball_static.jpg)\n", + "\n", + "## Complex scenario\n", + "As the rigid body is given a specific initial velocity, friction forces will be acting in the tangential plane to the normal force at each contact point. Energy conservation, checking frcition force direction and magnitude, and comparing difference in states between cone vs pryramid models can use a possible metrics.\n", + "\n", + "## Definition of coordinate frames and variable\n", + "\n", + "![triball_diagram](https://github.com/yaswanth1701/simulation_benchmark/assets/92177410/1b2589e8-efb3-4885-801f-0d9912178565)\n", + "\n", + "Consider an inertial frame $O$ and a rigid body with a coordinate frame $c$ attached at the center of mass:\n", + "\n", + "- The position of the center of gravity (cg) in $O$ is given by **c**.\n", + "- The orientation of $c$ with respect to $O$ is given by the quaternion **$q$**.\n", + "- A rotation matrix from $O$ to $c$ : $R(q)$ \n", + "- Angular velocity in frame $c$ : $\\omega$\n", + "- Three contact points for the model are expressed in frame $O$ as $C_a$, $C_b$ and $C_c$.\n", + "- The three contact force are denoted as $N_a$, $N_b$ and $N_c$ and are expressed in the $O$ frame\n", + " \n", + "Rigid body has the following inertial parameters:\n", + "- Total mass *m*\n", + "- inertia matrix $I$ expressed in $c$\n", + "- Density of model be $\\rho$\n", + "- Radius of ball/sphere is denoted as $R_s=0.02$.\n", + "- Radius of rod/cylinder is denoted as $R_c=0.005$.\n", + "- Mass of each ball and rod is $m_s$ and $m_c$ respectively.\n", + "\n", + "### Solution for simple scenario:" + ] + }, + { + "cell_type": "code", + "execution_count": 59, + "metadata": {}, + "outputs": [], + "source": [ + "import matplotlib.pyplot as plt\n", + "import numpy as np\n", + "import sympy as sym" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Geometric variables:\n", + "\n", + "- For simplifying the configuration of balls, we assume the coordinates of\n", + "
ball $A$ (shown in the above figure) and the altitude of the triangle \n", + " $AD$
are fixed throughout the test cases.\n", + "- The variables are angles $\\angle BAD$ ($\\theta _1$) and $\\angle CAD$ ($\\theta _2$).\n", + "- The height of the altitude be $h$ and the length from origin $O$ to point D be $k$.\n", + "- Then coordinate of ball $A$ will be $P_a(h - k, 0, 0.02)$\n", + "- Coordinates of ball $B$ will be $P_b(-k, h*tan\\theta _1, 0.02)$.\n", + "- Coordinates of ball $C$ will be $P_c(-k, -h*tan\\theta _2, 0.02)$.\n", + "- Further coordinates of center of mass (com) of each rod is denoted by $P_{ab}$, $P_{bc}$, $P_{ca}$.\n" + ] + }, + { + "cell_type": "code", + "execution_count": 47, + "metadata": {}, + "outputs": [], + "source": [ + "rho = 200\n", + "r_c = 0.005\n", + "r_s = 0.02\n", + "# total ten pair of angles theta_1 and theta_2\n", + "N = 10\n", + "\n", + "# volume of sphere\n", + "v_s = (4*np.pi*r_s**3)/3\n", + "m_s = rho*v_s\n", + "\n", + "#altittude height (m)\n", + "h = 0.15\n", + "k = 0.05\n", + "\n", + "theta_1 = np.linspace(np.pi/6, np.pi/2, N, endpoint=False)\n", + "theta_2 = np.linspace(np.pi/6, np.pi/3, N)\n", + "\n", + "# coordinates of ball A\n", + "p_a = np.repeat(np.array([[h - k , 0, 0.02]]), N, axis=0)\n", + "\n", + "# coordinates of ball B \n", + "p_b_x = np.ones((N,1)) * -k\n", + "p_b_y = h*np.tan(theta_1).reshape(N,1)\n", + "p_b_z = np.ones((N,1)) * 0.02\n", + "p_b = np.hstack((p_b_x, p_b_y, p_b_z))\n", + "\n", + "# coordinates of ball C\n", + "p_c_x = np.ones((N,1)) * -k\n", + "p_c_y = - h*np.tan(theta_2).reshape(N,1)\n", + "p_c_z = np.ones((N,1)) * 0.02\n", + "p_c = np.hstack((p_c_x, p_c_y, p_c_z))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "As the body is at rest the net force and moment about any point should be zeros. We choose to calculate the net moment about point $P_a$.\n", + "\n", + "- Force balance gives:\n", + " \n", + " $N_a = [0, 0, n_a]^T, \\text{ } N_b = [0, 0, n_b]^T \\text{ and } N_c = [0, 0, n_c]^T$ \n", + " \n", + " $g = [0, 0, -9.8]^T$ \n", + " \n", + " $F_{net}= ma$\n", + " \n", + " $a = 0$\n", + " \n", + " $N_a + N_b + N_c + g = 0$ -> $n_a + n_b + n_c = 9.8$ ---- $equation1$\n", + " \n", + " $\\tau _a = 0$\n", + " \n", + " $m_c*g \\times (P_{ab} - P_a)$ + $(m_s *g + N_b) \\times (P_b - P_a)$ +\n", + " $m_c *g \\times (P_{bc} - P_a)$ +\n", + "\n", + " $(m_s *g + N_c) \\times (P_c - P_a)$ + $m_c *g \\times (P_{ca} - P_a)$ = 0 ----- $equation2 \\text{ and } 3$\n", + " \n", + "So, we get a total of three linear equations to solve for $n_a$, $n_b$, and $n_c$." + ] + }, + { + "cell_type": "code", + "execution_count": 48, + "metadata": {}, + "outputs": [], + "source": [ + "def hat(v):\n", + " # hat operator for vector\n", + " v = v.ravel()\n", + " return np.array([[0, v[2], -v[1]],\n", + " [-v[2], 0, v[0]],\n", + " [v[1], -v[0], 0]])" + ] + }, + { + "cell_type": "code", + "execution_count": 52, + "metadata": {}, + "outputs": [], + "source": [ + "def compute_contact_forces(p_a, p_b, p_c):\n", + " # creating symbolic variables for normal forces\n", + " n_a = sym.symbols(\"n_a\")\n", + " n_b = sym.symbols(\"n_b\")\n", + " n_c = sym.symbols(\"n_c\")\n", + " \n", + " com = (p_a + p_b + p_c)/3\n", + " \n", + " # contact force at each contact point\n", + " N_a = np.array([0, 0, n_a]).reshape(3,1)\n", + " N_b = np.array([0, 0, n_b]).reshape(3,1)\n", + " N_c = np.array([0, 0, n_c]).reshape(3,1)\n", + "\n", + " # length of each rod\n", + " l_ab = np.linalg.norm(p_b - p_a)\n", + " l_bc = np.linalg.norm(p_c - p_b)\n", + " l_ca = np.linalg.norm(p_a - p_c)\n", + " \n", + " #mass of each rod\n", + " m_c1 = np.pi*(r_c**2)*l_ab*rho\n", + " m_c2 = np.pi*(r_c**2)*l_bc*rho\n", + " m_c3 = np.pi*(r_c**2)*l_ca*rho\n", + "\n", + " # com of rod AB\n", + " p_ab = (p_a + p_b)/2\n", + " \n", + " # com of rod BC\n", + " p_bc = (p_b + p_c)/2\n", + " \n", + " # com of rod CA\n", + " p_ca = (p_c + p_a)/2\n", + " g = np.array([0,0,-9.8]).reshape(3,1)\n", + "\n", + " # force balance \n", + " eq_f = N_a + N_b + N_c + (3*m_s + m_c1 + m_c2 + m_c3)*g\n", + "\n", + " # z direction force balance\n", + " eq1 = eq_f[2][0]\n", + " \n", + " # moment balance about A\n", + " eq_t = hat(p_ab - p_a) @ (m_c1 * g) + hat(p_b - p_a) @ (m_s * g + N_b) +\\\n", + " hat(p_bc - p_a) @ (m_c2 * g) + hat(p_c - p_a) @ (m_s *g + N_c) +\\\n", + " hat(p_ca - p_a) @ (m_c3 * g)\n", + " \n", + " eq2 = eq_t[0][0]\n", + " eq3 = eq_t[1][0]\n", + "\n", + " result = sym.linsolve([eq1, eq2, eq3], (n_a, n_b, n_c))\n", + "\n", + " return list(result.args)\n" + ] + }, + { + "cell_type": "code", + "execution_count": 57, + "metadata": {}, + "outputs": [], + "source": [ + "normal_forces = np.zeros((N,3))\n", + "for i in range(N):\n", + " normal_force = compute_contact_forces(p_a[i,:], p_b[i,:], p_c[i,:])\n", + " normal_forces[i, :] = normal_force[0]" + ] + }, + { + "cell_type": "code", + "execution_count": 64, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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3FHCm3+7lwqTg0MWD4eONo3XTMMZmsOnI0wGRLvNRLjCsLgi8bhicLh6UOXsRaUrGbcrriGIRFN5nOawWUxEhluJDLM0/DS5b7cSabMQZbcSEWYhKsxCRJi14dZCVJiVSLuF2CNOtYRZNYZDRESCnwLLMVitdj6w7WuSP0x4u0jAYhjEuU1EuayEucIxuaJxuby9InVGKvWmdMIsPYmyxhMVFuYNFdHegBFltxBhs3pvG8KEL1Q0DSP2hvs27+sKFyIi0l0psBxDTFQCU53puOvM9OrRj+ioDGKiBxDX4xQSo5OJttta9HJE2Cxa9EtERKSdKbAcg8lkYuGM/zbMPLlIM09EREQCROcYREREJOgpsIiIiEjQU2ARERGRoKfAIiIiIkFPgUVERESCngKLiIiIBD0FFhEREQl6CiwiIiIS9BRYREREJOgpsIiIiEjQU2ARERGRoKfAIiIiIkFPgUVERESCXpe4WrNhGABUVFS0+7GdTic1NTVUVFToas1BTm0VWtReoUNtFTpCra0av7cbv8ePpUsElsrKSgAyMjICXImIiIj4q7Kykri4uGNuYzLaEmuCnMfj4cCBA8TExGAymdr12BUVFWRkZLB//35iY2Pb9djSvtRWoUXtFTrUVqEj1NrKMAwqKytJS0vDbD72KJUu0cNiNpvp3bt3h75HbGxsSDS+qK1CjdordKitQkcotdXxelYaadCtiIiIBD0FFhEREQl6CizHYbfbmT9/Pna7PdClyHGorUKL2it0qK1CR1duqy4x6FZERES6NvWwiIiISNBTYBEREZGgp8AiIiIiQU+BRURERIKeAkuDvLw8rr/+ehITE4mIiGDEiBF8++23vtcNw2DevHmkpqYSERHB5MmT2blzZwAr7r7cbjdz586lX79+REREMGDAAO6///5m16JQewXGZ599xiWXXEJaWhomk4l33nmn2ettaZfS0lKuu+46YmNjiY+P56abbqKqqqoTP0X3cKy2cjqd3HnnnYwYMYKoqCjS0tK44YYbOHDgQLNjqK06z/H+tpq65ZZbMJlMLFq0qNnzod5eCizAoUOHmDhxIjabjffff58tW7bwhz/8gR49evi2eeSRR3jyySdZvHgxq1evJioqimnTplFXVxfAyrunhx9+mGeffZY//elPbN26lYcffphHHnmEp556yreN2iswqqurOfXUU3n66adbfb0t7XLdddexefNmli1bxrvvvstnn33Gz372s876CN3GsdqqpqaGtWvXMnfuXNauXctbb73F9u3bufTSS5ttp7bqPMf722r09ttvs2rVKtLS0lq8FvLtZYhx5513GmedddZRX/d4PEZKSorx6KOP+p4rKysz7Ha78corr3RGidLExRdfbPzkJz9p9twPfvAD47rrrjMMQ+0VLADj7bff9j1uS7ts2bLFAIxvvvnGt837779vmEwmIy8vr9Nq726ObKvWfP311wZg7N271zAMtVUgHa29cnNzjfT0dGPTpk1G3759jT/+8Y++17pCe6mHBfjPf/7D2LFjueqqq0hKSmL06NE899xzvtdzcnLIz89n8uTJvufi4uIYP348K1euDETJ3dqZZ57J8uXL2bFjBwDfffcdX3zxBdOnTwfUXsGqLe2ycuVK4uPjGTt2rG+byZMnYzabWb16dafXLIeVl5djMpmIj48H1FbBxuPx8OMf/5jf/va3DBs2rMXrXaG9usTFD09WdnY2zz77LLNnz+buu+/mm2++4bbbbiMsLIwZM2aQn58PQHJycrP9kpOTfa9J57nrrruoqKhg8ODBWCwW3G43Dz74INdddx2A2itItaVd8vPzSUpKava61WolISFBbRdAdXV13HnnnVx77bW+C+qprYLLww8/jNVq5bbbbmv19a7QXgoseJPp2LFjeeihhwAYPXo0mzZtYvHixcyYMSPA1cmRXn/9dV5++WX++c9/MmzYMNavX8/tt99OWlqa2kuknTmdTn74wx9iGAbPPvtsoMuRVqxZs4YnnniCtWvXYjKZAl1Oh9EpISA1NZWhQ4c2e27IkCHs27cPgJSUFAAKCgqabVNQUOB7TTrPb3/7W+666y6uueYaRowYwY9//GN+85vfsGDBAkDtFaza0i4pKSkUFhY2e93lclFaWqq2C4DGsLJ3716WLVvm610BtVUw+fzzzyksLKRPnz5YrVasVit79+7lf/7nf8jMzAS6RnspsAATJ05k+/btzZ7bsWMHffv2BaBfv36kpKSwfPly3+sVFRWsXr2aCRMmdGqt4p3BYDY3/6drsVjweDyA2itYtaVdJkyYQFlZGWvWrPFt8/HHH+PxeBg/fnyn19ydNYaVnTt38tFHH5GYmNjsdbVV8Pjxj3/Mhg0bWL9+ve8nLS2N3/72t3zwwQdAF2mvQI/6DQZff/21YbVajQcffNDYuXOn8fLLLxuRkZHGP/7xD982CxcuNOLj441///vfxoYNG4zLLrvM6Nevn1FbWxvAyrunGTNmGOnp6ca7775r5OTkGG+99ZbRs2dP44477vBto/YKjMrKSmPdunXGunXrDMB4/PHHjXXr1vlmlrSlXS688EJj9OjRxurVq40vvvjCyMrKMq699tpAfaQu61ht5XA4jEsvvdTo3bu3sX79euPgwYO+n/r6et8x1Fad53h/W0c6cpaQYYR+eymwNPjvf/9rDB8+3LDb7cbgwYONv/zlL81e93g8xty5c43k5GTDbrcbF1xwgbF9+/YAVdu9VVRUGL/+9a+NPn36GOHh4Ub//v2N3/3ud83+Q6r2CoxPPvnEAFr8zJgxwzCMtrVLSUmJce211xrR0dFGbGysMXPmTKOysjIAn6ZrO1Zb5eTktPoaYHzyySe+Y6itOs/x/raO1FpgCfX2MhlGk+VBRURERIKQxrCIiIhI0FNgERERkaCnwCIiIiJBT4FFREREgp4Ci4iIiAQ9BRYREREJegosIiIiEvQUWERERCToKbCIiIhI0FNgERERkaCnwCIiIiJBT4FFREREgt7/A0SG/0ChOM6LAAAAAElFTkSuQmCC", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "theta = np.rad2deg(theta_1 + theta_2)\n", + "plt.plot(theta, normal_forces, label=[\"n_a\", \"n_b\", \"n_c\"])\n", + "plt.legend()\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Solution for complex case scenario\n", + "\n", + " \n", + " \n", + "\n", + "\n", + "\n", + "**First image is friction cone model and second image is friction pyramid model.**\n", + "\n", + "##### **Energy conservation**\n", + "\n", + "- Kinetic energy of model: $T(t) = \\frac{1}{2} m \\dot c(t)^T \\dot c(t) + \\frac{1}{2} I \\omega(t)^T \\omega(t)$ \n", + "- Potential energy of model: $V(t) = -mg^Tc(t)$\n", + "- Total energy of model: $E(t) = T(t) + V(t)$\n", + "- Intial totaltotal energy of model: $E(t_0)$\n", + "- Total energy of model at time $t>0$ $E(t)$\n", + "- As friction force is dissipative force: $E(t_0) > E(t) => E(t_0) - E(t) > 0$\n", + "\n", + "##### **Friction is dissipative force**\n", + "\n", + "- Location of any point in $c$ frame: $r_c$.\n", + "- Slip velocity of any point on model in $O$ frame: $ \\dot c_p(t) = \\dot c(t) + \\omega(t) \\times r_c$.\n", + "- Unit vector along the direction of slip velocity: $ \\hat{\\dot{c_p}}(t) = \\frac {\\dot c_p(t)}{\\| \\dot c_p(t) \\|}$.\n", + "- For contact points $A, B$, and $C$ unit vector along the direction of their velocity: $ \\hat{\\dot{c_a}}, \\hat{\\dot{c_b}}$ and $\\hat{\\dot{c_c}}$.\n", + "- Contact forces at contact points in $O$ frame : $f$.\n", + "- Unit vector along the contact force in $O$ frame: $\\hat f$.\n", + "- As the velocity of ball is in $xy$ plane, the friction forces should opposite in direction to slip velocity: $f \\cdot \\dot c_p <=0$.\n", + "\n", + "##### **Magnitude of friction force**\n", + "- Unit normal at contact point: $\\hat n$\n", + "- Contact force along contact normal: $ (f \\cdot \\hat n) \\hat n$\n", + "- Unit vector along first friction direction in $c$ frame: $ fdir_1$\n", + "- Friction force along first friction direction expressed in $O$ frame: $R^T(q) (\\mu _1 \\| f \\cdot \\hat n \\| * fdir_1)$ \n", + "- Unit vector along second friction direction in $c$ frame: $ fdir_2$\n", + "- Friction force along second friction direction expressed in $O$ frame: $R^T(q) (\\mu _2 \\| f \\cdot \\hat n \\| * fdir_2)$ \n", + "\n", + "##### **Friction cone model (fcm) vs pyramid model (fpm) (ODE only)**\n", + "\n", + "- Difference in cog position in $O$ frame: $ \\| c_{fcm}(t) - c_{fpm}(t) \\|$\n", + "- Difference in cog velocity in $O$ frame: $ \\| \\dot c_{fcm}(t) - \\dot c_{fpm}(t) \\|$\n", + "- Difference in cog acceleration in $O$ frame: $ \\| \\ddot c_{fcm}(t) - \\ddot c_{fpm}(t) \\|$" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Inputs, Outputs, and Metrics\n", + "\n", + "### Inputs\n", + "This benchmark generates tests of different parameters based on these inputs:\n", + "\n", + "Parameter | Type | Description\n", + "---------------------------- | ------- | -----------\n", + "Physics engine | string | `ode`, `bullet`, `simbody`, or `dart`\n", + "Face angle | double | units in radians\n", + "Friction model | string | pyramid or cone (ode only)\n", + "Surface slope | Double | units of radians\n", + "Simple or Complex scenario | Boolean |\n", + "Centre of gravity height | Double | unit of meters expressed in link frame\n", + "Equal kinetic energies | Boolean | \n", + "\n", + "### Metrics\n", + "These errors are measured and saved:\n", + "\n", + "Metric | Type | Description\n", + "-----------------------| -------- | -----------\n", + "Contact force error | 3-vector | units of Newton(N)\n", + "Friction direction error | 3-vector |\n", + "Fricion magnitude error | 2-vector| units of Newton(N)\n", + "Linear velocity error | 3-vector | units of meters / second\n", + "position error | 3-vector | units of meters\n", + "Energy error | double | units of J\n", + "\n", + "### Additional outputs\n", + "In addition, computation time is measured, by saving these quantities as outputs:\n", + "\n", + "Metric | Type | Description\n", + "-----------------------| ------ | -----------\n", + "Duration in wall time | double | units of seconds\n", + "Duration in sim time | double | units of seconds\n", + "Duration ratio | double | wall duration divided by sim duration" + ] + } + ], + "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.10.12" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/triball_post_processing.py b/triball_post_processing.py new file mode 100644 index 0000000..64c8197 --- /dev/null +++ b/triball_post_processing.py @@ -0,0 +1,358 @@ +import sys +import os +import pandas as pd +import time +import numpy as np +from gz.math7 import Quaterniond, Vector3d +import matplotlib.pyplot as plt +import csv +import time +import sympy as sym + +SOURCE_FOLDER = os.path.dirname(os.path.abspath(__file__)) + +# BENCHMARK_NAME = sys.argv[1] +BENCHMARK_NAME = "BENCHMARK_triball_configuration" + +MODEL_NAME = ['30', '45', '60', '75', '90'] + +I_30 = [[8.4732487219449371e-05, -1.3552527156068805e-20, 2.5214795814616026e-21], + [-1.3552527156068805e-20, 0.00035705300836722431, 4.4766275773390029e-22], + [2.5214795814616026e-21, 4.4766275773390029e-22, 0.00043190422402162329]] + +I_45 = [[0.00019232606045470671, 1.3552527156068805e-20, 1.2627017167609311e-20], + [1.3552527156068805e-20, 0.00036422223881746503, 1.6650309163384415e-21], + [1.2627017167609311e-20, 1.6650309163384415e-21, 0.0005466328545714452]] + +I_60 = [[0.000311243867376448, 0, 0], + [0, 0.000311243867376448, 0], + [0, 0, 0.0006128367621210681]] + +I_75 = [[0.00066921849216050014, 2.7105054312137611e-20, -3.3685125287159029e-21], + [2.7105054312137611e-20, 0.00038309493110161302, 1.0621606046267175e-20], + [-3.3685125287159029e-21, 1.0621606046267175e-20, 0.0010423041088969216]] + +I_90 = [[0.0011706814995045239, 2.7105054312137611e-20, -3.3881317890172014e-21], + [2.7105054312137611e-20, 0.00039647954261617555, 2.3523493101256951e-20], + [-3.3881317890172014e-21, 2.3523493101256951e-20, 0.0015570834427368358]] + +class postProcessing: + + def __init__(self, test_name): + + self.m = {'30': 0.078742493606727915,'45': 0.081476344460819278, + '60': 0.060318578948924034, '75': 0.088985917618018107, + '90': 0.094448719111790758} + + self.I = {'30': np.array(I_30), '45': np.array(I_45), + '60': np.array(I_60), '75': np.array(I_75), + '90': np.array(I_90)} + + timestr = time.strftime("%Y%m%d-%H%M%S") + metrics_filename = test_name + "_" + timestr + ".csv" + self.metrics_path = os.path.join(SOURCE_FOLDER, "test_results", metrics_filename) + print(f"metrics path is {self.metrics_path}") + + self.csv_file = open(self.metrics_path, mode='w', newline='') + self.csv_writer = csv.writer(self.csv_file) + + metrics = ["energy0", "energyErr_maxabs", "contactForceErr_a_maxAbs", "contactForceErr_b_maxAbs", + "contactForceErr_c_maxAbs", "frictionForceMagErr_a_maxAbs", "frictionForceMagErr_b_maxAbs", + "frictionForceMagErr_c_maxAbs", "frictionForceDirErr_a_maxAbs", "frictionForceDirErr_b_maxAbs", + "frictionForceDirErr_c_maxAbs", "face_angle", "dt", "engine", "friction_coefficient", "friction_model", + "cog_h", "surface_slope", "isComplex", "modelCount", "simTime", "time", "timeRatio", "classname"] + self.csv_writer.writerow(metrics) + + def read_file(self,file_path: str): + benchmark_config = pd.read_csv(file_path, nrows=1).to_numpy() + states = pd.read_csv(file_path,skiprows=2).to_numpy() + return benchmark_config, states + + def get_file_names(self): + '''Method to obtain the file names and file paths of benchmark result''' + result_dir = os.path.join(SOURCE_FOLDER, "test_results", BENCHMARK_NAME, "CSV") + file_names = os.listdir(result_dir) + return result_dir, file_names + + def set_test_parameters(self,physic_engine, dt, friction_model, + complex, slope, friction_coefficient, + cog_height, equal_KE, wall_time): + self.physics_engine = physic_engine + self.dt = dt + self.fricition_model = friction_model + self.complex = complex + self.surface_slope = slope + self.mu = friction_coefficient + self.cog_height = cog_height + self.equal_ke = equal_KE + self.computation_time = wall_time + + if complex: + self.class_name = "static" + else: + self.class_name = "sliding" + + def hat(self, v): + # hat operator for vector + v = v.ravel() + return np.array([[0, v[2], -v[1]], + [-v[2], 0, v[0]], + [v[1], -v[0], 0]]) + + def compute_pos_mass(self, face_angle: str): + h = 0.15 + k = 0.05 + rho = 600 + r_c = 0.005 + r_s = 0.02 + + initial_com = {'30': 0, '45': 1, '60': 2, '75':3, '90':4} + angle = np.deg2rad(int(face_angle))/2 + + ## centre of gravity location of ball and rod + self.ball_pos = {'a': np.array([[h - k , initial_com[face_angle], 0.02]]), + 'b': np.array([[- k , h*np.tan(angle) + initial_com[face_angle], 0.02]]), + 'c': np.array([[- k , - h*np.tan(angle) + initial_com[face_angle], 0.02]])} + + v_s = (4*np.pi*r_s**3)/3 + self.m_s = rho*v_s + + self.rod_pos = {'ab': (self.ball_pos['a'] + self.ball_pos['b'])/2, + 'bc': (self.ball_pos['b'] + self.ball_pos['c'])/2, + 'ca': (self.ball_pos['c'] + self.ball_pos['a'])/2} + + self.l_ab = np.linalg.norm(self.ball_pos['b'] - self.ball_pos['a']) + self.l_bc = np.linalg.norm(self.ball_pos['c'] - self.ball_pos['b']) + self.l_ca = np.linalg.norm(self.ball_pos['a'] - self.ball_pos['c']) + + self.m_r1 = np.pi*(r_c**2)*self.l_ab*rho + self.m_r2 = np.pi*(r_c**2)*self.l_bc*rho + self.m_r3 = np.pi*(r_c**2)*self.l_ca*rho + + def compute_normal_force(self): + slope = self.surface_slope + + n_a = sym.symbols("n_a") + n_b = sym.symbols("n_b") + n_c = sym.symbols("n_c") + + F_a = np.array([0, 0, n_a]).reshape(3,1) + F_b = np.array([0, 0, n_b]).reshape(3,1) + F_c = np.array([0, 0, n_c]).reshape(3,1) + + g = np.array([-np.sin(slope)*9.8,0,-np.cos(slope)*9.8]).reshape(3,1) + + + eq_f = F_a + F_b + F_c + (3*self.m_s + self.m_r1 + self.m_r2 + self.m_r3)*g + + eq1 = eq_f[2][0] + + p_a = self.ball_pos['a'] + p_b = self.ball_pos['b'] + p_c = self.ball_pos['c'] + + p_ab = self.rod_pos['ab'] + p_bc = self.rod_pos['bc'] + p_ca = self.rod_pos['ca'] + + # moment balance about A + eq_t1 = self.hat(p_ab - p_a) @ (self.m_r1 * g) + self.hat(p_b - p_a) @ (self.m_s * g + F_b) +\ + self.hat(p_bc - p_a) @ (self.m_r2 * g) + self.hat(p_c - p_a) @ (self.m_s *g + F_c) +\ + self.hat(p_ca - p_a) @ (self.m_r3 * g) + + eq2 = eq_t1[0][0] + eq3 = eq_t1[1][0] + + result = sym.linsolve([eq1, eq2, eq3], (n_a, n_b, n_c)) + return list(result.args) + + def compute_slip_vel(self, com_vel: np.ndarray, + ang_vel: np.ndarray, r: np.ndarray): + return com_vel + self.hat(r) @ ang_vel + + def compute_normal_force_error(self, force1, force2, force3): + contact_forces = self.compute_normal_force() + contact_forces = np.array(contact_forces).reshape(3,1) + normal_force_error = np.zeros(3) + normal_force_error[0] = abs(contact_forces[0][0] - force1) + normal_force_error[1] = abs(contact_forces[1][0] - force2) + normal_force_error[2] = abs(contact_forces[2][0] - force3) + return normal_force_error + + def compute_friction_force_error(self, contact_info, + v, omega, pos): + normal = contact_info[4:7] + force = contact_info[7:10] + + ## contact force along normal (contact_force.normal) + force_n = np.dot(force, normal) + r_ac = contact_info[1:4] - pos + slip_vel = self.compute_slip_vel(v, omega, r_ac) + ## analytical solution + friction_force_a = self.mu * force_n * (slip_vel/np.linalg.norm(slip_vel)) + ## numerical solution + friciton_force_n = contact_info[7:9] + F_mag_error = np.linalg.norm(friciton_force_n[:2] - friction_force_a) + F_dir_error = np.dot(v, friciton_force_n) + + return F_mag_error, F_dir_error + + def calculate_mertics(self, states: np.ndarray, + face_angle: str): + sim_time = states[:, 0] + linear_accel = states[:, 2:5] + angular_accel = states[:, 5:8] + v = states[:, 8:11] + omega = states[:, 11:14] + pos = states[:, 14:17] + rot = states[:, 17:21] + contact1_info = states[:, 21:34] + contact2_info = states[:, 34:47] + contact3_info = states[:, 47:] + slope = self.surface_slope + + g = np.array([-np.sin(slope)*9.8,0,-np.cos(slope)*9.8]) + self.N = len(sim_time) + E = np.zeros(self.N) + self.F_mag_error = np.zeros((self.N,3)) + self.F_dir_error = np.zeros((self.N,3)) + self.normal_force_error = np.zeros((self.N, 3)) + + for i in range(self.N): + # angular velocity in body frame + omega_w = omega[i].tolist() + quat = rot[i].tolist() + quat = Quaterniond(quat[0], quat[1], quat[2], quat[3]) + omega_b = quat.rotate_vector_reverse(Vector3d(omega_w[0], + omega_w[1], omega_w[2])) + omega_b = np.array([omega_b[0], omega_b[1], omega_b[2]]) + + # translation energy + rotational energy + potential energy + tran_E = 0.5*self.m[face_angle]*v[i].dot(v[i]) + rot_E = 0.5*omega_b.dot(self.I[face_angle].dot(omega_b)) + V = - self.m[face_angle]*g.dot(pos[i]) + E[i] = tran_E + rot_E + V + + if self.complex: + F_mag_error, F_dir_error = self.compute_friction_force_error( + contact1_info[i], v[i], omega_b, + pos[i]) + self.F_mag_error[i, 0] = F_mag_error + self.F_dir_error[i, 0] = F_dir_error + + F_mag_error, F_dir_error = self.compute_friction_force_error( + contact2_info[i], v[i], omega_b, + pos[i]) + self.F_mag_error[i, 1] = F_mag_error + self.F_dir_error[i, 1] = F_dir_error + + F_mag_error, F_dir_error = self.compute_friction_force_error( + contact3_info[i], v[i], omega_b, + pos[i]) + self.F_mag_error[i, 2] = F_mag_error + self.F_dir_error[i, 2] = F_dir_error + else: + self.compute_pos_mass(face_angle) + normal_forces_error = self.compute_normal_force_error( + contact1_info[i, 9], contact2_info[i, 9], contact3_info[i, 9]) + + self.normal_force_error[i] = normal_forces_error + + self.initial_energy = E[0] + + self.E_error = E - self.initial_energy + self.sim_time = sim_time[-1] + + self.time_ratio = self.computation_time/self.sim_time + + + def get_maxabs_error(self): + self.E_error = self.E_error[self.E_error>0] + + if (len(self.E_error)!=0): + self.E_maxabs_error = np.max(self.E_error) + else: + self.E_maxabs_error = 0 + + self.F_maxabs_dir_error = [0, 0, 0] + self.F_maxabs_mag_error = [0, 0, 0] + self.N_maxabs_error = [0, 0, 0] + + + if self.complex: + self.F_dir_error = self.F_dir_error[self.F_dir_error>0] + self.F_maxabs_dir_error[0] = np.max(self.F_dir_error[:, 0]) + self.F_maxabs_dir_error[1] = np.max(self.F_dir_error[:, 1]) + self.F_maxabs_dir_error[2] = np.max(self.F_dir_error[:, 2]) + self.F_maxabs_mag_error[0] = np.max(self.F_mag_error[:, 0]) + self.F_maxabs_mag_error[1] = np.max(self.F_mag_error[:, 1]) + self.F_maxabs_mag_error[2] = np.max(self.F_mag_error[:, 2]) + else: + self.N_maxabs_error[0] = np.max(self.normal_force_error[:, 0]) + self.N_maxabs_error[1] = np.max(self.normal_force_error[:, 1]) + self.N_maxabs_error[2] = np.max(self.normal_force_error[:, 2]) + + def save_metrics(self, face_angle, model_count): + if complex: + class_name = "sliding" + else: + class_name = "static" + + self.csv_writer.writerow([self.initial_energy, self.E_maxabs_error, self.N_maxabs_error[0], + self.N_maxabs_error[1], self.N_maxabs_error[2], self.F_maxabs_mag_error[0], + self.F_maxabs_mag_error[1], self.F_maxabs_mag_error[2], self.F_maxabs_dir_error[0], + self.F_maxabs_dir_error[1], self.F_maxabs_dir_error[2], face_angle, self.dt, + self.physics_engine, self.mu, self.fricition_model, self.cog_height, self.surface_slope, + self.complex, model_count, self.sim_time, self.computation_time, self.time_ratio, + class_name]) + + +if __name__ == "__main__": + dir = BENCHMARK_NAME + print(f"BENCHMARK: {dir}") + + post_processing = postProcessing(dir) + result_dir , file_names = post_processing.get_file_names() + file_names = sorted(file_names, reverse=True) + + for file in file_names: + print(f"TEST: {file}") + file_path = os.path.join(result_dir,file) + config, states = post_processing.read_file(file_path) + physic_engine = config[0,0] + dt = config[0,1] + complex = bool(config[0,2]) + slope = config[0,3] + friction_coefficient = config[0,4] + friction_model = config[0,5] + cog_height = config[0,6] + wall_time = config[0, 7] + equal_KE = config[0, 8] + + if complex: + no_of_models = 19 + else: + no_of_models = 5 + + print(f" Physics engines: {physic_engine} \n Timestep: {dt} \n Complex: {complex} \n Number of models: {no_of_models}") + post_processing.set_test_parameters(physic_engine, dt, friction_model, complex, slope, friction_coefficient, + cog_height, equal_KE, wall_time) + + states_per_model = int(len(states[:,0])/no_of_models) + states = states.reshape(no_of_models, states_per_model,-1) + + for i in range(no_of_models): + print(f" => Model number: {i+1}") + model_states = states[i] + + if complex: + face_angle = '45' + else: + face_angle = MODEL_NAME[i] + + + post_processing.calculate_mertics(model_states, face_angle) + post_processing.get_maxabs_error() + post_processing.save_metrics(face_angle, no_of_models) + + post_processing.csv_file.close() \ No newline at end of file diff --git a/triball_sliding.cc b/triball_sliding.cc new file mode 100644 index 0000000..49774ee --- /dev/null +++ b/triball_sliding.cc @@ -0,0 +1,42 @@ +#include + +#include "triball.hh" +#include "gazebo/test/helper_physics_generator.hh" +#include + +using namespace gazebo; +using namespace benchmark; + + +const float friction_coefficient = 0.9; + +// cog height with respect to link frame +const double cog_h_max = 0.02; +const double cog_h_min = -0.02; +const double cog_h_step = 0.01; + +INSTANTIATE_TEST_CASE_P( + OdeTriballPyramidModel, TriballTest, + ::testing::Combine(::testing::Values("ode"), ::testing::Values("pyramid_model"), + ::testing::Values(true), ::testing::Values(0.0), + ::testing::Values(friction_coefficient), + ::testing::Range(cog_h_min, cog_h_max, cog_h_step), ::testing::Bool())); +INSTANTIATE_TEST_CASE_P( + OdeTriballConeModel, TriballTest, + ::testing::Combine(::testing::Values("ode"), ::testing::Values("cone_model"), + ::testing::Values(true), ::testing::Values(0.0), + ::testing::Values(friction_coefficient), + ::testing::Range(cog_h_min, cog_h_max, cog_h_step), ::testing::Bool())); + +// INSTANTIATE_TEST_CASE_P( +// BulletTriball, TriballTest, +// ::testing::Combine(::testing::Values("bullet"), ::testing::Values("pyramid"), +// ::testing::Values(false), ::testing::Range(slope_min, slope_max, slope_step), +// ::testing::Values(friction_coefficient), +// ::testing::Range(cog_h_min, cog_h_max, cog_h_step))); +///////////////////////////////////////////////// +int main(int argc, char **argv) +{ + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} \ No newline at end of file diff --git a/worlds/triball.world.erb b/worlds/triball.world.erb index 36aa45a..c7b087e 100644 --- a/worlds/triball.world.erb +++ b/worlds/triball.world.erb @@ -1,46 +1,1338 @@ + <% - # Triball benchmark example world - # SI units (length in meters) + # default values + unless defined?(frictionModel) + frictionModel = "pyramid" + end + + unless defined?(fixed_configuration) + fixed_configuration = 0 + end + + unless defined?(surfaceSlope) + surfaceSlope = 0 + end + + unless defined?(frictionCoefficient) + frictionCoefficient = 0.9 + end + require "matrix" v0 = [0, 15, 0] N = 16 w0max = 150.0 w0mags = w0max * Vector.elements((-N..N).to_a) / N.to_f + + gravity = [-9.8*Math::sin(surfaceSlope), 0, -9.8*Math::cos(surfaceSlope)] + %> - + + + <%= gravity.join(" ") %> + model://ground_plane + model://sun + +<% + if fixed_configuration == 0 +%> + + + + + 0 0 0.02 0 0 0 + + 600 + + + true + + + + 0.09999999999999999 0 0 0 0 0 + + + 0.02 + + + + + + <%= frictionCoefficient %> + <%= frictionCoefficient %> + 1 0 0 + + + + + + 0.09999999999999999 0 0 0 0 0 + + + 0.02 + + + + + + + + + 0.024999999999999998 0.0200961894323342 0.0 -1.5707963267948961 -1.3089969389957472 1.3089969389957468 + + + 0.005 + 0.15529142706151244 + + + + + + <%= frictionCoefficient %> + <%= frictionCoefficient %> + + + + + + 0.024999999999999998 0.0200961894323342 0.0 -1.5707963267948961 -1.3089969389957472 1.3089969389957468 + + + 0.005 + 0.15529142706151244 + + + + + + + + + 0.024999999999999998 -0.0200961894323342 0.0 1.5707963267948961 -1.3089969389957472 -1.3089969389957468 + + + 0.005 + 0.15529142706151244 + + + + + + <%= frictionCoefficient %> + <%= frictionCoefficient %> + + + + + + 0.024999999999999998 -0.0200961894323342 0.0 1.5707963267948961 -1.3089969389957472 -1.3089969389957468 + + + 0.005 + 0.15529142706151244 + + + + + + + + + -0.049999999999999996 0.0401923788646684 0 0 0 0 + + + 0.02 + + + + + + <%= frictionCoefficient %> + <%= frictionCoefficient %>/mu2> + 1 0 0 + + + + + + -0.049999999999999996 0.0401923788646684 0 0 0 0 + + + 0.02 + + + + + + + + + -0.049999999999999996 0.0 0.0 1.5707963267948963 -0.0 0.0 + + + 0.005 + 0.0803847577293368 + + + + + + <%= frictionCoefficient %> + <%= frictionCoefficient %> + + + + + + -0.049999999999999996 0.0 0.0 1.5707963267948963 -0.0 0.0 + + + 0.005 + 0.0803847577293368 + + + + + + + + + -0.049999999999999996 -0.0401923788646684 0 0 0 0 + + + 0.02 + + + + + + <%= frictionCoefficient %> + <%= frictionCoefficient %> + 1 0 0 + + + + + + -0.049999999999999996 -0.0401923788646684 0 0 0 0 + + + 0.02 + + + + + + + + + + + + + 0 0 0.02 0 0 0 + + 600 + + + true + + + + 0.09999999999999999 0 0 0 0 0 + + + 0.02 + + + + + + <%= frictionCoefficient %> + <%= frictionCoefficient %> + 1 0 0 + + + + + + 0.09999999999999999 0 0 0 0 0 + + + 0.02 + + + + + + + + + 0.024999999999999998 0.031066017177982127 0.0 -1.5707963267948961 -1.1780972450961724 1.1780972450961718 + + + 0.005 + 0.1623588300438591 + + + + + + <%= frictionCoefficient %> + <%= frictionCoefficient %> + + + + + + 0.024999999999999998 0.031066017177982127 0.0 -1.5707963267948961 -1.1780972450961724 1.1780972450961718 + + + 0.005 + 0.1623588300438591 + + + + + + + + + 0.024999999999999998 -0.031066017177982127 0.0 1.5707963267948961 -1.1780972450961724 -1.1780972450961718 + + + 0.005 + 0.1623588300438591 + + + + + + <%= frictionCoefficient %> + <%= frictionCoefficient %> + + + + + + 0.024999999999999998 -0.031066017177982127 0.0 1.5707963267948961 -1.1780972450961724 -1.1780972450961718 + + + 0.005 + 0.1623588300438591 + + + + + + + + + -0.049999999999999996 0.062132034355964254 0 0 0 0 + + + 0.02 + + + + + + <%= frictionCoefficient %> + <%= frictionCoefficient %> + 1 0 0 + + + + + + -0.049999999999999996 0.062132034355964254 0 0 0 0 + + + 0.02 + + + + + + + + + -0.049999999999999996 0.0 0.0 1.5707963267948963 -0.0 0.0 + + + 0.005 + 0.12426406871192851 + + + + + + <%= frictionCoefficient %> + <%= frictionCoefficient %> + + + + + + -0.049999999999999996 0.0 0.0 1.5707963267948963 -0.0 0.0 + + + 0.005 + 0.12426406871192851 + + + + + + + + + -0.049999999999999996 -0.062132034355964254 0 0 0 0 + + + 0.02 + + + + + + <%= frictionCoefficient %> + <%= frictionCoefficient %> + 1 0 0 + + + + + + -0.049999999999999996 -0.062132034355964254 0 0 0 0 + + + 0.02 + + + + + + + + + + + + + 0 0 0.02 0 0 0 + + 0.0 0.0 0 0 0 0 + 0.060318578948924034 + + 0.000311243867376448 + 0.000311243867376448 + 0.0006128367621210681 + 0.0 + 0.0 + 0.0 + + + + true + + + + 0.09999999999999999 0 0 0 0 0 + + + 0.02 + + + + + + <%= frictionCoefficient %> + <%= frictionCoefficient %> + 1 0 0 + + + + + + 0.09999999999999999 0 0 0 0 0 + + + 0.02 + + + + + + + + + 0.024999999999999998 0.04330127018922193 0.0 -1.5707962969925737 -1.0471975511965974 1.047197525387029 + + + 0.005 + 0.17320508075688773 + + + + + + <%= frictionCoefficient %> + <%= frictionCoefficient %> + + + + + + 0.024999999999999998 0.04330127018922193 0.0 -1.5707962969925737 -1.0471975511965974 1.047197525387029 + + + 0.005 + 0.17320508075688773 + + + + + + + + + 0.024999999999999998 -0.04330127018922193 0.0 1.5707962969925737 -1.0471975511965974 -1.047197525387029 + + + 0.005 + 0.17320508075688773 + + + + + + <%= frictionCoefficient %> + <%= frictionCoefficient %> + + + + + + 0.024999999999999998 -0.04330127018922193 0.0 1.5707962969925737 -1.0471975511965974 -1.047197525387029 + + + 0.005 + 0.17320508075688773 + + + + + + + + + -0.049999999999999996 0.08660254037844387 0 0 0 0 + + + 0.02 + + + + + + <%= frictionCoefficient %> + <%= frictionCoefficient %> + 1 0 0 + + + + + + -0.049999999999999996 0.08660254037844387 0 0 0 0 + + + 0.02 + + + + + + + + + -0.049999999999999996 0.0 0.0 1.5707963267948963 -0.0 0.0 + + + 0.005 + 0.17320508075688773 + + + + + + <%= frictionCoefficient %> + <%= frictionCoefficient %> + + + + + + -0.049999999999999996 0.0 0.0 1.5707963267948963 -0.0 0.0 + + + 0.005 + 0.17320508075688773 + + + + + + + + + -0.049999999999999996 -0.08660254037844387 0 0 0 0 + + + 0.02 + + + + + + <%= frictionCoefficient %> + <%= frictionCoefficient %> + 1 0 0 + + + + + + -0.049999999999999996 -0.08660254037844387 0 0 0 0 + + + 0.02 + + + + + + + + + + + + + 0 0 0.02 0 0 0 + + 600 + + + true + + + + 0.09999999999999999 0 0 0 0 0 + + + 0.02 + + + + + + <%= frictionCoefficient %> + <%= frictionCoefficient %> + 1 0 0 + + + + + + 0.09999999999999999 0 0 0 0 0 + + + 0.02 + + + + + + + + + 0.024999999999999998 0.057549524098422025 0.0 -1.5707963267948963 -0.9162978572970228 0.9162978572970227 + + + 0.005 + 0.18907086210153967 + + + + + + <%= frictionCoefficient %> + <%= frictionCoefficient %> + + + + + + 0.024999999999999998 0.057549524098422025 0.0 -1.5707963267948963 -0.9162978572970228 0.9162978572970227 + + + 0.005 + 0.18907086210153967 + + + + + + + + + 0.024999999999999998 -0.057549524098422025 0.0 1.5707963267948963 -0.9162978572970228 -0.9162978572970227 + + + 0.005 + 0.18907086210153967 + + + + + + <%= frictionCoefficient %> + <%= frictionCoefficient %> + + + + + + 0.024999999999999998 -0.057549524098422025 0.0 1.5707963267948963 -0.9162978572970228 -0.9162978572970227 + + + 0.005 + 0.18907086210153967 + + + + + + + + + -0.049999999999999996 0.11509904819684405 0 0 0 0 + + + 0.02 + + + + + + <%= frictionCoefficient %> + <%= frictionCoefficient %> + 1 0 0 + + + + + + -0.049999999999999996 0.11509904819684405 0 0 0 0 + + + 0.02 + + + + + + + + + -0.049999999999999996 0.0 0.0 1.5707963267948963 -0.0 0.0 + + + 0.005 + 0.2301980963936881 + + + + + + <%= frictionCoefficient %> + <%= frictionCoefficient %> + + + + + + -0.049999999999999996 0.0 0.0 1.5707963267948963 -0.0 0.0 + + + 0.005 + 0.2301980963936881 + + + + + + + + + -0.049999999999999996 -0.11509904819684405 0 0 0 0 + + + 0.02 + + + + + + <%= frictionCoefficient %> + <%= frictionCoefficient %> + 1 0 0 + + + + + + -0.049999999999999996 -0.11509904819684405 0 0 0 0 + + + 0.02 + + + + + + + + + + + + + 0 0 0.02 0 0 0 + + 600 + + + true + + + + 0.09999999999999999 0 0 0 0 0 + + + 0.02 + + + + + + <%= frictionCoefficient %> + <%= frictionCoefficient %> + 1 0 0 + + + + + + 0.09999999999999999 0 0 0 0 0 + + + 0.02 + + + + + + + + + 0.024999999999999998 0.07499999999999998 0.0 -1.5707963267948963 -0.7853981633974484 0.7853981633974483 + + + 0.005 + 0.21213203435596423 + + + + + + <%= frictionCoefficient %> + <%= frictionCoefficient %> + + + + + + 0.024999999999999998 0.07499999999999998 0.0 -1.5707963267948963 -0.7853981633974484 0.7853981633974483 + + + 0.005 + 0.21213203435596423 + + + + + + + + + 0.024999999999999998 -0.07499999999999998 0.0 1.5707963267948963 -0.7853981633974484 -0.7853981633974483 + + + 0.005 + 0.21213203435596423 + + + + + + <%= frictionCoefficient %> + <%= frictionCoefficient %> + + + + + + 0.024999999999999998 -0.07499999999999998 0.0 1.5707963267948963 -0.7853981633974484 -0.7853981633974483 + + + 0.005 + 0.21213203435596423 + + + + + + + + + -0.049999999999999996 0.14999999999999997 0 0 0 0 + + + 0.02 + + + + + + <%= frictionCoefficient %> + <%= frictionCoefficient %> + 1 0 0 + + + + + + -0.049999999999999996 0.14999999999999997 0 0 0 0 + + + 0.02 + + + + + + + + + -0.049999999999999996 0.0 0.0 1.5707963267948963 -0.0 0.0 + + + 0.005 + 0.29999999999999993 + + + + + + <%= frictionCoefficient %> + <%= frictionCoefficient %> + + + + + + -0.049999999999999996 0.0 0.0 1.5707963267948963 -0.0 0.0 + + + 0.005 + 0.29999999999999993 + + + + + + + + + -0.049999999999999996 -0.14999999999999997 0 0 0 0 + + + 0.02 + + + + + + <%= frictionCoefficient %> + <%= frictionCoefficient %> + 1 0 0 + + + + + + -0.049999999999999996 -0.14999999999999997 0 0 0 0 + + + 0.02 + + + + + + + + + + <% - w0mags.to_a.each_index do |i| - name = "triball_" + i.to_s - w0 = [0, 0, w0mags[i]] - x0 = 0.3 * i + else + w0mags.to_a.each_index do |i| + name = "triball_" + i.to_s + w0 = [0, 0, w0mags[i]] + x0 = 0.3 * i %> + - - model://triball - <%= x0 %> 0 0 0 0 0 - - - <%= v0.join(" ") %> - <%= w0.join(" ") %> + + 0 0 0.02 0 0 0 + + 0.0 0.0 0 0 0 0 + 0.060318578948924034 + + 0.000311243867376448 + 0.000311243867376448 + 0.0006128367621210681 + 0.0 + 0.0 + 0.0 + + + + true + + + + 0.09999999999999999 0 0 0 0 0 + + + 0.02 + + + + + + <%= frictionCoefficient %> + <%= frictionCoefficient %> + 1 0 0 + + + + + + 0.09999999999999999 0 0 0 0 0 + + + 0.02 + + + + + + + + + 0.024999999999999998 0.04330127018922193 0.0 -1.5707962969925737 -1.0471975511965974 1.047197525387029 + + + 0.005 + 0.17320508075688773 + + + + + + <%= frictionCoefficient %> + <%= frictionCoefficient %> + + + + + + 0.024999999999999998 0.04330127018922193 0.0 -1.5707962969925737 -1.0471975511965974 1.047197525387029 + + + 0.005 + 0.17320508075688773 + + + + + + + + + 0.024999999999999998 -0.04330127018922193 0.0 1.5707962969925737 -1.0471975511965974 -1.047197525387029 + + + 0.005 + 0.17320508075688773 + + + + + + <%= frictionCoefficient %> + <%= frictionCoefficient %> + + + + + + 0.024999999999999998 -0.04330127018922193 0.0 1.5707962969925737 -1.0471975511965974 -1.047197525387029 + + + 0.005 + 0.17320508075688773 + + + + + + + + + -0.049999999999999996 0.08660254037844387 0 0 0 0 + + + 0.02 + + + + + + <%= frictionCoefficient %> + <%= frictionCoefficient %> + 1 0 0 + + + + + + -0.049999999999999996 0.08660254037844387 0 0 0 0 + + + 0.02 + + + + + + + + + -0.049999999999999996 0.0 0.0 1.5707963267948963 -0.0 0.0 + + + 0.005 + 0.17320508075688773 + + + + + + <%= frictionCoefficient %> + <%= frictionCoefficient %> + + + + + + -0.049999999999999996 0.0 0.0 1.5707963267948963 -0.0 0.0 + + + 0.005 + 0.17320508075688773 + + + + + + + + + -0.049999999999999996 -0.08660254037844387 0 0 0 0 + + + 0.02 + + + + + + <%= frictionCoefficient %> + <%= frictionCoefficient %> + 1 0 0 + + + + + + -0.049999999999999996 -0.08660254037844387 0 0 0 0 + + + 0.02 + + + + + + + + + + <%= v0.join(" ") %> + <%= w0.join(" ") %> -<% + +<% + end end %> - - - 8.5 5.5 0.3 0 0 3.14159 - orbit - - + + + 1.5 -4 2.5 0 0.5 1.6 + orbit + + - + \ No newline at end of file diff --git a/worlds/triball_contact.world b/worlds/triball_contact.world new file mode 100644 index 0000000..12d40f8 --- /dev/null +++ b/worlds/triball_contact.world @@ -0,0 +1,7427 @@ + + + + + + + + -0.0 0 -9.8 + + + model://ground_plane + + + + model://sun + + + + + + cone_model + + + + + + + + 0.0 0 0 0 0 0 + + 0 0 0.02 0 0 0 + + 0.0 0.0 0 0 0 0 + 0.060318578948924034 + + 0.000311243867376448 + 0.000311243867376448 + 0.0006128367621210681 + 0.0 + 0.0 + 0.0 + + + + true + + + + 0.09999999999999999 0 0 0 0 0 + + + 0.02 + + + + + + 0.9 + 0.9 + 1 0 0 + + + + + + 0.09999999999999999 0 0 0 0 0 + + + 0.02 + + + + + + + + + 0.024999999999999998 0.04330127018922193 0.0 -1.5707962969925737 -1.0471975511965974 1.047197525387029 + + + 0.005 + 0.17320508075688773 + + + + + + 0.9 + 0.9 + + + + + + 0.024999999999999998 0.04330127018922193 0.0 -1.5707962969925737 -1.0471975511965974 1.047197525387029 + + + 0.005 + 0.17320508075688773 + + + + + + + + + 0.024999999999999998 -0.04330127018922193 0.0 1.5707962969925737 -1.0471975511965974 -1.047197525387029 + + + 0.005 + 0.17320508075688773 + + + + + + 0.9 + 0.9 + + + + + + 0.024999999999999998 -0.04330127018922193 0.0 1.5707962969925737 -1.0471975511965974 -1.047197525387029 + + + 0.005 + 0.17320508075688773 + + + + + + + + + -0.049999999999999996 0.08660254037844387 0 0 0 0 + + + 0.02 + + + + + + 0.9 + 0.9 + 1 0 0 + + + + + + -0.049999999999999996 0.08660254037844387 0 0 0 0 + + + 0.02 + + + + + + + + + -0.049999999999999996 0.0 0.0 1.5707963267948963 -0.0 0.0 + + + 0.005 + 0.17320508075688773 + + + + + + 0.9 + 0.9 + + + + + + -0.049999999999999996 0.0 0.0 1.5707963267948963 -0.0 0.0 + + + 0.005 + 0.17320508075688773 + + + + + + + + + -0.049999999999999996 -0.08660254037844387 0 0 0 0 + + + 0.02 + + + + + + 0.9 + 0.9 + 1 0 0 + + + + + + -0.049999999999999996 -0.08660254037844387 0 0 0 0 + + + 0.02 + + + + + + + + + + 0 15 0 + 0 0 -150.0 + + + + + + + 0.3 0 0 0 0 0 + + 0 0 0.02 0 0 0 + + 0.0 0.0 0 0 0 0 + 0.060318578948924034 + + 0.000311243867376448 + 0.000311243867376448 + 0.0006128367621210681 + 0.0 + 0.0 + 0.0 + + + + true + + + + 0.09999999999999999 0 0 0 0 0 + + + 0.02 + + + + + + 0.9 + 0.9 + 1 0 0 + + + + + + 0.09999999999999999 0 0 0 0 0 + + + 0.02 + + + + + + + + + 0.024999999999999998 0.04330127018922193 0.0 -1.5707962969925737 -1.0471975511965974 1.047197525387029 + + + 0.005 + 0.17320508075688773 + + + + + + 0.9 + 0.9 + + + + + + 0.024999999999999998 0.04330127018922193 0.0 -1.5707962969925737 -1.0471975511965974 1.047197525387029 + + + 0.005 + 0.17320508075688773 + + + + + + + + + 0.024999999999999998 -0.04330127018922193 0.0 1.5707962969925737 -1.0471975511965974 -1.047197525387029 + + + 0.005 + 0.17320508075688773 + + + + + + 0.9 + 0.9 + + + + + + 0.024999999999999998 -0.04330127018922193 0.0 1.5707962969925737 -1.0471975511965974 -1.047197525387029 + + + 0.005 + 0.17320508075688773 + + + + + + + + + -0.049999999999999996 0.08660254037844387 0 0 0 0 + + + 0.02 + + + + + + 0.9 + 0.9 + 1 0 0 + + + + + + -0.049999999999999996 0.08660254037844387 0 0 0 0 + + + 0.02 + + + + + + + + + -0.049999999999999996 0.0 0.0 1.5707963267948963 -0.0 0.0 + + + 0.005 + 0.17320508075688773 + + + + + + 0.9 + 0.9 + + + + + + -0.049999999999999996 0.0 0.0 1.5707963267948963 -0.0 0.0 + + + 0.005 + 0.17320508075688773 + + + + + + + + + -0.049999999999999996 -0.08660254037844387 0 0 0 0 + + + 0.02 + + + + + + 0.9 + 0.9 + 1 0 0 + + + + + + -0.049999999999999996 -0.08660254037844387 0 0 0 0 + + + 0.02 + + + + + + + + + + 0 15 0 + 0 0 -140.625 + + + + + + + 0.6 0 0 0 0 0 + + 0 0 0.02 0 0 0 + + 0.0 0.0 0 0 0 0 + 0.060318578948924034 + + 0.000311243867376448 + 0.000311243867376448 + 0.0006128367621210681 + 0.0 + 0.0 + 0.0 + + + + true + + + + 0.09999999999999999 0 0 0 0 0 + + + 0.02 + + + + + + 0.9 + 0.9 + 1 0 0 + + + + + + 0.09999999999999999 0 0 0 0 0 + + + 0.02 + + + + + + + + + 0.024999999999999998 0.04330127018922193 0.0 -1.5707962969925737 -1.0471975511965974 1.047197525387029 + + + 0.005 + 0.17320508075688773 + + + + + + 0.9 + 0.9 + + + + + + 0.024999999999999998 0.04330127018922193 0.0 -1.5707962969925737 -1.0471975511965974 1.047197525387029 + + + 0.005 + 0.17320508075688773 + + + + + + + + + 0.024999999999999998 -0.04330127018922193 0.0 1.5707962969925737 -1.0471975511965974 -1.047197525387029 + + + 0.005 + 0.17320508075688773 + + + + + + 0.9 + 0.9 + + + + + + 0.024999999999999998 -0.04330127018922193 0.0 1.5707962969925737 -1.0471975511965974 -1.047197525387029 + + + 0.005 + 0.17320508075688773 + + + + + + + + + -0.049999999999999996 0.08660254037844387 0 0 0 0 + + + 0.02 + + + + + + 0.9 + 0.9 + 1 0 0 + + + + + + -0.049999999999999996 0.08660254037844387 0 0 0 0 + + + 0.02 + + + + + + + + + -0.049999999999999996 0.0 0.0 1.5707963267948963 -0.0 0.0 + + + 0.005 + 0.17320508075688773 + + + + + + 0.9 + 0.9 + + + + + + -0.049999999999999996 0.0 0.0 1.5707963267948963 -0.0 0.0 + + + 0.005 + 0.17320508075688773 + + + + + + + + + -0.049999999999999996 -0.08660254037844387 0 0 0 0 + + + 0.02 + + + + + + 0.9 + 0.9 + 1 0 0 + + + + + + -0.049999999999999996 -0.08660254037844387 0 0 0 0 + + + 0.02 + + + + + + + + + + 0 15 0 + 0 0 -131.25 + + + + + + + 0.8999999999999999 0 0 0 0 0 + + 0 0 0.02 0 0 0 + + 0.0 0.0 0 0 0 0 + 0.060318578948924034 + + 0.000311243867376448 + 0.000311243867376448 + 0.0006128367621210681 + 0.0 + 0.0 + 0.0 + + + + true + + + + 0.09999999999999999 0 0 0 0 0 + + + 0.02 + + + + + + 0.9 + 0.9 + 1 0 0 + + + + + + 0.09999999999999999 0 0 0 0 0 + + + 0.02 + + + + + + + + + 0.024999999999999998 0.04330127018922193 0.0 -1.5707962969925737 -1.0471975511965974 1.047197525387029 + + + 0.005 + 0.17320508075688773 + + + + + + 0.9 + 0.9 + + + + + + 0.024999999999999998 0.04330127018922193 0.0 -1.5707962969925737 -1.0471975511965974 1.047197525387029 + + + 0.005 + 0.17320508075688773 + + + + + + + + + 0.024999999999999998 -0.04330127018922193 0.0 1.5707962969925737 -1.0471975511965974 -1.047197525387029 + + + 0.005 + 0.17320508075688773 + + + + + + 0.9 + 0.9 + + + + + + 0.024999999999999998 -0.04330127018922193 0.0 1.5707962969925737 -1.0471975511965974 -1.047197525387029 + + + 0.005 + 0.17320508075688773 + + + + + + + + + -0.049999999999999996 0.08660254037844387 0 0 0 0 + + + 0.02 + + + + + + 0.9 + 0.9 + 1 0 0 + + + + + + -0.049999999999999996 0.08660254037844387 0 0 0 0 + + + 0.02 + + + + + + + + + -0.049999999999999996 0.0 0.0 1.5707963267948963 -0.0 0.0 + + + 0.005 + 0.17320508075688773 + + + + + + 0.9 + 0.9 + + + + + + -0.049999999999999996 0.0 0.0 1.5707963267948963 -0.0 0.0 + + + 0.005 + 0.17320508075688773 + + + + + + + + + -0.049999999999999996 -0.08660254037844387 0 0 0 0 + + + 0.02 + + + + + + 0.9 + 0.9 + 1 0 0 + + + + + + -0.049999999999999996 -0.08660254037844387 0 0 0 0 + + + 0.02 + + + + + + + + + + 0 15 0 + 0 0 -121.875 + + + + + + + 1.2 0 0 0 0 0 + + 0 0 0.02 0 0 0 + + 0.0 0.0 0 0 0 0 + 0.060318578948924034 + + 0.000311243867376448 + 0.000311243867376448 + 0.0006128367621210681 + 0.0 + 0.0 + 0.0 + + + + true + + + + 0.09999999999999999 0 0 0 0 0 + + + 0.02 + + + + + + 0.9 + 0.9 + 1 0 0 + + + + + + 0.09999999999999999 0 0 0 0 0 + + + 0.02 + + + + + + + + + 0.024999999999999998 0.04330127018922193 0.0 -1.5707962969925737 -1.0471975511965974 1.047197525387029 + + + 0.005 + 0.17320508075688773 + + + + + + 0.9 + 0.9 + + + + + + 0.024999999999999998 0.04330127018922193 0.0 -1.5707962969925737 -1.0471975511965974 1.047197525387029 + + + 0.005 + 0.17320508075688773 + + + + + + + + + 0.024999999999999998 -0.04330127018922193 0.0 1.5707962969925737 -1.0471975511965974 -1.047197525387029 + + + 0.005 + 0.17320508075688773 + + + + + + 0.9 + 0.9 + + + + + + 0.024999999999999998 -0.04330127018922193 0.0 1.5707962969925737 -1.0471975511965974 -1.047197525387029 + + + 0.005 + 0.17320508075688773 + + + + + + + + + -0.049999999999999996 0.08660254037844387 0 0 0 0 + + + 0.02 + + + + + + 0.9 + 0.9 + 1 0 0 + + + + + + -0.049999999999999996 0.08660254037844387 0 0 0 0 + + + 0.02 + + + + + + + + + -0.049999999999999996 0.0 0.0 1.5707963267948963 -0.0 0.0 + + + 0.005 + 0.17320508075688773 + + + + + + 0.9 + 0.9 + + + + + + -0.049999999999999996 0.0 0.0 1.5707963267948963 -0.0 0.0 + + + 0.005 + 0.17320508075688773 + + + + + + + + + -0.049999999999999996 -0.08660254037844387 0 0 0 0 + + + 0.02 + + + + + + 0.9 + 0.9 + 1 0 0 + + + + + + -0.049999999999999996 -0.08660254037844387 0 0 0 0 + + + 0.02 + + + + + + + + + + 0 15 0 + 0 0 -112.5 + + + + + + + 1.5 0 0 0 0 0 + + 0 0 0.02 0 0 0 + + 0.0 0.0 0 0 0 0 + 0.060318578948924034 + + 0.000311243867376448 + 0.000311243867376448 + 0.0006128367621210681 + 0.0 + 0.0 + 0.0 + + + + true + + + + 0.09999999999999999 0 0 0 0 0 + + + 0.02 + + + + + + 0.9 + 0.9 + 1 0 0 + + + + + + 0.09999999999999999 0 0 0 0 0 + + + 0.02 + + + + + + + + + 0.024999999999999998 0.04330127018922193 0.0 -1.5707962969925737 -1.0471975511965974 1.047197525387029 + + + 0.005 + 0.17320508075688773 + + + + + + 0.9 + 0.9 + + + + + + 0.024999999999999998 0.04330127018922193 0.0 -1.5707962969925737 -1.0471975511965974 1.047197525387029 + + + 0.005 + 0.17320508075688773 + + + + + + + + + 0.024999999999999998 -0.04330127018922193 0.0 1.5707962969925737 -1.0471975511965974 -1.047197525387029 + + + 0.005 + 0.17320508075688773 + + + + + + 0.9 + 0.9 + + + + + + 0.024999999999999998 -0.04330127018922193 0.0 1.5707962969925737 -1.0471975511965974 -1.047197525387029 + + + 0.005 + 0.17320508075688773 + + + + + + + + + -0.049999999999999996 0.08660254037844387 0 0 0 0 + + + 0.02 + + + + + + 0.9 + 0.9 + 1 0 0 + + + + + + -0.049999999999999996 0.08660254037844387 0 0 0 0 + + + 0.02 + + + + + + + + + -0.049999999999999996 0.0 0.0 1.5707963267948963 -0.0 0.0 + + + 0.005 + 0.17320508075688773 + + + + + + 0.9 + 0.9 + + + + + + -0.049999999999999996 0.0 0.0 1.5707963267948963 -0.0 0.0 + + + 0.005 + 0.17320508075688773 + + + + + + + + + -0.049999999999999996 -0.08660254037844387 0 0 0 0 + + + 0.02 + + + + + + 0.9 + 0.9 + 1 0 0 + + + + + + -0.049999999999999996 -0.08660254037844387 0 0 0 0 + + + 0.02 + + + + + + + + + + 0 15 0 + 0 0 -103.125 + + + + + + + 1.7999999999999998 0 0 0 0 0 + + 0 0 0.02 0 0 0 + + 0.0 0.0 0 0 0 0 + 0.060318578948924034 + + 0.000311243867376448 + 0.000311243867376448 + 0.0006128367621210681 + 0.0 + 0.0 + 0.0 + + + + true + + + + 0.09999999999999999 0 0 0 0 0 + + + 0.02 + + + + + + 0.9 + 0.9 + 1 0 0 + + + + + + 0.09999999999999999 0 0 0 0 0 + + + 0.02 + + + + + + + + + 0.024999999999999998 0.04330127018922193 0.0 -1.5707962969925737 -1.0471975511965974 1.047197525387029 + + + 0.005 + 0.17320508075688773 + + + + + + 0.9 + 0.9 + + + + + + 0.024999999999999998 0.04330127018922193 0.0 -1.5707962969925737 -1.0471975511965974 1.047197525387029 + + + 0.005 + 0.17320508075688773 + + + + + + + + + 0.024999999999999998 -0.04330127018922193 0.0 1.5707962969925737 -1.0471975511965974 -1.047197525387029 + + + 0.005 + 0.17320508075688773 + + + + + + 0.9 + 0.9 + + + + + + 0.024999999999999998 -0.04330127018922193 0.0 1.5707962969925737 -1.0471975511965974 -1.047197525387029 + + + 0.005 + 0.17320508075688773 + + + + + + + + + -0.049999999999999996 0.08660254037844387 0 0 0 0 + + + 0.02 + + + + + + 0.9 + 0.9 + 1 0 0 + + + + + + -0.049999999999999996 0.08660254037844387 0 0 0 0 + + + 0.02 + + + + + + + + + -0.049999999999999996 0.0 0.0 1.5707963267948963 -0.0 0.0 + + + 0.005 + 0.17320508075688773 + + + + + + 0.9 + 0.9 + + + + + + -0.049999999999999996 0.0 0.0 1.5707963267948963 -0.0 0.0 + + + 0.005 + 0.17320508075688773 + + + + + + + + + -0.049999999999999996 -0.08660254037844387 0 0 0 0 + + + 0.02 + + + + + + 0.9 + 0.9 + 1 0 0 + + + + + + -0.049999999999999996 -0.08660254037844387 0 0 0 0 + + + 0.02 + + + + + + + + + + 0 15 0 + 0 0 -93.75 + + + + + + + 2.1 0 0 0 0 0 + + 0 0 0.02 0 0 0 + + 0.0 0.0 0 0 0 0 + 0.060318578948924034 + + 0.000311243867376448 + 0.000311243867376448 + 0.0006128367621210681 + 0.0 + 0.0 + 0.0 + + + + true + + + + 0.09999999999999999 0 0 0 0 0 + + + 0.02 + + + + + + 0.9 + 0.9 + 1 0 0 + + + + + + 0.09999999999999999 0 0 0 0 0 + + + 0.02 + + + + + + + + + 0.024999999999999998 0.04330127018922193 0.0 -1.5707962969925737 -1.0471975511965974 1.047197525387029 + + + 0.005 + 0.17320508075688773 + + + + + + 0.9 + 0.9 + + + + + + 0.024999999999999998 0.04330127018922193 0.0 -1.5707962969925737 -1.0471975511965974 1.047197525387029 + + + 0.005 + 0.17320508075688773 + + + + + + + + + 0.024999999999999998 -0.04330127018922193 0.0 1.5707962969925737 -1.0471975511965974 -1.047197525387029 + + + 0.005 + 0.17320508075688773 + + + + + + 0.9 + 0.9 + + + + + + 0.024999999999999998 -0.04330127018922193 0.0 1.5707962969925737 -1.0471975511965974 -1.047197525387029 + + + 0.005 + 0.17320508075688773 + + + + + + + + + -0.049999999999999996 0.08660254037844387 0 0 0 0 + + + 0.02 + + + + + + 0.9 + 0.9 + 1 0 0 + + + + + + -0.049999999999999996 0.08660254037844387 0 0 0 0 + + + 0.02 + + + + + + + + + -0.049999999999999996 0.0 0.0 1.5707963267948963 -0.0 0.0 + + + 0.005 + 0.17320508075688773 + + + + + + 0.9 + 0.9 + + + + + + -0.049999999999999996 0.0 0.0 1.5707963267948963 -0.0 0.0 + + + 0.005 + 0.17320508075688773 + + + + + + + + + -0.049999999999999996 -0.08660254037844387 0 0 0 0 + + + 0.02 + + + + + + 0.9 + 0.9 + 1 0 0 + + + + + + -0.049999999999999996 -0.08660254037844387 0 0 0 0 + + + 0.02 + + + + + + + + + + 0 15 0 + 0 0 -84.375 + + + + + + + 2.4 0 0 0 0 0 + + 0 0 0.02 0 0 0 + + 0.0 0.0 0 0 0 0 + 0.060318578948924034 + + 0.000311243867376448 + 0.000311243867376448 + 0.0006128367621210681 + 0.0 + 0.0 + 0.0 + + + + true + + + + 0.09999999999999999 0 0 0 0 0 + + + 0.02 + + + + + + 0.9 + 0.9 + 1 0 0 + + + + + + 0.09999999999999999 0 0 0 0 0 + + + 0.02 + + + + + + + + + 0.024999999999999998 0.04330127018922193 0.0 -1.5707962969925737 -1.0471975511965974 1.047197525387029 + + + 0.005 + 0.17320508075688773 + + + + + + 0.9 + 0.9 + + + + + + 0.024999999999999998 0.04330127018922193 0.0 -1.5707962969925737 -1.0471975511965974 1.047197525387029 + + + 0.005 + 0.17320508075688773 + + + + + + + + + 0.024999999999999998 -0.04330127018922193 0.0 1.5707962969925737 -1.0471975511965974 -1.047197525387029 + + + 0.005 + 0.17320508075688773 + + + + + + 0.9 + 0.9 + + + + + + 0.024999999999999998 -0.04330127018922193 0.0 1.5707962969925737 -1.0471975511965974 -1.047197525387029 + + + 0.005 + 0.17320508075688773 + + + + + + + + + -0.049999999999999996 0.08660254037844387 0 0 0 0 + + + 0.02 + + + + + + 0.9 + 0.9 + 1 0 0 + + + + + + -0.049999999999999996 0.08660254037844387 0 0 0 0 + + + 0.02 + + + + + + + + + -0.049999999999999996 0.0 0.0 1.5707963267948963 -0.0 0.0 + + + 0.005 + 0.17320508075688773 + + + + + + 0.9 + 0.9 + + + + + + -0.049999999999999996 0.0 0.0 1.5707963267948963 -0.0 0.0 + + + 0.005 + 0.17320508075688773 + + + + + + + + + -0.049999999999999996 -0.08660254037844387 0 0 0 0 + + + 0.02 + + + + + + 0.9 + 0.9 + 1 0 0 + + + + + + -0.049999999999999996 -0.08660254037844387 0 0 0 0 + + + 0.02 + + + + + + + + + + 0 15 0 + 0 0 -75.0 + + + + + + + 2.6999999999999997 0 0 0 0 0 + + 0 0 0.02 0 0 0 + + 0.0 0.0 0 0 0 0 + 0.060318578948924034 + + 0.000311243867376448 + 0.000311243867376448 + 0.0006128367621210681 + 0.0 + 0.0 + 0.0 + + + + true + + + + 0.09999999999999999 0 0 0 0 0 + + + 0.02 + + + + + + 0.9 + 0.9 + 1 0 0 + + + + + + 0.09999999999999999 0 0 0 0 0 + + + 0.02 + + + + + + + + + 0.024999999999999998 0.04330127018922193 0.0 -1.5707962969925737 -1.0471975511965974 1.047197525387029 + + + 0.005 + 0.17320508075688773 + + + + + + 0.9 + 0.9 + + + + + + 0.024999999999999998 0.04330127018922193 0.0 -1.5707962969925737 -1.0471975511965974 1.047197525387029 + + + 0.005 + 0.17320508075688773 + + + + + + + + + 0.024999999999999998 -0.04330127018922193 0.0 1.5707962969925737 -1.0471975511965974 -1.047197525387029 + + + 0.005 + 0.17320508075688773 + + + + + + 0.9 + 0.9 + + + + + + 0.024999999999999998 -0.04330127018922193 0.0 1.5707962969925737 -1.0471975511965974 -1.047197525387029 + + + 0.005 + 0.17320508075688773 + + + + + + + + + -0.049999999999999996 0.08660254037844387 0 0 0 0 + + + 0.02 + + + + + + 0.9 + 0.9 + 1 0 0 + + + + + + -0.049999999999999996 0.08660254037844387 0 0 0 0 + + + 0.02 + + + + + + + + + -0.049999999999999996 0.0 0.0 1.5707963267948963 -0.0 0.0 + + + 0.005 + 0.17320508075688773 + + + + + + 0.9 + 0.9 + + + + + + -0.049999999999999996 0.0 0.0 1.5707963267948963 -0.0 0.0 + + + 0.005 + 0.17320508075688773 + + + + + + + + + -0.049999999999999996 -0.08660254037844387 0 0 0 0 + + + 0.02 + + + + + + 0.9 + 0.9 + 1 0 0 + + + + + + -0.049999999999999996 -0.08660254037844387 0 0 0 0 + + + 0.02 + + + + + + + + + + 0 15 0 + 0 0 -65.625 + + + + + + + 3.0 0 0 0 0 0 + + 0 0 0.02 0 0 0 + + 0.0 0.0 0 0 0 0 + 0.060318578948924034 + + 0.000311243867376448 + 0.000311243867376448 + 0.0006128367621210681 + 0.0 + 0.0 + 0.0 + + + + true + + + + 0.09999999999999999 0 0 0 0 0 + + + 0.02 + + + + + + 0.9 + 0.9 + 1 0 0 + + + + + + 0.09999999999999999 0 0 0 0 0 + + + 0.02 + + + + + + + + + 0.024999999999999998 0.04330127018922193 0.0 -1.5707962969925737 -1.0471975511965974 1.047197525387029 + + + 0.005 + 0.17320508075688773 + + + + + + 0.9 + 0.9 + + + + + + 0.024999999999999998 0.04330127018922193 0.0 -1.5707962969925737 -1.0471975511965974 1.047197525387029 + + + 0.005 + 0.17320508075688773 + + + + + + + + + 0.024999999999999998 -0.04330127018922193 0.0 1.5707962969925737 -1.0471975511965974 -1.047197525387029 + + + 0.005 + 0.17320508075688773 + + + + + + 0.9 + 0.9 + + + + + + 0.024999999999999998 -0.04330127018922193 0.0 1.5707962969925737 -1.0471975511965974 -1.047197525387029 + + + 0.005 + 0.17320508075688773 + + + + + + + + + -0.049999999999999996 0.08660254037844387 0 0 0 0 + + + 0.02 + + + + + + 0.9 + 0.9 + 1 0 0 + + + + + + -0.049999999999999996 0.08660254037844387 0 0 0 0 + + + 0.02 + + + + + + + + + -0.049999999999999996 0.0 0.0 1.5707963267948963 -0.0 0.0 + + + 0.005 + 0.17320508075688773 + + + + + + 0.9 + 0.9 + + + + + + -0.049999999999999996 0.0 0.0 1.5707963267948963 -0.0 0.0 + + + 0.005 + 0.17320508075688773 + + + + + + + + + -0.049999999999999996 -0.08660254037844387 0 0 0 0 + + + 0.02 + + + + + + 0.9 + 0.9 + 1 0 0 + + + + + + -0.049999999999999996 -0.08660254037844387 0 0 0 0 + + + 0.02 + + + + + + + + + + 0 15 0 + 0 0 -56.25 + + + + + + + 3.3 0 0 0 0 0 + + 0 0 0.02 0 0 0 + + 0.0 0.0 0 0 0 0 + 0.060318578948924034 + + 0.000311243867376448 + 0.000311243867376448 + 0.0006128367621210681 + 0.0 + 0.0 + 0.0 + + + + true + + + + 0.09999999999999999 0 0 0 0 0 + + + 0.02 + + + + + + 0.9 + 0.9 + 1 0 0 + + + + + + 0.09999999999999999 0 0 0 0 0 + + + 0.02 + + + + + + + + + 0.024999999999999998 0.04330127018922193 0.0 -1.5707962969925737 -1.0471975511965974 1.047197525387029 + + + 0.005 + 0.17320508075688773 + + + + + + 0.9 + 0.9 + + + + + + 0.024999999999999998 0.04330127018922193 0.0 -1.5707962969925737 -1.0471975511965974 1.047197525387029 + + + 0.005 + 0.17320508075688773 + + + + + + + + + 0.024999999999999998 -0.04330127018922193 0.0 1.5707962969925737 -1.0471975511965974 -1.047197525387029 + + + 0.005 + 0.17320508075688773 + + + + + + 0.9 + 0.9 + + + + + + 0.024999999999999998 -0.04330127018922193 0.0 1.5707962969925737 -1.0471975511965974 -1.047197525387029 + + + 0.005 + 0.17320508075688773 + + + + + + + + + -0.049999999999999996 0.08660254037844387 0 0 0 0 + + + 0.02 + + + + + + 0.9 + 0.9 + 1 0 0 + + + + + + -0.049999999999999996 0.08660254037844387 0 0 0 0 + + + 0.02 + + + + + + + + + -0.049999999999999996 0.0 0.0 1.5707963267948963 -0.0 0.0 + + + 0.005 + 0.17320508075688773 + + + + + + 0.9 + 0.9 + + + + + + -0.049999999999999996 0.0 0.0 1.5707963267948963 -0.0 0.0 + + + 0.005 + 0.17320508075688773 + + + + + + + + + -0.049999999999999996 -0.08660254037844387 0 0 0 0 + + + 0.02 + + + + + + 0.9 + 0.9 + 1 0 0 + + + + + + -0.049999999999999996 -0.08660254037844387 0 0 0 0 + + + 0.02 + + + + + + + + + + 0 15 0 + 0 0 -46.875 + + + + + + + 3.5999999999999996 0 0 0 0 0 + + 0 0 0.02 0 0 0 + + 0.0 0.0 0 0 0 0 + 0.060318578948924034 + + 0.000311243867376448 + 0.000311243867376448 + 0.0006128367621210681 + 0.0 + 0.0 + 0.0 + + + + true + + + + 0.09999999999999999 0 0 0 0 0 + + + 0.02 + + + + + + 0.9 + 0.9 + 1 0 0 + + + + + + 0.09999999999999999 0 0 0 0 0 + + + 0.02 + + + + + + + + + 0.024999999999999998 0.04330127018922193 0.0 -1.5707962969925737 -1.0471975511965974 1.047197525387029 + + + 0.005 + 0.17320508075688773 + + + + + + 0.9 + 0.9 + + + + + + 0.024999999999999998 0.04330127018922193 0.0 -1.5707962969925737 -1.0471975511965974 1.047197525387029 + + + 0.005 + 0.17320508075688773 + + + + + + + + + 0.024999999999999998 -0.04330127018922193 0.0 1.5707962969925737 -1.0471975511965974 -1.047197525387029 + + + 0.005 + 0.17320508075688773 + + + + + + 0.9 + 0.9 + + + + + + 0.024999999999999998 -0.04330127018922193 0.0 1.5707962969925737 -1.0471975511965974 -1.047197525387029 + + + 0.005 + 0.17320508075688773 + + + + + + + + + -0.049999999999999996 0.08660254037844387 0 0 0 0 + + + 0.02 + + + + + + 0.9 + 0.9 + 1 0 0 + + + + + + -0.049999999999999996 0.08660254037844387 0 0 0 0 + + + 0.02 + + + + + + + + + -0.049999999999999996 0.0 0.0 1.5707963267948963 -0.0 0.0 + + + 0.005 + 0.17320508075688773 + + + + + + 0.9 + 0.9 + + + + + + -0.049999999999999996 0.0 0.0 1.5707963267948963 -0.0 0.0 + + + 0.005 + 0.17320508075688773 + + + + + + + + + -0.049999999999999996 -0.08660254037844387 0 0 0 0 + + + 0.02 + + + + + + 0.9 + 0.9 + 1 0 0 + + + + + + -0.049999999999999996 -0.08660254037844387 0 0 0 0 + + + 0.02 + + + + + + + + + + 0 15 0 + 0 0 -37.5 + + + + + + + 3.9 0 0 0 0 0 + + 0 0 0.02 0 0 0 + + 0.0 0.0 0 0 0 0 + 0.060318578948924034 + + 0.000311243867376448 + 0.000311243867376448 + 0.0006128367621210681 + 0.0 + 0.0 + 0.0 + + + + true + + + + 0.09999999999999999 0 0 0 0 0 + + + 0.02 + + + + + + 0.9 + 0.9 + 1 0 0 + + + + + + 0.09999999999999999 0 0 0 0 0 + + + 0.02 + + + + + + + + + 0.024999999999999998 0.04330127018922193 0.0 -1.5707962969925737 -1.0471975511965974 1.047197525387029 + + + 0.005 + 0.17320508075688773 + + + + + + 0.9 + 0.9 + + + + + + 0.024999999999999998 0.04330127018922193 0.0 -1.5707962969925737 -1.0471975511965974 1.047197525387029 + + + 0.005 + 0.17320508075688773 + + + + + + + + + 0.024999999999999998 -0.04330127018922193 0.0 1.5707962969925737 -1.0471975511965974 -1.047197525387029 + + + 0.005 + 0.17320508075688773 + + + + + + 0.9 + 0.9 + + + + + + 0.024999999999999998 -0.04330127018922193 0.0 1.5707962969925737 -1.0471975511965974 -1.047197525387029 + + + 0.005 + 0.17320508075688773 + + + + + + + + + -0.049999999999999996 0.08660254037844387 0 0 0 0 + + + 0.02 + + + + + + 0.9 + 0.9 + 1 0 0 + + + + + + -0.049999999999999996 0.08660254037844387 0 0 0 0 + + + 0.02 + + + + + + + + + -0.049999999999999996 0.0 0.0 1.5707963267948963 -0.0 0.0 + + + 0.005 + 0.17320508075688773 + + + + + + 0.9 + 0.9 + + + + + + -0.049999999999999996 0.0 0.0 1.5707963267948963 -0.0 0.0 + + + 0.005 + 0.17320508075688773 + + + + + + + + + -0.049999999999999996 -0.08660254037844387 0 0 0 0 + + + 0.02 + + + + + + 0.9 + 0.9 + 1 0 0 + + + + + + -0.049999999999999996 -0.08660254037844387 0 0 0 0 + + + 0.02 + + + + + + + + + + 0 15 0 + 0 0 -28.125 + + + + + + + 4.2 0 0 0 0 0 + + 0 0 0.02 0 0 0 + + 0.0 0.0 0 0 0 0 + 0.060318578948924034 + + 0.000311243867376448 + 0.000311243867376448 + 0.0006128367621210681 + 0.0 + 0.0 + 0.0 + + + + true + + + + 0.09999999999999999 0 0 0 0 0 + + + 0.02 + + + + + + 0.9 + 0.9 + 1 0 0 + + + + + + 0.09999999999999999 0 0 0 0 0 + + + 0.02 + + + + + + + + + 0.024999999999999998 0.04330127018922193 0.0 -1.5707962969925737 -1.0471975511965974 1.047197525387029 + + + 0.005 + 0.17320508075688773 + + + + + + 0.9 + 0.9 + + + + + + 0.024999999999999998 0.04330127018922193 0.0 -1.5707962969925737 -1.0471975511965974 1.047197525387029 + + + 0.005 + 0.17320508075688773 + + + + + + + + + 0.024999999999999998 -0.04330127018922193 0.0 1.5707962969925737 -1.0471975511965974 -1.047197525387029 + + + 0.005 + 0.17320508075688773 + + + + + + 0.9 + 0.9 + + + + + + 0.024999999999999998 -0.04330127018922193 0.0 1.5707962969925737 -1.0471975511965974 -1.047197525387029 + + + 0.005 + 0.17320508075688773 + + + + + + + + + -0.049999999999999996 0.08660254037844387 0 0 0 0 + + + 0.02 + + + + + + 0.9 + 0.9 + 1 0 0 + + + + + + -0.049999999999999996 0.08660254037844387 0 0 0 0 + + + 0.02 + + + + + + + + + -0.049999999999999996 0.0 0.0 1.5707963267948963 -0.0 0.0 + + + 0.005 + 0.17320508075688773 + + + + + + 0.9 + 0.9 + + + + + + -0.049999999999999996 0.0 0.0 1.5707963267948963 -0.0 0.0 + + + 0.005 + 0.17320508075688773 + + + + + + + + + -0.049999999999999996 -0.08660254037844387 0 0 0 0 + + + 0.02 + + + + + + 0.9 + 0.9 + 1 0 0 + + + + + + -0.049999999999999996 -0.08660254037844387 0 0 0 0 + + + 0.02 + + + + + + + + + + 0 15 0 + 0 0 -18.75 + + + + + + + 4.5 0 0 0 0 0 + + 0 0 0.02 0 0 0 + + 0.0 0.0 0 0 0 0 + 0.060318578948924034 + + 0.000311243867376448 + 0.000311243867376448 + 0.0006128367621210681 + 0.0 + 0.0 + 0.0 + + + + true + + + + 0.09999999999999999 0 0 0 0 0 + + + 0.02 + + + + + + 0.9 + 0.9 + 1 0 0 + + + + + + 0.09999999999999999 0 0 0 0 0 + + + 0.02 + + + + + + + + + 0.024999999999999998 0.04330127018922193 0.0 -1.5707962969925737 -1.0471975511965974 1.047197525387029 + + + 0.005 + 0.17320508075688773 + + + + + + 0.9 + 0.9 + + + + + + 0.024999999999999998 0.04330127018922193 0.0 -1.5707962969925737 -1.0471975511965974 1.047197525387029 + + + 0.005 + 0.17320508075688773 + + + + + + + + + 0.024999999999999998 -0.04330127018922193 0.0 1.5707962969925737 -1.0471975511965974 -1.047197525387029 + + + 0.005 + 0.17320508075688773 + + + + + + 0.9 + 0.9 + + + + + + 0.024999999999999998 -0.04330127018922193 0.0 1.5707962969925737 -1.0471975511965974 -1.047197525387029 + + + 0.005 + 0.17320508075688773 + + + + + + + + + -0.049999999999999996 0.08660254037844387 0 0 0 0 + + + 0.02 + + + + + + 0.9 + 0.9 + 1 0 0 + + + + + + -0.049999999999999996 0.08660254037844387 0 0 0 0 + + + 0.02 + + + + + + + + + -0.049999999999999996 0.0 0.0 1.5707963267948963 -0.0 0.0 + + + 0.005 + 0.17320508075688773 + + + + + + 0.9 + 0.9 + + + + + + -0.049999999999999996 0.0 0.0 1.5707963267948963 -0.0 0.0 + + + 0.005 + 0.17320508075688773 + + + + + + + + + -0.049999999999999996 -0.08660254037844387 0 0 0 0 + + + 0.02 + + + + + + 0.9 + 0.9 + 1 0 0 + + + + + + -0.049999999999999996 -0.08660254037844387 0 0 0 0 + + + 0.02 + + + + + + + + + + 0 15 0 + 0 0 -9.375 + + + + + + + 4.8 0 0 0 0 0 + + 0 0 0.02 0 0 0 + + 0.0 0.0 0 0 0 0 + 0.060318578948924034 + + 0.000311243867376448 + 0.000311243867376448 + 0.0006128367621210681 + 0.0 + 0.0 + 0.0 + + + + true + + + + 0.09999999999999999 0 0 0 0 0 + + + 0.02 + + + + + + 0.9 + 0.9 + 1 0 0 + + + + + + 0.09999999999999999 0 0 0 0 0 + + + 0.02 + + + + + + + + + 0.024999999999999998 0.04330127018922193 0.0 -1.5707962969925737 -1.0471975511965974 1.047197525387029 + + + 0.005 + 0.17320508075688773 + + + + + + 0.9 + 0.9 + + + + + + 0.024999999999999998 0.04330127018922193 0.0 -1.5707962969925737 -1.0471975511965974 1.047197525387029 + + + 0.005 + 0.17320508075688773 + + + + + + + + + 0.024999999999999998 -0.04330127018922193 0.0 1.5707962969925737 -1.0471975511965974 -1.047197525387029 + + + 0.005 + 0.17320508075688773 + + + + + + 0.9 + 0.9 + + + + + + 0.024999999999999998 -0.04330127018922193 0.0 1.5707962969925737 -1.0471975511965974 -1.047197525387029 + + + 0.005 + 0.17320508075688773 + + + + + + + + + -0.049999999999999996 0.08660254037844387 0 0 0 0 + + + 0.02 + + + + + + 0.9 + 0.9 + 1 0 0 + + + + + + -0.049999999999999996 0.08660254037844387 0 0 0 0 + + + 0.02 + + + + + + + + + -0.049999999999999996 0.0 0.0 1.5707963267948963 -0.0 0.0 + + + 0.005 + 0.17320508075688773 + + + + + + 0.9 + 0.9 + + + + + + -0.049999999999999996 0.0 0.0 1.5707963267948963 -0.0 0.0 + + + 0.005 + 0.17320508075688773 + + + + + + + + + -0.049999999999999996 -0.08660254037844387 0 0 0 0 + + + 0.02 + + + + + + 0.9 + 0.9 + 1 0 0 + + + + + + -0.049999999999999996 -0.08660254037844387 0 0 0 0 + + + 0.02 + + + + + + + + + + 0 15 0 + 0 0 0.0 + + + + + + + 5.1 0 0 0 0 0 + + 0 0 0.02 0 0 0 + + 0.0 0.0 0 0 0 0 + 0.060318578948924034 + + 0.000311243867376448 + 0.000311243867376448 + 0.0006128367621210681 + 0.0 + 0.0 + 0.0 + + + + true + + + + 0.09999999999999999 0 0 0 0 0 + + + 0.02 + + + + + + 0.9 + 0.9 + 1 0 0 + + + + + + 0.09999999999999999 0 0 0 0 0 + + + 0.02 + + + + + + + + + 0.024999999999999998 0.04330127018922193 0.0 -1.5707962969925737 -1.0471975511965974 1.047197525387029 + + + 0.005 + 0.17320508075688773 + + + + + + 0.9 + 0.9 + + + + + + 0.024999999999999998 0.04330127018922193 0.0 -1.5707962969925737 -1.0471975511965974 1.047197525387029 + + + 0.005 + 0.17320508075688773 + + + + + + + + + 0.024999999999999998 -0.04330127018922193 0.0 1.5707962969925737 -1.0471975511965974 -1.047197525387029 + + + 0.005 + 0.17320508075688773 + + + + + + 0.9 + 0.9 + + + + + + 0.024999999999999998 -0.04330127018922193 0.0 1.5707962969925737 -1.0471975511965974 -1.047197525387029 + + + 0.005 + 0.17320508075688773 + + + + + + + + + -0.049999999999999996 0.08660254037844387 0 0 0 0 + + + 0.02 + + + + + + 0.9 + 0.9 + 1 0 0 + + + + + + -0.049999999999999996 0.08660254037844387 0 0 0 0 + + + 0.02 + + + + + + + + + -0.049999999999999996 0.0 0.0 1.5707963267948963 -0.0 0.0 + + + 0.005 + 0.17320508075688773 + + + + + + 0.9 + 0.9 + + + + + + -0.049999999999999996 0.0 0.0 1.5707963267948963 -0.0 0.0 + + + 0.005 + 0.17320508075688773 + + + + + + + + + -0.049999999999999996 -0.08660254037844387 0 0 0 0 + + + 0.02 + + + + + + 0.9 + 0.9 + 1 0 0 + + + + + + -0.049999999999999996 -0.08660254037844387 0 0 0 0 + + + 0.02 + + + + + + + + + + 0 15 0 + 0 0 9.375 + + + + + + + 5.3999999999999995 0 0 0 0 0 + + 0 0 0.02 0 0 0 + + 0.0 0.0 0 0 0 0 + 0.060318578948924034 + + 0.000311243867376448 + 0.000311243867376448 + 0.0006128367621210681 + 0.0 + 0.0 + 0.0 + + + + true + + + + 0.09999999999999999 0 0 0 0 0 + + + 0.02 + + + + + + 0.9 + 0.9 + 1 0 0 + + + + + + 0.09999999999999999 0 0 0 0 0 + + + 0.02 + + + + + + + + + 0.024999999999999998 0.04330127018922193 0.0 -1.5707962969925737 -1.0471975511965974 1.047197525387029 + + + 0.005 + 0.17320508075688773 + + + + + + 0.9 + 0.9 + + + + + + 0.024999999999999998 0.04330127018922193 0.0 -1.5707962969925737 -1.0471975511965974 1.047197525387029 + + + 0.005 + 0.17320508075688773 + + + + + + + + + 0.024999999999999998 -0.04330127018922193 0.0 1.5707962969925737 -1.0471975511965974 -1.047197525387029 + + + 0.005 + 0.17320508075688773 + + + + + + 0.9 + 0.9 + + + + + + 0.024999999999999998 -0.04330127018922193 0.0 1.5707962969925737 -1.0471975511965974 -1.047197525387029 + + + 0.005 + 0.17320508075688773 + + + + + + + + + -0.049999999999999996 0.08660254037844387 0 0 0 0 + + + 0.02 + + + + + + 0.9 + 0.9 + 1 0 0 + + + + + + -0.049999999999999996 0.08660254037844387 0 0 0 0 + + + 0.02 + + + + + + + + + -0.049999999999999996 0.0 0.0 1.5707963267948963 -0.0 0.0 + + + 0.005 + 0.17320508075688773 + + + + + + 0.9 + 0.9 + + + + + + -0.049999999999999996 0.0 0.0 1.5707963267948963 -0.0 0.0 + + + 0.005 + 0.17320508075688773 + + + + + + + + + -0.049999999999999996 -0.08660254037844387 0 0 0 0 + + + 0.02 + + + + + + 0.9 + 0.9 + 1 0 0 + + + + + + -0.049999999999999996 -0.08660254037844387 0 0 0 0 + + + 0.02 + + + + + + + + + + 0 15 0 + 0 0 18.75 + + + + + + + 5.7 0 0 0 0 0 + + 0 0 0.02 0 0 0 + + 0.0 0.0 0 0 0 0 + 0.060318578948924034 + + 0.000311243867376448 + 0.000311243867376448 + 0.0006128367621210681 + 0.0 + 0.0 + 0.0 + + + + true + + + + 0.09999999999999999 0 0 0 0 0 + + + 0.02 + + + + + + 0.9 + 0.9 + 1 0 0 + + + + + + 0.09999999999999999 0 0 0 0 0 + + + 0.02 + + + + + + + + + 0.024999999999999998 0.04330127018922193 0.0 -1.5707962969925737 -1.0471975511965974 1.047197525387029 + + + 0.005 + 0.17320508075688773 + + + + + + 0.9 + 0.9 + + + + + + 0.024999999999999998 0.04330127018922193 0.0 -1.5707962969925737 -1.0471975511965974 1.047197525387029 + + + 0.005 + 0.17320508075688773 + + + + + + + + + 0.024999999999999998 -0.04330127018922193 0.0 1.5707962969925737 -1.0471975511965974 -1.047197525387029 + + + 0.005 + 0.17320508075688773 + + + + + + 0.9 + 0.9 + + + + + + 0.024999999999999998 -0.04330127018922193 0.0 1.5707962969925737 -1.0471975511965974 -1.047197525387029 + + + 0.005 + 0.17320508075688773 + + + + + + + + + -0.049999999999999996 0.08660254037844387 0 0 0 0 + + + 0.02 + + + + + + 0.9 + 0.9 + 1 0 0 + + + + + + -0.049999999999999996 0.08660254037844387 0 0 0 0 + + + 0.02 + + + + + + + + + -0.049999999999999996 0.0 0.0 1.5707963267948963 -0.0 0.0 + + + 0.005 + 0.17320508075688773 + + + + + + 0.9 + 0.9 + + + + + + -0.049999999999999996 0.0 0.0 1.5707963267948963 -0.0 0.0 + + + 0.005 + 0.17320508075688773 + + + + + + + + + -0.049999999999999996 -0.08660254037844387 0 0 0 0 + + + 0.02 + + + + + + 0.9 + 0.9 + 1 0 0 + + + + + + -0.049999999999999996 -0.08660254037844387 0 0 0 0 + + + 0.02 + + + + + + + + + + 0 15 0 + 0 0 28.125 + + + + + + + 6.0 0 0 0 0 0 + + 0 0 0.02 0 0 0 + + 0.0 0.0 0 0 0 0 + 0.060318578948924034 + + 0.000311243867376448 + 0.000311243867376448 + 0.0006128367621210681 + 0.0 + 0.0 + 0.0 + + + + true + + + + 0.09999999999999999 0 0 0 0 0 + + + 0.02 + + + + + + 0.9 + 0.9 + 1 0 0 + + + + + + 0.09999999999999999 0 0 0 0 0 + + + 0.02 + + + + + + + + + 0.024999999999999998 0.04330127018922193 0.0 -1.5707962969925737 -1.0471975511965974 1.047197525387029 + + + 0.005 + 0.17320508075688773 + + + + + + 0.9 + 0.9 + + + + + + 0.024999999999999998 0.04330127018922193 0.0 -1.5707962969925737 -1.0471975511965974 1.047197525387029 + + + 0.005 + 0.17320508075688773 + + + + + + + + + 0.024999999999999998 -0.04330127018922193 0.0 1.5707962969925737 -1.0471975511965974 -1.047197525387029 + + + 0.005 + 0.17320508075688773 + + + + + + 0.9 + 0.9 + + + + + + 0.024999999999999998 -0.04330127018922193 0.0 1.5707962969925737 -1.0471975511965974 -1.047197525387029 + + + 0.005 + 0.17320508075688773 + + + + + + + + + -0.049999999999999996 0.08660254037844387 0 0 0 0 + + + 0.02 + + + + + + 0.9 + 0.9 + 1 0 0 + + + + + + -0.049999999999999996 0.08660254037844387 0 0 0 0 + + + 0.02 + + + + + + + + + -0.049999999999999996 0.0 0.0 1.5707963267948963 -0.0 0.0 + + + 0.005 + 0.17320508075688773 + + + + + + 0.9 + 0.9 + + + + + + -0.049999999999999996 0.0 0.0 1.5707963267948963 -0.0 0.0 + + + 0.005 + 0.17320508075688773 + + + + + + + + + -0.049999999999999996 -0.08660254037844387 0 0 0 0 + + + 0.02 + + + + + + 0.9 + 0.9 + 1 0 0 + + + + + + -0.049999999999999996 -0.08660254037844387 0 0 0 0 + + + 0.02 + + + + + + + + + + 0 15 0 + 0 0 37.5 + + + + + + + 6.3 0 0 0 0 0 + + 0 0 0.02 0 0 0 + + 0.0 0.0 0 0 0 0 + 0.060318578948924034 + + 0.000311243867376448 + 0.000311243867376448 + 0.0006128367621210681 + 0.0 + 0.0 + 0.0 + + + + true + + + + 0.09999999999999999 0 0 0 0 0 + + + 0.02 + + + + + + 0.9 + 0.9 + 1 0 0 + + + + + + 0.09999999999999999 0 0 0 0 0 + + + 0.02 + + + + + + + + + 0.024999999999999998 0.04330127018922193 0.0 -1.5707962969925737 -1.0471975511965974 1.047197525387029 + + + 0.005 + 0.17320508075688773 + + + + + + 0.9 + 0.9 + + + + + + 0.024999999999999998 0.04330127018922193 0.0 -1.5707962969925737 -1.0471975511965974 1.047197525387029 + + + 0.005 + 0.17320508075688773 + + + + + + + + + 0.024999999999999998 -0.04330127018922193 0.0 1.5707962969925737 -1.0471975511965974 -1.047197525387029 + + + 0.005 + 0.17320508075688773 + + + + + + 0.9 + 0.9 + + + + + + 0.024999999999999998 -0.04330127018922193 0.0 1.5707962969925737 -1.0471975511965974 -1.047197525387029 + + + 0.005 + 0.17320508075688773 + + + + + + + + + -0.049999999999999996 0.08660254037844387 0 0 0 0 + + + 0.02 + + + + + + 0.9 + 0.9 + 1 0 0 + + + + + + -0.049999999999999996 0.08660254037844387 0 0 0 0 + + + 0.02 + + + + + + + + + -0.049999999999999996 0.0 0.0 1.5707963267948963 -0.0 0.0 + + + 0.005 + 0.17320508075688773 + + + + + + 0.9 + 0.9 + + + + + + -0.049999999999999996 0.0 0.0 1.5707963267948963 -0.0 0.0 + + + 0.005 + 0.17320508075688773 + + + + + + + + + -0.049999999999999996 -0.08660254037844387 0 0 0 0 + + + 0.02 + + + + + + 0.9 + 0.9 + 1 0 0 + + + + + + -0.049999999999999996 -0.08660254037844387 0 0 0 0 + + + 0.02 + + + + + + + + + + 0 15 0 + 0 0 46.875 + + + + + + + 6.6 0 0 0 0 0 + + 0 0 0.02 0 0 0 + + 0.0 0.0 0 0 0 0 + 0.060318578948924034 + + 0.000311243867376448 + 0.000311243867376448 + 0.0006128367621210681 + 0.0 + 0.0 + 0.0 + + + + true + + + + 0.09999999999999999 0 0 0 0 0 + + + 0.02 + + + + + + 0.9 + 0.9 + 1 0 0 + + + + + + 0.09999999999999999 0 0 0 0 0 + + + 0.02 + + + + + + + + + 0.024999999999999998 0.04330127018922193 0.0 -1.5707962969925737 -1.0471975511965974 1.047197525387029 + + + 0.005 + 0.17320508075688773 + + + + + + 0.9 + 0.9 + + + + + + 0.024999999999999998 0.04330127018922193 0.0 -1.5707962969925737 -1.0471975511965974 1.047197525387029 + + + 0.005 + 0.17320508075688773 + + + + + + + + + 0.024999999999999998 -0.04330127018922193 0.0 1.5707962969925737 -1.0471975511965974 -1.047197525387029 + + + 0.005 + 0.17320508075688773 + + + + + + 0.9 + 0.9 + + + + + + 0.024999999999999998 -0.04330127018922193 0.0 1.5707962969925737 -1.0471975511965974 -1.047197525387029 + + + 0.005 + 0.17320508075688773 + + + + + + + + + -0.049999999999999996 0.08660254037844387 0 0 0 0 + + + 0.02 + + + + + + 0.9 + 0.9 + 1 0 0 + + + + + + -0.049999999999999996 0.08660254037844387 0 0 0 0 + + + 0.02 + + + + + + + + + -0.049999999999999996 0.0 0.0 1.5707963267948963 -0.0 0.0 + + + 0.005 + 0.17320508075688773 + + + + + + 0.9 + 0.9 + + + + + + -0.049999999999999996 0.0 0.0 1.5707963267948963 -0.0 0.0 + + + 0.005 + 0.17320508075688773 + + + + + + + + + -0.049999999999999996 -0.08660254037844387 0 0 0 0 + + + 0.02 + + + + + + 0.9 + 0.9 + 1 0 0 + + + + + + -0.049999999999999996 -0.08660254037844387 0 0 0 0 + + + 0.02 + + + + + + + + + + 0 15 0 + 0 0 56.25 + + + + + + + 6.8999999999999995 0 0 0 0 0 + + 0 0 0.02 0 0 0 + + 0.0 0.0 0 0 0 0 + 0.060318578948924034 + + 0.000311243867376448 + 0.000311243867376448 + 0.0006128367621210681 + 0.0 + 0.0 + 0.0 + + + + true + + + + 0.09999999999999999 0 0 0 0 0 + + + 0.02 + + + + + + 0.9 + 0.9 + 1 0 0 + + + + + + 0.09999999999999999 0 0 0 0 0 + + + 0.02 + + + + + + + + + 0.024999999999999998 0.04330127018922193 0.0 -1.5707962969925737 -1.0471975511965974 1.047197525387029 + + + 0.005 + 0.17320508075688773 + + + + + + 0.9 + 0.9 + + + + + + 0.024999999999999998 0.04330127018922193 0.0 -1.5707962969925737 -1.0471975511965974 1.047197525387029 + + + 0.005 + 0.17320508075688773 + + + + + + + + + 0.024999999999999998 -0.04330127018922193 0.0 1.5707962969925737 -1.0471975511965974 -1.047197525387029 + + + 0.005 + 0.17320508075688773 + + + + + + 0.9 + 0.9 + + + + + + 0.024999999999999998 -0.04330127018922193 0.0 1.5707962969925737 -1.0471975511965974 -1.047197525387029 + + + 0.005 + 0.17320508075688773 + + + + + + + + + -0.049999999999999996 0.08660254037844387 0 0 0 0 + + + 0.02 + + + + + + 0.9 + 0.9 + 1 0 0 + + + + + + -0.049999999999999996 0.08660254037844387 0 0 0 0 + + + 0.02 + + + + + + + + + -0.049999999999999996 0.0 0.0 1.5707963267948963 -0.0 0.0 + + + 0.005 + 0.17320508075688773 + + + + + + 0.9 + 0.9 + + + + + + -0.049999999999999996 0.0 0.0 1.5707963267948963 -0.0 0.0 + + + 0.005 + 0.17320508075688773 + + + + + + + + + -0.049999999999999996 -0.08660254037844387 0 0 0 0 + + + 0.02 + + + + + + 0.9 + 0.9 + 1 0 0 + + + + + + -0.049999999999999996 -0.08660254037844387 0 0 0 0 + + + 0.02 + + + + + + + + + + 0 15 0 + 0 0 65.625 + + + + + + + 7.199999999999999 0 0 0 0 0 + + 0 0 0.02 0 0 0 + + 0.0 0.0 0 0 0 0 + 0.060318578948924034 + + 0.000311243867376448 + 0.000311243867376448 + 0.0006128367621210681 + 0.0 + 0.0 + 0.0 + + + + true + + + + 0.09999999999999999 0 0 0 0 0 + + + 0.02 + + + + + + 0.9 + 0.9 + 1 0 0 + + + + + + 0.09999999999999999 0 0 0 0 0 + + + 0.02 + + + + + + + + + 0.024999999999999998 0.04330127018922193 0.0 -1.5707962969925737 -1.0471975511965974 1.047197525387029 + + + 0.005 + 0.17320508075688773 + + + + + + 0.9 + 0.9 + + + + + + 0.024999999999999998 0.04330127018922193 0.0 -1.5707962969925737 -1.0471975511965974 1.047197525387029 + + + 0.005 + 0.17320508075688773 + + + + + + + + + 0.024999999999999998 -0.04330127018922193 0.0 1.5707962969925737 -1.0471975511965974 -1.047197525387029 + + + 0.005 + 0.17320508075688773 + + + + + + 0.9 + 0.9 + + + + + + 0.024999999999999998 -0.04330127018922193 0.0 1.5707962969925737 -1.0471975511965974 -1.047197525387029 + + + 0.005 + 0.17320508075688773 + + + + + + + + + -0.049999999999999996 0.08660254037844387 0 0 0 0 + + + 0.02 + + + + + + 0.9 + 0.9 + 1 0 0 + + + + + + -0.049999999999999996 0.08660254037844387 0 0 0 0 + + + 0.02 + + + + + + + + + -0.049999999999999996 0.0 0.0 1.5707963267948963 -0.0 0.0 + + + 0.005 + 0.17320508075688773 + + + + + + 0.9 + 0.9 + + + + + + -0.049999999999999996 0.0 0.0 1.5707963267948963 -0.0 0.0 + + + 0.005 + 0.17320508075688773 + + + + + + + + + -0.049999999999999996 -0.08660254037844387 0 0 0 0 + + + 0.02 + + + + + + 0.9 + 0.9 + 1 0 0 + + + + + + -0.049999999999999996 -0.08660254037844387 0 0 0 0 + + + 0.02 + + + + + + + + + + 0 15 0 + 0 0 75.0 + + + + + + + 7.5 0 0 0 0 0 + + 0 0 0.02 0 0 0 + + 0.0 0.0 0 0 0 0 + 0.060318578948924034 + + 0.000311243867376448 + 0.000311243867376448 + 0.0006128367621210681 + 0.0 + 0.0 + 0.0 + + + + true + + + + 0.09999999999999999 0 0 0 0 0 + + + 0.02 + + + + + + 0.9 + 0.9 + 1 0 0 + + + + + + 0.09999999999999999 0 0 0 0 0 + + + 0.02 + + + + + + + + + 0.024999999999999998 0.04330127018922193 0.0 -1.5707962969925737 -1.0471975511965974 1.047197525387029 + + + 0.005 + 0.17320508075688773 + + + + + + 0.9 + 0.9 + + + + + + 0.024999999999999998 0.04330127018922193 0.0 -1.5707962969925737 -1.0471975511965974 1.047197525387029 + + + 0.005 + 0.17320508075688773 + + + + + + + + + 0.024999999999999998 -0.04330127018922193 0.0 1.5707962969925737 -1.0471975511965974 -1.047197525387029 + + + 0.005 + 0.17320508075688773 + + + + + + 0.9 + 0.9 + + + + + + 0.024999999999999998 -0.04330127018922193 0.0 1.5707962969925737 -1.0471975511965974 -1.047197525387029 + + + 0.005 + 0.17320508075688773 + + + + + + + + + -0.049999999999999996 0.08660254037844387 0 0 0 0 + + + 0.02 + + + + + + 0.9 + 0.9 + 1 0 0 + + + + + + -0.049999999999999996 0.08660254037844387 0 0 0 0 + + + 0.02 + + + + + + + + + -0.049999999999999996 0.0 0.0 1.5707963267948963 -0.0 0.0 + + + 0.005 + 0.17320508075688773 + + + + + + 0.9 + 0.9 + + + + + + -0.049999999999999996 0.0 0.0 1.5707963267948963 -0.0 0.0 + + + 0.005 + 0.17320508075688773 + + + + + + + + + -0.049999999999999996 -0.08660254037844387 0 0 0 0 + + + 0.02 + + + + + + 0.9 + 0.9 + 1 0 0 + + + + + + -0.049999999999999996 -0.08660254037844387 0 0 0 0 + + + 0.02 + + + + + + + + + + 0 15 0 + 0 0 84.375 + + + + + + + 7.8 0 0 0 0 0 + + 0 0 0.02 0 0 0 + + 0.0 0.0 0 0 0 0 + 0.060318578948924034 + + 0.000311243867376448 + 0.000311243867376448 + 0.0006128367621210681 + 0.0 + 0.0 + 0.0 + + + + true + + + + 0.09999999999999999 0 0 0 0 0 + + + 0.02 + + + + + + 0.9 + 0.9 + 1 0 0 + + + + + + 0.09999999999999999 0 0 0 0 0 + + + 0.02 + + + + + + + + + 0.024999999999999998 0.04330127018922193 0.0 -1.5707962969925737 -1.0471975511965974 1.047197525387029 + + + 0.005 + 0.17320508075688773 + + + + + + 0.9 + 0.9 + + + + + + 0.024999999999999998 0.04330127018922193 0.0 -1.5707962969925737 -1.0471975511965974 1.047197525387029 + + + 0.005 + 0.17320508075688773 + + + + + + + + + 0.024999999999999998 -0.04330127018922193 0.0 1.5707962969925737 -1.0471975511965974 -1.047197525387029 + + + 0.005 + 0.17320508075688773 + + + + + + 0.9 + 0.9 + + + + + + 0.024999999999999998 -0.04330127018922193 0.0 1.5707962969925737 -1.0471975511965974 -1.047197525387029 + + + 0.005 + 0.17320508075688773 + + + + + + + + + -0.049999999999999996 0.08660254037844387 0 0 0 0 + + + 0.02 + + + + + + 0.9 + 0.9 + 1 0 0 + + + + + + -0.049999999999999996 0.08660254037844387 0 0 0 0 + + + 0.02 + + + + + + + + + -0.049999999999999996 0.0 0.0 1.5707963267948963 -0.0 0.0 + + + 0.005 + 0.17320508075688773 + + + + + + 0.9 + 0.9 + + + + + + -0.049999999999999996 0.0 0.0 1.5707963267948963 -0.0 0.0 + + + 0.005 + 0.17320508075688773 + + + + + + + + + -0.049999999999999996 -0.08660254037844387 0 0 0 0 + + + 0.02 + + + + + + 0.9 + 0.9 + 1 0 0 + + + + + + -0.049999999999999996 -0.08660254037844387 0 0 0 0 + + + 0.02 + + + + + + + + + + 0 15 0 + 0 0 93.75 + + + + + + + 8.1 0 0 0 0 0 + + 0 0 0.02 0 0 0 + + 0.0 0.0 0 0 0 0 + 0.060318578948924034 + + 0.000311243867376448 + 0.000311243867376448 + 0.0006128367621210681 + 0.0 + 0.0 + 0.0 + + + + true + + + + 0.09999999999999999 0 0 0 0 0 + + + 0.02 + + + + + + 0.9 + 0.9 + 1 0 0 + + + + + + 0.09999999999999999 0 0 0 0 0 + + + 0.02 + + + + + + + + + 0.024999999999999998 0.04330127018922193 0.0 -1.5707962969925737 -1.0471975511965974 1.047197525387029 + + + 0.005 + 0.17320508075688773 + + + + + + 0.9 + 0.9 + + + + + + 0.024999999999999998 0.04330127018922193 0.0 -1.5707962969925737 -1.0471975511965974 1.047197525387029 + + + 0.005 + 0.17320508075688773 + + + + + + + + + 0.024999999999999998 -0.04330127018922193 0.0 1.5707962969925737 -1.0471975511965974 -1.047197525387029 + + + 0.005 + 0.17320508075688773 + + + + + + 0.9 + 0.9 + + + + + + 0.024999999999999998 -0.04330127018922193 0.0 1.5707962969925737 -1.0471975511965974 -1.047197525387029 + + + 0.005 + 0.17320508075688773 + + + + + + + + + -0.049999999999999996 0.08660254037844387 0 0 0 0 + + + 0.02 + + + + + + 0.9 + 0.9 + 1 0 0 + + + + + + -0.049999999999999996 0.08660254037844387 0 0 0 0 + + + 0.02 + + + + + + + + + -0.049999999999999996 0.0 0.0 1.5707963267948963 -0.0 0.0 + + + 0.005 + 0.17320508075688773 + + + + + + 0.9 + 0.9 + + + + + + -0.049999999999999996 0.0 0.0 1.5707963267948963 -0.0 0.0 + + + 0.005 + 0.17320508075688773 + + + + + + + + + -0.049999999999999996 -0.08660254037844387 0 0 0 0 + + + 0.02 + + + + + + 0.9 + 0.9 + 1 0 0 + + + + + + -0.049999999999999996 -0.08660254037844387 0 0 0 0 + + + 0.02 + + + + + + + + + + 0 15 0 + 0 0 103.125 + + + + + + + 8.4 0 0 0 0 0 + + 0 0 0.02 0 0 0 + + 0.0 0.0 0 0 0 0 + 0.060318578948924034 + + 0.000311243867376448 + 0.000311243867376448 + 0.0006128367621210681 + 0.0 + 0.0 + 0.0 + + + + true + + + + 0.09999999999999999 0 0 0 0 0 + + + 0.02 + + + + + + 0.9 + 0.9 + 1 0 0 + + + + + + 0.09999999999999999 0 0 0 0 0 + + + 0.02 + + + + + + + + + 0.024999999999999998 0.04330127018922193 0.0 -1.5707962969925737 -1.0471975511965974 1.047197525387029 + + + 0.005 + 0.17320508075688773 + + + + + + 0.9 + 0.9 + + + + + + 0.024999999999999998 0.04330127018922193 0.0 -1.5707962969925737 -1.0471975511965974 1.047197525387029 + + + 0.005 + 0.17320508075688773 + + + + + + + + + 0.024999999999999998 -0.04330127018922193 0.0 1.5707962969925737 -1.0471975511965974 -1.047197525387029 + + + 0.005 + 0.17320508075688773 + + + + + + 0.9 + 0.9 + + + + + + 0.024999999999999998 -0.04330127018922193 0.0 1.5707962969925737 -1.0471975511965974 -1.047197525387029 + + + 0.005 + 0.17320508075688773 + + + + + + + + + -0.049999999999999996 0.08660254037844387 0 0 0 0 + + + 0.02 + + + + + + 0.9 + 0.9 + 1 0 0 + + + + + + -0.049999999999999996 0.08660254037844387 0 0 0 0 + + + 0.02 + + + + + + + + + -0.049999999999999996 0.0 0.0 1.5707963267948963 -0.0 0.0 + + + 0.005 + 0.17320508075688773 + + + + + + 0.9 + 0.9 + + + + + + -0.049999999999999996 0.0 0.0 1.5707963267948963 -0.0 0.0 + + + 0.005 + 0.17320508075688773 + + + + + + + + + -0.049999999999999996 -0.08660254037844387 0 0 0 0 + + + 0.02 + + + + + + 0.9 + 0.9 + 1 0 0 + + + + + + -0.049999999999999996 -0.08660254037844387 0 0 0 0 + + + 0.02 + + + + + + + + + + 0 15 0 + 0 0 112.5 + + + + + + + 8.7 0 0 0 0 0 + + 0 0 0.02 0 0 0 + + 0.0 0.0 0 0 0 0 + 0.060318578948924034 + + 0.000311243867376448 + 0.000311243867376448 + 0.0006128367621210681 + 0.0 + 0.0 + 0.0 + + + + true + + + + 0.09999999999999999 0 0 0 0 0 + + + 0.02 + + + + + + 0.9 + 0.9 + 1 0 0 + + + + + + 0.09999999999999999 0 0 0 0 0 + + + 0.02 + + + + + + + + + 0.024999999999999998 0.04330127018922193 0.0 -1.5707962969925737 -1.0471975511965974 1.047197525387029 + + + 0.005 + 0.17320508075688773 + + + + + + 0.9 + 0.9 + + + + + + 0.024999999999999998 0.04330127018922193 0.0 -1.5707962969925737 -1.0471975511965974 1.047197525387029 + + + 0.005 + 0.17320508075688773 + + + + + + + + + 0.024999999999999998 -0.04330127018922193 0.0 1.5707962969925737 -1.0471975511965974 -1.047197525387029 + + + 0.005 + 0.17320508075688773 + + + + + + 0.9 + 0.9 + + + + + + 0.024999999999999998 -0.04330127018922193 0.0 1.5707962969925737 -1.0471975511965974 -1.047197525387029 + + + 0.005 + 0.17320508075688773 + + + + + + + + + -0.049999999999999996 0.08660254037844387 0 0 0 0 + + + 0.02 + + + + + + 0.9 + 0.9 + 1 0 0 + + + + + + -0.049999999999999996 0.08660254037844387 0 0 0 0 + + + 0.02 + + + + + + + + + -0.049999999999999996 0.0 0.0 1.5707963267948963 -0.0 0.0 + + + 0.005 + 0.17320508075688773 + + + + + + 0.9 + 0.9 + + + + + + -0.049999999999999996 0.0 0.0 1.5707963267948963 -0.0 0.0 + + + 0.005 + 0.17320508075688773 + + + + + + + + + -0.049999999999999996 -0.08660254037844387 0 0 0 0 + + + 0.02 + + + + + + 0.9 + 0.9 + 1 0 0 + + + + + + -0.049999999999999996 -0.08660254037844387 0 0 0 0 + + + 0.02 + + + + + + + + + + 0 15 0 + 0 0 121.875 + + + + + + + 9.0 0 0 0 0 0 + + 0 0 0.02 0 0 0 + + 0.0 0.0 0 0 0 0 + 0.060318578948924034 + + 0.000311243867376448 + 0.000311243867376448 + 0.0006128367621210681 + 0.0 + 0.0 + 0.0 + + + + true + + + + 0.09999999999999999 0 0 0 0 0 + + + 0.02 + + + + + + 0.9 + 0.9 + 1 0 0 + + + + + + 0.09999999999999999 0 0 0 0 0 + + + 0.02 + + + + + + + + + 0.024999999999999998 0.04330127018922193 0.0 -1.5707962969925737 -1.0471975511965974 1.047197525387029 + + + 0.005 + 0.17320508075688773 + + + + + + 0.9 + 0.9 + + + + + + 0.024999999999999998 0.04330127018922193 0.0 -1.5707962969925737 -1.0471975511965974 1.047197525387029 + + + 0.005 + 0.17320508075688773 + + + + + + + + + 0.024999999999999998 -0.04330127018922193 0.0 1.5707962969925737 -1.0471975511965974 -1.047197525387029 + + + 0.005 + 0.17320508075688773 + + + + + + 0.9 + 0.9 + + + + + + 0.024999999999999998 -0.04330127018922193 0.0 1.5707962969925737 -1.0471975511965974 -1.047197525387029 + + + 0.005 + 0.17320508075688773 + + + + + + + + + -0.049999999999999996 0.08660254037844387 0 0 0 0 + + + 0.02 + + + + + + 0.9 + 0.9 + 1 0 0 + + + + + + -0.049999999999999996 0.08660254037844387 0 0 0 0 + + + 0.02 + + + + + + + + + -0.049999999999999996 0.0 0.0 1.5707963267948963 -0.0 0.0 + + + 0.005 + 0.17320508075688773 + + + + + + 0.9 + 0.9 + + + + + + -0.049999999999999996 0.0 0.0 1.5707963267948963 -0.0 0.0 + + + 0.005 + 0.17320508075688773 + + + + + + + + + -0.049999999999999996 -0.08660254037844387 0 0 0 0 + + + 0.02 + + + + + + 0.9 + 0.9 + 1 0 0 + + + + + + -0.049999999999999996 -0.08660254037844387 0 0 0 0 + + + 0.02 + + + + + + + + + + 0 15 0 + 0 0 131.25 + + + + + + + 9.299999999999999 0 0 0 0 0 + + 0 0 0.02 0 0 0 + + 0.0 0.0 0 0 0 0 + 0.060318578948924034 + + 0.000311243867376448 + 0.000311243867376448 + 0.0006128367621210681 + 0.0 + 0.0 + 0.0 + + + + true + + + + 0.09999999999999999 0 0 0 0 0 + + + 0.02 + + + + + + 0.9 + 0.9 + 1 0 0 + + + + + + 0.09999999999999999 0 0 0 0 0 + + + 0.02 + + + + + + + + + 0.024999999999999998 0.04330127018922193 0.0 -1.5707962969925737 -1.0471975511965974 1.047197525387029 + + + 0.005 + 0.17320508075688773 + + + + + + 0.9 + 0.9 + + + + + + 0.024999999999999998 0.04330127018922193 0.0 -1.5707962969925737 -1.0471975511965974 1.047197525387029 + + + 0.005 + 0.17320508075688773 + + + + + + + + + 0.024999999999999998 -0.04330127018922193 0.0 1.5707962969925737 -1.0471975511965974 -1.047197525387029 + + + 0.005 + 0.17320508075688773 + + + + + + 0.9 + 0.9 + + + + + + 0.024999999999999998 -0.04330127018922193 0.0 1.5707962969925737 -1.0471975511965974 -1.047197525387029 + + + 0.005 + 0.17320508075688773 + + + + + + + + + -0.049999999999999996 0.08660254037844387 0 0 0 0 + + + 0.02 + + + + + + 0.9 + 0.9 + 1 0 0 + + + + + + -0.049999999999999996 0.08660254037844387 0 0 0 0 + + + 0.02 + + + + + + + + + -0.049999999999999996 0.0 0.0 1.5707963267948963 -0.0 0.0 + + + 0.005 + 0.17320508075688773 + + + + + + 0.9 + 0.9 + + + + + + -0.049999999999999996 0.0 0.0 1.5707963267948963 -0.0 0.0 + + + 0.005 + 0.17320508075688773 + + + + + + + + + -0.049999999999999996 -0.08660254037844387 0 0 0 0 + + + 0.02 + + + + + + 0.9 + 0.9 + 1 0 0 + + + + + + -0.049999999999999996 -0.08660254037844387 0 0 0 0 + + + 0.02 + + + + + + + + + + 0 15 0 + 0 0 140.625 + + + + + + + 9.6 0 0 0 0 0 + + 0 0 0.02 0 0 0 + + 0.0 0.0 0 0 0 0 + 0.060318578948924034 + + 0.000311243867376448 + 0.000311243867376448 + 0.0006128367621210681 + 0.0 + 0.0 + 0.0 + + + + true + + + + 0.09999999999999999 0 0 0 0 0 + + + 0.02 + + + + + + 0.9 + 0.9 + 1 0 0 + + + + + + 0.09999999999999999 0 0 0 0 0 + + + 0.02 + + + + + + + + + 0.024999999999999998 0.04330127018922193 0.0 -1.5707962969925737 -1.0471975511965974 1.047197525387029 + + + 0.005 + 0.17320508075688773 + + + + + + 0.9 + 0.9 + + + + + + 0.024999999999999998 0.04330127018922193 0.0 -1.5707962969925737 -1.0471975511965974 1.047197525387029 + + + 0.005 + 0.17320508075688773 + + + + + + + + + 0.024999999999999998 -0.04330127018922193 0.0 1.5707962969925737 -1.0471975511965974 -1.047197525387029 + + + 0.005 + 0.17320508075688773 + + + + + + 0.9 + 0.9 + + + + + + 0.024999999999999998 -0.04330127018922193 0.0 1.5707962969925737 -1.0471975511965974 -1.047197525387029 + + + 0.005 + 0.17320508075688773 + + + + + + + + + -0.049999999999999996 0.08660254037844387 0 0 0 0 + + + 0.02 + + + + + + 0.9 + 0.9 + 1 0 0 + + + + + + -0.049999999999999996 0.08660254037844387 0 0 0 0 + + + 0.02 + + + + + + + + + -0.049999999999999996 0.0 0.0 1.5707963267948963 -0.0 0.0 + + + 0.005 + 0.17320508075688773 + + + + + + 0.9 + 0.9 + + + + + + -0.049999999999999996 0.0 0.0 1.5707963267948963 -0.0 0.0 + + + 0.005 + 0.17320508075688773 + + + + + + + + + -0.049999999999999996 -0.08660254037844387 0 0 0 0 + + + 0.02 + + + + + + 0.9 + 0.9 + 1 0 0 + + + + + + -0.049999999999999996 -0.08660254037844387 0 0 0 0 + + + 0.02 + + + + + + + + + + 0 15 0 + 0 0 150.0 + + + + + + + 1.5 -4 2.5 0 0.5 1.6 + orbit + + + + + diff --git a/worlds/triball_contact.world.erb b/worlds/triball_contact.world.erb new file mode 100644 index 0000000..496a1e6 --- /dev/null +++ b/worlds/triball_contact.world.erb @@ -0,0 +1,1436 @@ + + +<% + # default values + unless defined?(frictionModel) + frictionModel = "pyramid_model" + end + + unless defined?(complex) + complex = 1 + end + + unless defined?(surfaceSlope) + surfaceSlope = 0 + end + + unless defined?(frictionCoefficient) + frictionCoefficient = 0.9 + end + + unless defined?(cogH) + cogH = 0 + end + + unless defined?(equalKE) + equalKE = 0 + end + + def get_velocities(energy) + linear_vel = [] + angular_vel = [] + mass = 0.060318578948924034 + izz = 0.0006128367621210681 + for i in 1..10 + v = Math.sqrt(i * 2 * energy / (mass*10)) + + linear_vel.insert(i -1, v) + + w = Math.sqrt((10 - i) * 2 * energy / (izz*10)) + angular_vel.insert(i -1, w) + + if i !=10 + linear_vel.insert(i - 1, v) + w = - w + angular_vel.insert(i - 1, w) + end + end + [linear_vel, angular_vel] + end + + require "matrix" + + v0 = [0, 15, 0] # linear velocity along y axis + N = 9 + w0max = 150.0 + w0mags = w0max * Vector.elements((-N..N).to_a) / N.to_f # angular velocity along z axis + + mass = 0.060318578948924034 + Izz = 0.0006128367621210681 + initial_energy = 0.5 * mass * v0.map {|x| x*x }.sum + if equalKE.to_i == 1 + v, w0mags = get_velocities(initial_energy) + end + + + gravity = [-9.8*Math::sin(surfaceSlope.to_f), 0, -9.8*Math::cos(surfaceSlope.to_f)] + +%> + + + + + <%= gravity.join(" ") %> + + + model://ground_plane + + + + model://sun + + + + + + <%= frictionModel %> + + + + +<% + if complex.to_i == 0 +%> + + + + 0 0 0 0 0 0 + + 0 0 0.02 0 0 0 + + 0.0022414159556670668 0 <%= cogH %> 0 0 0 + 0.078742493606727915 + + 8.4732487219449371e-05 + -1.3552527156068805e-20 + 2.5214795814616026e-21 + 0.00035705300836722431 + 4.4766275773390029e-22 + 0.00043190422402162329 + + + + + true + + + + 0.09999999999999999 0 0 0 0 0 + + + 0.02 + + + + + + <%= frictionCoefficient %> + <%= frictionCoefficient %> + 1 0 0 + + + + + + 0.09999999999999999 0 0 0 0 0 + + + 0.02 + + + + + + + + + 0.024999999999999998 0.0200961894323342 0.0 -1.5707963267948961 -1.3089969389957472 1.3089969389957468 + + + 0.005 + 0.15529142706151244 + + + + + + <%= frictionCoefficient %> + <%= frictionCoefficient %> + + + + + + 0.024999999999999998 0.0200961894323342 0.0 -1.5707963267948961 -1.3089969389957472 1.3089969389957468 + + + 0.005 + 0.15529142706151244 + + + + + + + + + 0.024999999999999998 -0.0200961894323342 0.0 1.5707963267948961 -1.3089969389957472 -1.3089969389957468 + + + 0.005 + 0.15529142706151244 + + + + + + <%= frictionCoefficient %> + <%= frictionCoefficient %> + + + + + + 0.024999999999999998 -0.0200961894323342 0.0 1.5707963267948961 -1.3089969389957472 -1.3089969389957468 + + + 0.005 + 0.15529142706151244 + + + + + + + + + -0.049999999999999996 0.0401923788646684 0 0 0 0 + + + 0.02 + + + + + + <%= frictionCoefficient %> + <%= frictionCoefficient %> + 1 0 0 + + + + + + -0.049999999999999996 0.0401923788646684 0 0 0 0 + + + 0.02 + + + + + + + + + -0.049999999999999996 0.0 0.0 1.5707963267948963 -0.0 0.0 + + + 0.005 + 0.0803847577293368 + + + + + + <%= frictionCoefficient %> + <%= frictionCoefficient %> + + + + + + -0.049999999999999996 0.0 0.0 1.5707963267948963 -0.0 0.0 + + + 0.005 + 0.0803847577293368 + + + + + + + + + -0.049999999999999996 -0.0401923788646684 0 0 0 0 + + + 0.02 + + + + + + <%= frictionCoefficient %> + <%= frictionCoefficient %> + 1 0 0 + + + + + + -0.049999999999999996 -0.0401923788646684 0 0 0 0 + + + 0.02 + + + + + + + + + + + + 0 1 0 0 0 0 + + 0 0 0.02 0 0 0 + + 0.0011016530914522173 0 <%= cogH %> 0 0 0 + 0.081476344460819278 + + 0.00019232606045470671 + 1.3552527156068805e-20 + 1.2627017167609311e-20 + 0.00036422223881746503 + 1.6650309163384415e-21 + 0.0005466328545714452 + + + + + true + + + + 0.09999999999999999 0 0 0 0 0 + + + 0.02 + + + + + + <%= frictionCoefficient %> + <%= frictionCoefficient %> + 1 0 0 + + + + + + 0.09999999999999999 0 0 0 0 0 + + + 0.02 + + + + + + + + + 0.024999999999999998 0.031066017177982127 0.0 -1.5707963267948961 -1.1780972450961724 1.1780972450961718 + + + 0.005 + 0.1623588300438591 + + + + + + <%= frictionCoefficient %> + <%= frictionCoefficient %> + + + + + + 0.024999999999999998 0.031066017177982127 0.0 -1.5707963267948961 -1.1780972450961724 1.1780972450961718 + + + 0.005 + 0.1623588300438591 + + + + + + + + + 0.024999999999999998 -0.031066017177982127 0.0 1.5707963267948961 -1.1780972450961724 -1.1780972450961718 + + + 0.005 + 0.1623588300438591 + + + + + + <%= frictionCoefficient %> + <%= frictionCoefficient %> + + + + + + 0.024999999999999998 -0.031066017177982127 0.0 1.5707963267948961 -1.1780972450961724 -1.1780972450961718 + + + 0.005 + 0.1623588300438591 + + + + + + + + + -0.049999999999999996 0.062132034355964254 0 0 0 0 + + + 0.02 + + + + + + <%= frictionCoefficient %> + <%= frictionCoefficient %> + 1 0 0 + + + + + + -0.049999999999999996 0.062132034355964254 0 0 0 0 + + + 0.02 + + + + + + + + + -0.049999999999999996 0.0 0.0 1.5707963267948963 -0.0 0.0 + + + 0.005 + 0.12426406871192851 + + + + + + <%= frictionCoefficient %> + <%= frictionCoefficient %> + + + + + + -0.049999999999999996 0.0 0.0 1.5707963267948963 -0.0 0.0 + + + 0.005 + 0.12426406871192851 + + + + + + + + + -0.049999999999999996 -0.062132034355964254 0 0 0 0 + + + 0.02 + + + + + + <%= frictionCoefficient %> + <%= frictionCoefficient %> + 1 0 0 + + + + + + -0.049999999999999996 -0.062132034355964254 0 0 0 0 + + + 0.02 + + + + + + + + + + + + + 0 2 0.02 0 0 0 + + 0.0 0.0 <%= cogH %> 0 0 0 + 0.060318578948924034 + + 0.000311243867376448 + 0.000311243867376448 + 0.0006128367621210681 + 0.0 + 0.0 + 0.0 + + + + true + + + + 0.09999999999999999 0 0 0 0 0 + + + 0.02 + + + + + + <%= frictionCoefficient %> + <%= frictionCoefficient %> + 1 0 0 + + + + + + 0.09999999999999999 0 0 0 0 0 + + + 0.02 + + + + + + + + + 0.024999999999999998 0.04330127018922193 0.0 -1.5707962969925737 -1.0471975511965974 1.047197525387029 + + + 0.005 + 0.17320508075688773 + + + + + + <%= frictionCoefficient %> + <%= frictionCoefficient %> + + + + + + 0.024999999999999998 0.04330127018922193 0.0 -1.5707962969925737 -1.0471975511965974 1.047197525387029 + + + 0.005 + 0.17320508075688773 + + + + + + + + + 0.024999999999999998 -0.04330127018922193 0.0 1.5707962969925737 -1.0471975511965974 -1.047197525387029 + + + 0.005 + 0.17320508075688773 + + + + + + <%= frictionCoefficient %> + <%= frictionCoefficient %> + + + + + + 0.024999999999999998 -0.04330127018922193 0.0 1.5707962969925737 -1.0471975511965974 -1.047197525387029 + + + 0.005 + 0.17320508075688773 + + + + + + + + + -0.049999999999999996 0.08660254037844387 0 0 0 0 + + + 0.02 + + + + + + <%= frictionCoefficient %> + <%= frictionCoefficient %> + 1 0 0 + + + + + + -0.049999999999999996 0.08660254037844387 0 0 0 0 + + + 0.02 + + + + + + + + + -0.049999999999999996 0.0 0.0 1.5707963267948963 -0.0 0.0 + + + 0.005 + 0.17320508075688773 + + + + + + <%= frictionCoefficient %> + <%= frictionCoefficient %> + + + + + + -0.049999999999999996 0.0 0.0 1.5707963267948963 -0.0 0.0 + + + 0.005 + 0.17320508075688773 + + + + + + + + + -0.049999999999999996 -0.08660254037844387 0 0 0 0 + + + 0.02 + + + + + + <%= frictionCoefficient %> + <%= frictionCoefficient %> + 1 0 0 + + + + + + -0.049999999999999996 -0.08660254037844387 0 0 0 0 + + + 0.02 + + + + + + + + + + + + 0 3 0 0 0 0 + + 0 0 0.02 0 0 0 + + -0.0010889786320120855 0 <%= cogH %> 0 0 0 + 0.088985917618018107 + + 0.00066921849216050014 + 2.7105054312137611e-20 + -3.3685125287159029e-21 + 0.00038309493110161302 + 1.0621606046267175e-20 + 0.0010423041088969216 + + + + true + + + + 0.09999999999999999 0 0 0 0 0 + + + 0.02 + + + + + + <%= frictionCoefficient %> + <%= frictionCoefficient %> + 1 0 0 + + + + + + 0.09999999999999999 0 0 0 0 0 + + + 0.02 + + + + + + + + + 0.024999999999999998 0.057549524098422025 0.0 -1.5707963267948963 -0.9162978572970228 0.9162978572970227 + + + 0.005 + 0.18907086210153967 + + + + + + <%= frictionCoefficient %> + <%= frictionCoefficient %> + + + + + + 0.024999999999999998 0.057549524098422025 0.0 -1.5707963267948963 -0.9162978572970228 0.9162978572970227 + + + 0.005 + 0.18907086210153967 + + + + + + + + + 0.024999999999999998 -0.057549524098422025 0.0 1.5707963267948963 -0.9162978572970228 -0.9162978572970227 + + + 0.005 + 0.18907086210153967 + + + + + + <%= frictionCoefficient %> + <%= frictionCoefficient %> + + + + + + 0.024999999999999998 -0.057549524098422025 0.0 1.5707963267948963 -0.9162978572970228 -0.9162978572970227 + + + 0.005 + 0.18907086210153967 + + + + + + + + + -0.049999999999999996 0.11509904819684405 0 0 0 0 + + + 0.02 + + + + + + <%= frictionCoefficient %> + <%= frictionCoefficient %> + 1 0 0 + + + + + + -0.049999999999999996 0.11509904819684405 0 0 0 0 + + + 0.02 + + + + + + + + + -0.049999999999999996 0.0 0.0 1.5707963267948963 -0.0 0.0 + + + 0.005 + 0.2301980963936881 + + + + + + <%= frictionCoefficient %> + <%= frictionCoefficient %> + + + + + + -0.049999999999999996 0.0 0.0 1.5707963267948963 -0.0 0.0 + + + 0.005 + 0.2301980963936881 + + + + + + + + + -0.049999999999999996 -0.11509904819684405 0 0 0 0 + + + 0.02 + + + + + + <%= frictionCoefficient %> + <%= frictionCoefficient %> + 1 0 0 + + + + + + -0.049999999999999996 -0.11509904819684405 0 0 0 0 + + + 0.02 + + + + + + + + + + + + 0 4 0 0 0 0 + + 0 0 0.02 0 0 0 + + -0.0021920256670695452 0 <%= cogH %> 0 0 0 + 0.094448719111790758 + + 0.0011706814995045239 + 2.7105054312137611e-20 + -3.3881317890172014e-21 + 0.00039647954261617555 + 2.3523493101256951e-20 + 0.0015570834427368358 + + + + + true + + + + 0.09999999999999999 0 0 0 0 0 + + + 0.02 + + + + + + <%= frictionCoefficient %> + <%= frictionCoefficient %> + 1 0 0 + + + + + + 0.09999999999999999 0 0 0 0 0 + + + 0.02 + + + + + + + + + 0.024999999999999998 0.07499999999999998 0.0 -1.5707963267948963 -0.7853981633974484 0.7853981633974483 + + + 0.005 + 0.21213203435596423 + + + + + + <%= frictionCoefficient %> + <%= frictionCoefficient %> + + + + + + 0.024999999999999998 0.07499999999999998 0.0 -1.5707963267948963 -0.7853981633974484 0.7853981633974483 + + + 0.005 + 0.21213203435596423 + + + + + + + + + 0.024999999999999998 -0.07499999999999998 0.0 1.5707963267948963 -0.7853981633974484 -0.7853981633974483 + + + 0.005 + 0.21213203435596423 + + + + + + <%= frictionCoefficient %> + <%= frictionCoefficient %> + + + + + + 0.024999999999999998 -0.07499999999999998 0.0 1.5707963267948963 -0.7853981633974484 -0.7853981633974483 + + + 0.005 + 0.21213203435596423 + + + + + + + + + -0.049999999999999996 0.14999999999999997 0 0 0 0 + + + 0.02 + + + + + + <%= frictionCoefficient %> + <%= frictionCoefficient %> + 1 0 0 + + + + + + -0.049999999999999996 0.14999999999999997 0 0 0 0 + + + 0.02 + + + + + + + + + -0.049999999999999996 0.0 0.0 1.5707963267948963 -0.0 0.0 + + + 0.005 + 0.29999999999999993 + + + + + + <%= frictionCoefficient %> + <%= frictionCoefficient %> + + + + + + -0.049999999999999996 0.0 0.0 1.5707963267948963 -0.0 0.0 + + + 0.005 + 0.29999999999999993 + + + + + + + + + -0.049999999999999996 -0.14999999999999997 0 0 0 0 + + + 0.02 + + + + + + <%= frictionCoefficient %> + <%= frictionCoefficient %> + 1 0 0 + + + + + + -0.049999999999999996 -0.14999999999999997 0 0 0 0 + + + 0.02 + + + + + + + + + + +<% + else + w0mags.to_a.each_index do |i| + name = "triball_" + i.to_s + if equalKE.to_i == 1 + v0 = [0, v[i], 0] + w0 = [0, 0, w0mags[i]] + else + w0 = [0, 0, w0mags[i]] + end + + x0 = 0.3 * i +%> + + + <%= x0 %> 0 0 0 0 0 + + 0 0 0.02 0 0 0 + + 0.0 0.0 <%= cogH %> 0 0 0 + 0.060318578948924034 + + 0.000311243867376448 + 0.000311243867376448 + 0.0006128367621210681 + 0.0 + 0.0 + 0.0 + + + + true + + + + 0.09999999999999999 0 0 0 0 0 + + + 0.02 + + + + + + <%= frictionCoefficient %> + <%= frictionCoefficient %> + 1 0 0 + + + + + + 0.09999999999999999 0 0 0 0 0 + + + 0.02 + + + + + + + + + 0.024999999999999998 0.04330127018922193 0.0 -1.5707962969925737 -1.0471975511965974 1.047197525387029 + + + 0.005 + 0.17320508075688773 + + + + + + <%= frictionCoefficient %> + <%= frictionCoefficient %> + + + + + + 0.024999999999999998 0.04330127018922193 0.0 -1.5707962969925737 -1.0471975511965974 1.047197525387029 + + + 0.005 + 0.17320508075688773 + + + + + + + + + 0.024999999999999998 -0.04330127018922193 0.0 1.5707962969925737 -1.0471975511965974 -1.047197525387029 + + + 0.005 + 0.17320508075688773 + + + + + + <%= frictionCoefficient %> + <%= frictionCoefficient %> + + + + + + 0.024999999999999998 -0.04330127018922193 0.0 1.5707962969925737 -1.0471975511965974 -1.047197525387029 + + + 0.005 + 0.17320508075688773 + + + + + + + + + -0.049999999999999996 0.08660254037844387 0 0 0 0 + + + 0.02 + + + + + + <%= frictionCoefficient %> + <%= frictionCoefficient %> + 1 0 0 + + + + + + -0.049999999999999996 0.08660254037844387 0 0 0 0 + + + 0.02 + + + + + + + + + -0.049999999999999996 0.0 0.0 1.5707963267948963 -0.0 0.0 + + + 0.005 + 0.17320508075688773 + + + + + + <%= frictionCoefficient %> + <%= frictionCoefficient %> + + + + + + -0.049999999999999996 0.0 0.0 1.5707963267948963 -0.0 0.0 + + + 0.005 + 0.17320508075688773 + + + + + + + + + -0.049999999999999996 -0.08660254037844387 0 0 0 0 + + + 0.02 + + + + + + <%= frictionCoefficient %> + <%= frictionCoefficient %> + 1 0 0 + + + + + + -0.049999999999999996 -0.08660254037844387 0 0 0 0 + + + 0.02 + + + + + + + + + + <%= v0.join(" ") %> + <%= w0.join(" ") %> + + + +<% + end + end +%> + + + 1.5 -4 2.5 0 0.5 1.6 + orbit + + + + +