/* * Copyright (C) 2016 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 "gazebo/physics/physics.hh" #include "gazebo/test/ServerFixture.hh" #include "gazebo/test/helper_physics_generator.hh" #include "gazebo/transport/Publisher.hh" using namespace gazebo; class KeysToJoints : public ServerFixture, public testing::WithParamInterface { /// \brief Key to joint position /// \param[in] _physicsEngine Physics engine to use. public: void Position(const std::string &_physicsEngine); /// \brief Key to joint velocity /// \param[in] _physicsEngine Physics engine to use. public: void Velocity(const std::string &_physicsEngine); /// \brief Key to joint force /// \param[in] _physicsEngine Physics engine to use. public: void Force(const std::string &_physicsEngine); /// \brief One key to many joints /// \param[in] _physicsEngine Physics engine to use. public: void MultipleJoints(const std::string &_physicsEngine); }; //////////////////////////////////////////////////////////////////////// void KeysToJoints::Position(const std::string &_physicsEngine) { this->Load("worlds/keys_to_joints.world", false, _physicsEngine); auto world = physics::get_world(); ASSERT_NE(world , nullptr); auto model = world->GetModel("position_teleop"); ASSERT_NE(model, nullptr); // Setup keyboard publisher auto keyboardPub = this->node->Advertise("~/keyboard/keypress"); // Position teleop auto joint = model->GetJoint("joint"); ASSERT_NE(joint, nullptr); // Trigger key to increase position double target = joint->GetAngle(0).Radian() + 0.05; msgs::Any msg; msg.set_type(msgs::Any_ValueType_INT32); msg.set_int_value(106); keyboardPub->Publish(msg); int maxSleep = 50; int sleep = 0; while (joint->GetAngle(0).Radian() < target && sleep < maxSleep) { common::Time::MSleep(100); ++sleep; } EXPECT_GT(joint->GetAngle(0).Radian(), target); // Trigger key to decrease position target = joint->GetAngle(0).Radian() - 0.05; msg.set_int_value(117); keyboardPub->Publish(msg); sleep = 0; while (joint->GetAngle(0).Radian() > target && sleep < maxSleep) { common::Time::MSleep(100); ++sleep; } EXPECT_LT(joint->GetAngle(0).Radian(), target); } TEST_P(KeysToJoints, Position) { const std::string physicsEngine = GetParam(); Position(physicsEngine); } //////////////////////////////////////////////////////////////////////// void KeysToJoints::Velocity(const std::string &_physicsEngine) { this->Load("worlds/keys_to_joints.world", false, _physicsEngine); auto world = physics::get_world(); ASSERT_NE(world , nullptr); auto model = world->GetModel("velocity_teleop"); ASSERT_NE(model, nullptr); // Setup keyboard publisher auto keyboardPub = this->node->Advertise("~/keyboard/keypress"); // Velocity teleop auto joint = model->GetJoint("joint"); ASSERT_NE(joint, nullptr); // Trigger key to have a positive velocity double target = 0.29; msgs::Any msg; msg.set_type(msgs::Any_ValueType_INT32); msg.set_int_value(107); keyboardPub->Publish(msg); int maxSleep = 50; int sleep = 0; while (joint->GetVelocity(0) < target && sleep < maxSleep) { common::Time::MSleep(100); ++sleep; } EXPECT_GT(joint->GetVelocity(0), target); // Trigger key to stop double tol = 1e-5; msg.set_int_value(105); keyboardPub->Publish(msg); sleep = 0; while (std::abs(joint->GetVelocity(0)) > tol && sleep < maxSleep) { common::Time::MSleep(100); ++sleep; } EXPECT_LT(std::abs(joint->GetVelocity(0)), tol); // Trigger key to have a negative velocity msg.set_int_value(56); keyboardPub->Publish(msg); sleep = 0; while (joint->GetVelocity(0) > -target && sleep < maxSleep) { common::Time::MSleep(100); ++sleep; } EXPECT_LT(joint->GetVelocity(0), -target); } TEST_P(KeysToJoints, Velocity) { const std::string physicsEngine = GetParam(); Velocity(physicsEngine); } //////////////////////////////////////////////////////////////////////// void KeysToJoints::Force(const std::string &_physicsEngine) { this->Load("worlds/keys_to_joints.world", false, _physicsEngine); auto world = physics::get_world(); ASSERT_NE(world , nullptr); auto model = world->GetModel("force_teleop"); ASSERT_NE(model, nullptr); // Setup keyboard publisher auto keyboardPub = this->node->Advertise("~/keyboard/keypress"); // Force teleop auto joint = model->GetJoint("joint"); ASSERT_NE(joint, nullptr); // Trigger key to push in positive direction double target = joint->GetAngle(0).Radian() + 0.1; msgs::Any msg; msg.set_type(msgs::Any_ValueType_INT32); msg.set_int_value(108); keyboardPub->Publish(msg); // DART only responds after a few clicks: issue #2091 if (_physicsEngine == "dart") { for (int i = 0; i < 5; ++i) keyboardPub->Publish(msg); } int maxSleep = 50; int sleep = 0; while (joint->GetAngle(0).Radian() < target && sleep < maxSleep) { common::Time::MSleep(100); ++sleep; } EXPECT_GT(joint->GetAngle(0).Radian(), target); // Trigger key to stop if (_physicsEngine == "dart") { gzerr << "Skipping rest of test for [dart] due to issue #2091" << std::endl; return; } double tol = 0.1; msg.set_int_value(111); keyboardPub->Publish(msg); sleep = 0; while (std::abs(joint->GetVelocity(0)) > tol && sleep < maxSleep) { common::Time::MSleep(100); ++sleep; } EXPECT_LT(std::abs(joint->GetVelocity(0)), tol); } TEST_P(KeysToJoints, Force) { const std::string physicsEngine = GetParam(); if (physicsEngine == "simbody") { gzerr << "Skipping test for [" << physicsEngine << "] due to Joint::SetForce, see issue #2092" << std::endl; return; } if (physicsEngine == "bullet") { gzerr << "Skipping test for [" << physicsEngine << "] because of thread safety, see issue #2098" << std::endl; return; } Force(physicsEngine); } //////////////////////////////////////////////////////////////////////// void KeysToJoints::MultipleJoints(const std::string &_physicsEngine) { this->Load("worlds/keys_to_joints.world", false, _physicsEngine); auto world = physics::get_world(); ASSERT_NE(world , nullptr); auto model = world->GetModel("multiple_teleop"); ASSERT_NE(model, nullptr); // Setup keyboard publisher auto keyboardPub = this->node->Advertise("~/keyboard/keypress"); // MultipleJoints teleop auto joint2 = model->GetJoint("joint_2"); ASSERT_NE(joint2, nullptr); auto joint3 = model->GetJoint("joint_3"); ASSERT_NE(joint3, nullptr); // Trigger a single key which increases joint2 and decreases joint3 double target2 = joint2->GetAngle(0).Radian() + 0.05; double target3 = joint3->GetAngle(0).Radian() - 0.05; msgs::Any msg; msg.set_type(msgs::Any_ValueType_INT32); msg.set_int_value(59); keyboardPub->Publish(msg); int maxSleep = 50; int sleep = 0; while (joint2->GetAngle(0).Radian() < target2 && joint3->GetAngle(0).Radian() > target3 && sleep < maxSleep) { common::Time::MSleep(100); ++sleep; } EXPECT_GT(joint2->GetAngle(0).Radian(), target2); EXPECT_LT(joint3->GetAngle(0).Radian(), target3); } TEST_P(KeysToJoints, MultipleJoints) { const std::string physicsEngine = GetParam(); MultipleJoints(physicsEngine); } INSTANTIATE_TEST_CASE_P(PhysicsEngines, KeysToJoints, PHYSICS_ENGINE_VALUES); int main(int argc, char **argv) { ::testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); }