1 // =============================================================================
2 // PROJECT CHRONO - http://projectchrono.org
3 //
4 // Copyright (c) 2020 projectchrono.org
5 // All right reserved.
6 //
7 // Use of this source code is governed by a BSD-style license that can be found
8 // in the LICENSE file at the top level of the distribution and at
9 // http://projectchrono.org/license-chrono.txt.
10 //
11 // =============================================================================
12 // Authors: Radu Serban
13 // =============================================================================
14 //
15 // Definition of the base vehicle co-simulation TERRAIN NODE class.
16 //
17 // The global reference frame has Z up, X towards the front of the vehicle, and
18 // Y pointing to the left.
19 //
20 // =============================================================================
21 
22 #ifndef CH_VEHCOSIM_TERRAIN_NODE_H
23 #define CH_VEHCOSIM_TERRAIN_NODE_H
24 
25 #include "chrono/ChConfig.h"
26 
27 #include "chrono_vehicle/ChSubsysDefs.h"
28 #include "chrono_vehicle/ChPart.h"
29 #include "chrono_vehicle/cosim/ChVehicleCosimBaseNode.h"
30 
31 #include "chrono_thirdparty/rapidjson/document.h"
32 
33 namespace chrono {
34 namespace vehicle {
35 
36 /// @addtogroup vehicle_cosim
37 /// @{
38 
39 /// Base class for a terrain node.
40 /// Implements required functionality for a co-simulation node (Initialize(), Synchronize(), Advance()) and all MPI
41 /// communication.
42 ///
43 /// A derived class must implement functions to:
44 /// - specify the communication interface type (SupportsMeshInterface())
45 /// - construct and initialize the concrete terrain object (OnInitialize())
46 /// - accept new spindle body states (UpdateWheelProxy() and/or UpdateMeshProxies())
47 /// - provide terrain forces acting on the spindle bodies (GetForceWheelProxy() and/or GetForcesMeshProxies())
48 /// - advance the dynamic state of the terrain (OnAdvance())
49 ///
50 /// Optionally, a derived class may implement functions to:
51 /// - perform additional operations after a synchronization data exchange (OnSynchronize())
52 /// - perform additional data output (OnOutputData())
53 /// - provide run-time visualization (Render())
54 class CH_VEHICLE_API ChVehicleCosimTerrainNode : public ChVehicleCosimBaseNode {
55   public:
~ChVehicleCosimTerrainNode()56     virtual ~ChVehicleCosimTerrainNode() {}
57 
58     /// Return the node type as NodeType::TERRAIN.
GetNodeType()59     virtual NodeType GetNodeType() const override { return NodeType::TERRAIN; }
60 
61     /// Enable/disable run-time visualization (default: false).
62     /// If enabled, rendering is done with the specified frequency.
63     /// Note that a particular concrete terrain node may not support run-time visualization or may not render all
64     /// physics elements.
65     void EnableRuntimeVisualization(bool render, double render_fps = 100);
66 
67     /// Set the terrain patch dimensions.
68     /// If invoked, this function must be called before Initialize.
69     void SetDimensions(double length, double width);
70 
71     /// Initialize this node.
72     /// This function allows the node to initialize itself and, optionally, perform an
73     /// initial data exchange with any other node.
74     virtual void Initialize() override final;
75 
76     /// Synchronize this node.
77     /// This function is called at every co-simulation synchronization time to
78     /// allow the node to exchange information with any other node.
79     virtual void Synchronize(int step_number, double time) override final;
80 
81     /// Advance simulation.
82     /// This function is called after a synchronization to allow the node to advance
83     /// its state by the specified time step.  A node is allowed to take as many internal
84     /// integration steps as required, but no inter-node communication should occur.
85     virtual void Advance(double step_size) override final;
86 
87     /// Output logging and debugging data.
88     virtual void OutputData(int frame) override final;
89 
90     /// Output post-processing visualization data.
91     /// If implemented, this function should write a file in the "visualization" subdirectory of m_node_out_dir.
OutputVisualizationData(int frame)92     virtual void OutputVisualizationData(int frame) override {}
93 
94     /// Return current number of contacts.
95     /// (concrete terrain specific)
GetNumContacts()96     virtual int GetNumContacts() const { return 0; }
97 
98   protected:
99     /// Construct a terrain node to wrap a terrain patch of given length and width.
100     ChVehicleCosimTerrainNode(double length, double width);
101 
102     // ------------------------- Virtual methods
103 
104     /// Specify whether or not the terrain node supports the MESH communication interface.
105     /// See ChVehicleCosimBaseNode::InterfaceType.
106     /// A terrain that also supports the MESH communication interface must override the functions UpdateMeshProxies()
107     /// and GetForcesMeshProxies().
108     virtual bool SupportsMeshInterface() const = 0;
109 
110     /// Return the terrain initial height.
111     /// This value must be available before the call to Initialize() (and therefore, before the derived class's
112     /// OnInitialize() is called).
113     virtual double GetInitHeight() const = 0;
114 
115     /// Perform any additional operations after the initial data exchange with the MBS node, including creating any
116     /// required proxies for the specified number of tires. A derived class has access to the following vectors (of size
117     /// equal to the number of tires):
118     /// - radius for each tire (through m_tire_radius)
119     /// - width for each tire (through m_tire_width)
120     /// - mesh information for each tire (through m_mesh_data)
121     /// - contact material for each tire (through m_mat_props)
122     /// - vertical load on each tire (through m_load_mass)
123     virtual void OnInitialize(unsigned int num_tires) = 0;
124 
125     /// Perform any additional operations after the data exchange and synchronization with the MBS node. A derived class
126     /// has access to the following vectors (of size equal to the number of tires):
127     /// - full dynamic state of the spindle bodies (through m_spindle_state) when using the BODY communication interface
128     /// - state of the mesh vertices (through m_mesh_state) when using the MESH communication interface
OnSynchronize(int step_number,double time)129     virtual void OnSynchronize(int step_number, double time) {}
130 
131     /// Advance the state of the terrain system by the specified step.
132     virtual void OnAdvance(double step_size) = 0;
133 
134     /// Perform additional output at the specified frame (called from within OutputData).
OnOutputData(int frame)135     virtual void OnOutputData(int frame) {}
136 
137     /// Render simulation.
138     /// This function is called from Advance() at the frequency spoecified in the call to EnableRuntimeVisualization().
139     /// Any call to Render occurs after a call to OnAdvance().
Render(double time)140     virtual void Render(double time) {}
141 
142     // ------------------------- Virtual methods for the MESH communication interface
143     // A derived class must implement these methods if SupportsMeshInterface returns true.
144 
145     /// Update the state of all proxy bodies for the i-th tire mesh.
146     /// Use information in the provided MeshState struct (vertex positions and velocities expressed in absolute frame).
UpdateMeshProxies(unsigned int i,MeshState & mesh_state)147     virtual void UpdateMeshProxies(unsigned int i, MeshState& mesh_state) {
148         if (SupportsMeshInterface()) {
149             throw ChException("Current terrain type does not support the MESH communication interface!");
150         }
151     }
152 
153     /// Collect cumulative contact forces on all proxy bodies for the i-th tire mesh.
154     /// Load indices of vertices in contact and the corresponding vertex forces (expressed in absolute frame)
155     /// into the provided MeshContact struct.
GetForcesMeshProxies(unsigned int i,MeshContact & mesh_contact)156     virtual void GetForcesMeshProxies(unsigned int i, MeshContact& mesh_contact) {
157         if (SupportsMeshInterface()) {
158             throw ChException("Current terrain type does not the MESH communication interface!");
159         }
160     }
161 
162     // ------------------------- Virtual methods for the BODY communication interface
163 
164     /// Update the state of the wheel proxy body for the i-th tire.
165     /// Use information in the provided BodyState struct (pose and velocities expressed in absolute frame).
166     virtual void UpdateWheelProxy(unsigned int i, BodyState& spindle_state) = 0;
167 
168     /// Collect cumulative contact force and torque on the wheel proxy body for the i-th tire.
169     /// Load contact forces (expressed in absolute frame) into the provided TerrainForce struct.
170     virtual void GetForceWheelProxy(unsigned int i, TerrainForce& wheel_contact) = 0;
171 
172   protected:
173     bool m_render;         ///< if true, perform run-time rendering
174     double m_render_step;  ///< time step between rendered frames
175 
176     double m_hdimX;  ///< patch half-length (X direction)
177     double m_hdimY;  ///< patch half-width (Y direction)
178 
179     // Communication data
180 
181     InterfaceType m_interface_type;  ///< type of communication interface
182 
183     std::vector<double> m_tire_radius;       ///< tire radius
184     std::vector<double> m_tire_width;        ///< tire width
185     std::vector<double> m_load_mass;         ///< vertical load on tire
186     std::vector<MaterialInfo> m_mat_props;   ///< tire contact material properties
187     std::vector<MeshData> m_mesh_data;       ///< tire mesh data
188     std::vector<MeshState> m_mesh_state;     ///< tire mesh state (used for MESH communication)
189     std::vector<BodyState> m_spindle_state;  ///< spindle state (used for BODY communication interface)
190 
191   private:
192     void SynchronizeBody(int step_number, double time);
193     void SynchronizeMesh(int step_number, double time);
194 
195     /// Print vertex and face connectivity data for the i-th tire, as received at synchronization.
196     /// Invoked only when using the MESH communicatin interface.
197     void PrintMeshUpdateData(unsigned int i);
198 
199     std::vector<MeshContact> m_mesh_contact;    ///< tire mesh contact forces (used for MESH communication interface)
200     std::vector<TerrainForce> m_wheel_contact;  ///< spindle contact force (used for BODY communication interface)
201 };
202 
203 /// @} vehicle_cosim
204 
205 }  // end namespace vehicle
206 }  // end namespace chrono
207 
208 #endif
209