Skip to content

Commit bbb4bc2

Browse files
authored
Add SmoothSphereHalfSpaceForce component (#2665)
* Add SmoothSphereHalfSpaceForce. * Use sockets for ContactGeometry. * Remove this->, add docs about constant contact force.
1 parent 4d4c4d6 commit bbb4bc2

11 files changed

+703
-1
lines changed

Bindings/OpenSimHeaders_simulation.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929

3030
#include <OpenSim/Simulation/Model/ElasticFoundationForce.h>
3131
#include <OpenSim/Simulation/Model/HuntCrossleyForce.h>
32+
#include <OpenSim/Simulation/Model/SmoothSphereHalfSpaceForce.h>
3233

3334
#include <OpenSim/Simulation/Model/ContactGeometrySet.h>
3435
#include <OpenSim/Simulation/Model/Probe.h>

Bindings/simulation.i

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,7 @@ OpenSim::ModelComponentSet<OpenSim::Controller>;
120120
%include <OpenSim/Simulation/Model/ContactSphere.h>
121121
%include <OpenSim/Simulation/Model/ElasticFoundationForce.h>
122122
%include <OpenSim/Simulation/Model/HuntCrossleyForce.h>
123+
%include <OpenSim/Simulation/Model/SmoothSphereHalfSpaceForce.h>
123124

124125
%include <OpenSim/Simulation/Model/Actuator.h>
125126
%template(SetActuators) OpenSim::Set<OpenSim::Actuator, OpenSim::Object>;

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ v4.1
2525
- Updated the docopt.cpp dependency so that OpenSim can be compiled with Visual C++ from Visual Studio 2019.
2626
- Updated Simbody to 3.7 to fix an issue with the simbody-visualizer on macOS 10.15 Catalina.
2727
- On Mac and Linux, we include a shell script opensim-install-command-line.sh to make OpenSim's command-line tools easily accessible.
28+
- Added the compliant SmoothSphereHalfSpaceForce component, for use with direct collocation and Moco.
2829

2930

3031
Converting from v4.0 to v4.1
Lines changed: 242 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,242 @@
1+
/* -------------------------------------------------------------------------- *
2+
* OpenSim: SmoothSphereHalfSpaceForce.cpp *
3+
* -------------------------------------------------------------------------- *
4+
* Copyright (c) 2017-19 Stanford University and the Authors *
5+
* *
6+
* Author(s): Antoine Falisse, Gil Serrancoli *
7+
* Contributors: Peter Eastman *
8+
* *
9+
* Licensed under the Apache License, Version 2.0 (the "License"); you may *
10+
* not use this file except in compliance with the License. You may obtain a *
11+
* copy of the License at http://www.apache.org/licenses/LICENSE-2.0 *
12+
* *
13+
* Unless required by applicable law or agreed to in writing, software *
14+
* distributed under the License is distributed on an "AS IS" BASIS, *
15+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
16+
* See the License for the specific language governing permissions and *
17+
* limitations under the License. *
18+
* -------------------------------------------------------------------------- */
19+
20+
#include "SmoothSphereHalfSpaceForce.h"
21+
22+
#include <simbody/internal/SmoothSphereHalfSpaceForce.h>
23+
24+
#include <OpenSim/Simulation/Model/Model.h>
25+
26+
using namespace OpenSim;
27+
28+
//=============================================================================
29+
// SMOOTH SPHERE HALF SPACE FORCE
30+
//=============================================================================
31+
// Uses default (compiler-generated) destructor, copy constructor, copy
32+
// assignment operator.
33+
34+
// Default constructor.
35+
SmoothSphereHalfSpaceForce::SmoothSphereHalfSpaceForce() {
36+
constructProperties();
37+
}
38+
39+
// Take over ownership of supplied object.
40+
SmoothSphereHalfSpaceForce::SmoothSphereHalfSpaceForce(const std::string& name,
41+
const ContactSphere& contactSphere,
42+
const ContactHalfSpace& contactHalfSpace) {
43+
setName(name);
44+
connectSocket_sphere(contactSphere);
45+
connectSocket_half_space(contactHalfSpace);
46+
47+
constructProperties();
48+
}
49+
50+
void SmoothSphereHalfSpaceForce::extendAddToSystem(
51+
SimTK::MultibodySystem& system) const {
52+
53+
Super::extendAddToSystem(system);
54+
55+
double stiffness = get_stiffness();
56+
double dissipation = get_dissipation();
57+
double staticFriction = get_static_friction();
58+
double dynamicFriction = get_dynamic_friction();
59+
double viscousFriction = get_viscous_friction();
60+
double transitionVelocity = get_transition_velocity();
61+
double cf = get_constant_contact_force();
62+
double bd = get_hertz_smoothing();
63+
double bv = get_hunt_crossley_smoothing();
64+
65+
SimTK::SmoothSphereHalfSpaceForce force(_model->updForceSubsystem());
66+
67+
const auto& sphere = getConnectee<ContactSphere>("sphere");
68+
const auto& halfSpace = getConnectee<ContactHalfSpace>("half_space");
69+
70+
force.setStiffness(stiffness);
71+
force.setDissipation(dissipation);
72+
force.setStaticFriction(staticFriction);
73+
force.setDynamicFriction(dynamicFriction);
74+
force.setViscousFriction(viscousFriction);
75+
force.setTransitionVelocity(transitionVelocity);
76+
force.setConstantContactForce(cf);
77+
force.setHertzSmoothing(bd);
78+
force.setHuntCrossleySmoothing(bv);
79+
80+
force.setContactSphereBody(sphere.getFrame().getMobilizedBody());
81+
force.setContactSphereLocationInBody(
82+
sphere.getFrame().findTransformInBaseFrame() *
83+
sphere.get_location());
84+
force.setContactSphereRadius(sphere.getRadius());
85+
86+
force.setContactHalfSpaceBody(halfSpace.getFrame().getMobilizedBody());
87+
88+
force.setContactHalfSpaceFrame(
89+
halfSpace.getFrame().findTransformInBaseFrame() *
90+
halfSpace.getTransform());
91+
92+
auto* mutableThis = const_cast<SmoothSphereHalfSpaceForce*>(this);
93+
mutableThis->_index = force.getForceIndex();
94+
}
95+
96+
void OpenSim::SmoothSphereHalfSpaceForce::extendRealizeInstance(
97+
const SimTK::State& state) const {
98+
Super::extendRealizeInstance(state);
99+
if (!getProperty_force_visualization_scale_factor().empty()) {
100+
m_forceVizScaleFactor = get_force_visualization_scale_factor();
101+
} else {
102+
const Model& model = getModel();
103+
const double mass = model.getTotalMass(state);
104+
const double weight = mass * model.getGravity().norm();
105+
m_forceVizScaleFactor = 1 / weight;
106+
}
107+
}
108+
109+
void SmoothSphereHalfSpaceForce::constructProperties() {
110+
constructProperty_stiffness(1.0);
111+
constructProperty_dissipation(0.0);
112+
constructProperty_static_friction(0.0);
113+
constructProperty_dynamic_friction(0.0);
114+
constructProperty_viscous_friction(0.0);
115+
constructProperty_transition_velocity(0.01);
116+
constructProperty_constant_contact_force(1e-5);
117+
constructProperty_hertz_smoothing(300.0);
118+
constructProperty_hunt_crossley_smoothing(50.0);
119+
constructProperty_force_visualization_radius(0.01);
120+
constructProperty_force_visualization_scale_factor();
121+
}
122+
123+
//=============================================================================
124+
// REPORTING
125+
//=============================================================================
126+
// Provide names of the quantities (column labels) of the force value(s)
127+
OpenSim::Array<std::string>
128+
SmoothSphereHalfSpaceForce::getRecordLabels() const {
129+
OpenSim::Array<std::string> labels("");
130+
131+
labels.append(getName() + ".Sphere" + ".force.X");
132+
labels.append(getName() + ".Sphere" + ".force.Y");
133+
labels.append(getName() + ".Sphere" + ".force.Z");
134+
labels.append(getName() + ".Sphere" + ".torque.X");
135+
labels.append(getName() + ".Sphere" + ".torque.Y");
136+
labels.append(getName() + ".Sphere" + ".torque.Z");
137+
138+
labels.append(getName() + ".HalfSpace" + ".force.X");
139+
labels.append(getName() + ".HalfSpace" + ".force.Y");
140+
labels.append(getName() + ".HalfSpace" + ".force.Z");
141+
labels.append(getName() + ".HalfSpace" + ".torque.X");
142+
labels.append(getName() + ".HalfSpace" + ".torque.Y");
143+
labels.append(getName() + ".HalfSpace" + ".torque.Z");
144+
145+
return labels;
146+
}
147+
148+
// Provide the value(s) to be reported that correspond to the labels
149+
OpenSim::Array<double> SmoothSphereHalfSpaceForce::getRecordValues(
150+
const SimTK::State& state) const {
151+
152+
OpenSim::Array<double> values(1);
153+
154+
const auto& sphere = getConnectee<ContactSphere>("sphere");
155+
const auto sphereIdx = sphere.getFrame().getMobilizedBodyIndex();
156+
157+
const auto& halfSpace = getConnectee<ContactHalfSpace>("half_space");
158+
const auto halfSpaceIdx = halfSpace.getFrame().getMobilizedBodyIndex();
159+
160+
const Model& model = getModel();
161+
const auto& forceSubsys = model.getForceSubsystem();
162+
const SimTK::Force& abstractForce = forceSubsys.getForce(_index);
163+
const auto& simtkForce =
164+
static_cast<const SimTK::SmoothSphereHalfSpaceForce&>(
165+
abstractForce);
166+
167+
SimTK::Vector_<SimTK::SpatialVec> bodyForces(0);
168+
SimTK::Vector_<SimTK::Vec3> particleForces(0);
169+
SimTK::Vector mobilityForces(0);
170+
171+
simtkForce.calcForceContribution(
172+
state, bodyForces, particleForces, mobilityForces);
173+
174+
// On sphere
175+
const auto& thisBodyForce1 = bodyForces(sphereIdx);
176+
SimTK::Vec3 forces1 = thisBodyForce1[1];
177+
SimTK::Vec3 torques1 = thisBodyForce1[0];
178+
values.append(3, &forces1[0]);
179+
values.append(3, &torques1[0]);
180+
181+
// On plane
182+
const auto& thisBodyForce2 = bodyForces(halfSpaceIdx);
183+
SimTK::Vec3 forces2 = thisBodyForce2[1];
184+
SimTK::Vec3 torques2 = thisBodyForce2[0];
185+
values.append(3, &forces2[0]);
186+
values.append(3, &torques2[0]);
187+
188+
return values;
189+
}
190+
191+
void SmoothSphereHalfSpaceForce::generateDecorations(bool fixed,
192+
const ModelDisplayHints& hints, const SimTK::State& state,
193+
SimTK::Array_<SimTK::DecorativeGeometry>& geometry) const {
194+
Super::generateDecorations(fixed, hints, state, geometry);
195+
196+
if (!fixed && (state.getSystemStage() >= SimTK::Stage::Dynamics) &&
197+
hints.get_show_forces()) {
198+
// Get the underlying SimTK force element.
199+
const Model& model = getModel();
200+
const auto& forceSubsystem = model.getForceSubsystem();
201+
const SimTK::Force& abstractForce = forceSubsystem.getForce(_index);
202+
const auto& simtkForce =
203+
static_cast<const SimTK::SmoothSphereHalfSpaceForce&>(
204+
abstractForce);
205+
206+
// Compute the body forces.
207+
SimTK::Vector_<SimTK::SpatialVec> bodyForces(0);
208+
SimTK::Vector_<SimTK::Vec3> particleForces(0);
209+
SimTK::Vector mobilityForces(0);
210+
simtkForce.calcForceContribution(
211+
state, bodyForces, particleForces, mobilityForces);
212+
213+
// Get the index to the associated contact sphere.
214+
const auto& sphere = getConnectee<ContactSphere>("sphere");
215+
const auto& sphereIdx = sphere.getFrame().getMobilizedBodyIndex();
216+
217+
// Get the translational force for the contact sphere associated with
218+
// this force element.
219+
const auto& sphereForce = bodyForces(sphereIdx)[1];
220+
221+
// Scale the contact force vector and compute the cylinder length.
222+
const auto& scaledContactForce =
223+
m_forceVizScaleFactor * sphereForce;
224+
const SimTK::Real length(scaledContactForce.norm());
225+
226+
// Compute the force visualization transform.
227+
const SimTK::Vec3 contactSpherePosition =
228+
sphere.getFrame().findStationLocationInGround(
229+
state, sphere.get_location());
230+
const SimTK::Transform forceVizTransform(
231+
SimTK::Rotation(SimTK::UnitVec3(scaledContactForce),
232+
SimTK::YAxis),
233+
contactSpherePosition + scaledContactForce / 2.0);
234+
235+
// Construct the force decoration and add it to the list of geometries.
236+
SimTK::DecorativeCylinder forceViz(get_force_visualization_radius(),
237+
0.5 * length);
238+
forceViz.setTransform(forceVizTransform);
239+
forceViz.setColor(SimTK::Vec3(0.0, 0.6, 0.0));
240+
geometry.push_back(forceViz);
241+
}
242+
}

0 commit comments

Comments
 (0)