Skip to content

Commit 3ca1d2d

Browse files
committed
UPBGE: Implement angular servo control motion logic brick.
Previously the servo control logic brick was able to control only the linear velocity using force. But some users showed that in some non-rare case it could be needed to servo control the angular velocity via torques. To fill this gap, the servo control logic brick exposes a enum named "Servo Type" to select either linear or angular velocity, linear is the default. This option is used in KX_ObjectActuator to compute from linear or angular velocity a force or torque. Note: The reference object in case of angular velocity is just used to substract its angular velocity contrary to linear velocity which compute the linear velocity of the reference object on the position of the affected object.
1 parent 846d96f commit 3ca1d2d

File tree

6 files changed

+91
-46
lines changed

6 files changed

+91
-46
lines changed

source/blender/editors/space_logic/logic_window.c

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1741,11 +1741,13 @@ static void draw_actuator_motion(uiLayout *layout, PointerRNA *ptr)
17411741
PointerRNA settings_ptr;
17421742
uiLayout *split, *row, *col, *sub;
17431743
int physics_type;
1744+
bool angular;
17441745

17451746
ob = (Object *)ptr->id.data;
17461747
RNA_pointer_create((ID *)ob, &RNA_GameObjectSettings, ob, &settings_ptr);
17471748
physics_type = RNA_enum_get(&settings_ptr, "physics_type");
1748-
1749+
angular = (RNA_enum_get(ptr, "servo_mode") == ACT_SERVO_ANGULAR);
1750+
17491751
uiItemR(layout, ptr, "mode", 0, NULL, ICON_NONE);
17501752

17511753
switch (RNA_enum_get(ptr, "mode")) {
@@ -1790,10 +1792,18 @@ static void draw_actuator_motion(uiLayout *layout, PointerRNA *ptr)
17901792
case ACT_OBJECT_SERVO:
17911793
uiItemR(layout, ptr, "reference_object", 0, NULL, ICON_NONE);
17921794

1795+
uiItemR(layout, ptr, "servo_mode", 0, NULL, ICON_NONE);
1796+
17931797
split = uiLayoutSplit(layout, 0.9, false);
17941798
row = uiLayoutRow(split, false);
1795-
uiItemR(row, ptr, "linear_velocity", 0, NULL, ICON_NONE);
1796-
uiItemR(split, ptr, "use_local_linear_velocity", UI_ITEM_R_TOGGLE, NULL, ICON_NONE);
1799+
if (angular) {
1800+
uiItemR(row, ptr, "angular_velocity", 0, NULL, ICON_NONE);
1801+
uiItemR(split, ptr, "use_local_angular_velocity", UI_ITEM_R_TOGGLE, NULL, ICON_NONE);
1802+
}
1803+
else {
1804+
uiItemR(row, ptr, "linear_velocity", 0, NULL, ICON_NONE);
1805+
uiItemR(split, ptr, "use_local_linear_velocity", UI_ITEM_R_TOGGLE, NULL, ICON_NONE);
1806+
}
17971807

17981808
row = uiLayoutRow(layout, false);
17991809
col = uiLayoutColumn(row, false);

source/blender/makesdna/DNA_actuator_types.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,8 @@ typedef struct bPropertyActuator {
117117
typedef struct bObjectActuator {
118118
short flag, type, otype;
119119
short damping;
120+
short servotype;
121+
short pad2[3];
120122
float forceloc[3], forcerot[3];
121123
float pad[3], pad1[3];
122124
float dloc[3], drot[3]; /* angle in radians */
@@ -308,6 +310,10 @@ typedef struct bActuator {
308310
#define ACT_OBJECT_SERVO 1
309311
#define ACT_OBJECT_CHARACTER 2
310312

313+
/* objectactuator->servotype */
314+
#define ACT_SERVO_LINEAR 0
315+
#define ACT_SERVO_ANGULAR 1
316+
311317
/* actuator->type */
312318
#define ACT_OBJECT 0
313319
#define ACT_IPO 1

source/blender/makesrna/intern/rna_actuator.c

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -725,6 +725,12 @@ static void rna_def_object_actuator(BlenderRNA *brna)
725725
{0, NULL, 0, NULL, NULL}
726726
};
727727

728+
static EnumPropertyItem prop_servo_type_items[] = {
729+
{ACT_SERVO_LINEAR, "SERVO_LINEAR", 0, "Linear", ""},
730+
{ACT_SERVO_ANGULAR, "SERVO_ANGULAR", 0, "Angular", ""},
731+
{0, NULL, 0, NULL, NULL}
732+
};
733+
728734
srna = RNA_def_struct(brna, "ObjectActuator", "Actuator");
729735
RNA_def_struct_ui_text(srna, "Motion Actuator", "Actuator to control the object movement");
730736
RNA_def_struct_sdna_from(srna, "bObjectActuator", "data");
@@ -736,6 +742,11 @@ static void rna_def_object_actuator(BlenderRNA *brna)
736742
RNA_def_property_enum_funcs(prop, NULL, "rna_ObjectActuator_type_set", NULL);
737743
RNA_def_property_ui_text(prop, "Motion Type", "Specify the motion system");
738744
RNA_def_property_update(prop, NC_LOGIC, NULL);
745+
746+
prop = RNA_def_property(srna, "servo_mode", PROP_ENUM, PROP_NONE);
747+
RNA_def_property_enum_sdna(prop, NULL, "servotype");
748+
RNA_def_property_enum_items(prop, prop_servo_type_items);
749+
RNA_def_property_ui_text(prop, "Servo Type", "Specify the servo control system");
739750

740751
prop = RNA_def_property(srna, "reference_object", PROP_POINTER, PROP_NONE);
741752
RNA_def_property_struct_type(prop, "Object");
@@ -895,17 +906,17 @@ static void rna_def_object_actuator(BlenderRNA *brna)
895906

896907
prop = RNA_def_property(srna, "use_servo_limit_x", PROP_BOOLEAN, PROP_NONE);
897908
RNA_def_property_boolean_sdna(prop, NULL, "flag", ACT_SERVO_LIMIT_X);
898-
RNA_def_property_ui_text(prop, "X", "Set limit to force along the X axis");
909+
RNA_def_property_ui_text(prop, "X", "Set limit to force/torque along the X axis");
899910
RNA_def_property_update(prop, NC_LOGIC, NULL);
900911

901912
prop = RNA_def_property(srna, "use_servo_limit_y", PROP_BOOLEAN, PROP_NONE);
902913
RNA_def_property_boolean_sdna(prop, NULL, "flag", ACT_SERVO_LIMIT_Y);
903-
RNA_def_property_ui_text(prop, "Y", "Set limit to force along the Y axis");
914+
RNA_def_property_ui_text(prop, "Y", "Set limit to force/torque along the Y axis");
904915
RNA_def_property_update(prop, NC_LOGIC, NULL);
905916

906917
prop = RNA_def_property(srna, "use_servo_limit_z", PROP_BOOLEAN, PROP_NONE);
907918
RNA_def_property_boolean_sdna(prop, NULL, "flag", ACT_SERVO_LIMIT_Z);
908-
RNA_def_property_ui_text(prop, "Z", "Set limit to force along the Z axis");
919+
RNA_def_property_ui_text(prop, "Z", "Set limit to force/torque along the Z axis");
909920
RNA_def_property_update(prop, NC_LOGIC, NULL);
910921

911922
prop = RNA_def_property(srna, "use_character_jump", PROP_BOOLEAN, PROP_NONE);

source/gameengine/Converter/BL_ConvertActuators.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,7 @@ void BL_ConvertActuators(const char* maggiename,
185185
bitLocalFlag.CharacterJump = bool((obact->flag & ACT_CHAR_JUMP)!=0);
186186
bitLocalFlag.AddOrSetLinV = bool((obact->flag & ACT_ADD_LIN_VEL)!=0);
187187
bitLocalFlag.AddOrSetCharLoc = bool((obact->flag & ACT_ADD_CHAR_LOC)!=0);
188+
bitLocalFlag.ServoControlAngular = (obact->servotype == ACT_SERVO_ANGULAR);
188189
if (obact->reference && bitLocalFlag.ServoControl)
189190
{
190191
obref = converter.FindGameObject(obact->reference);

source/gameengine/Ketsji/KX_ObjectActuator.cpp

Lines changed: 56 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -148,59 +148,75 @@ bool KX_ObjectActuator::Update()
148148
if (mass < MT_EPSILON) {
149149
return false;
150150
}
151-
MT_Vector3 v = parent->GetLinearVelocity(m_bitLocalFlag.LinearVelocity);
151+
152+
MT_Vector3 v;
153+
if (m_bitLocalFlag.ServoControlAngular) {
154+
v = parent->GetAngularVelocity(m_bitLocalFlag.AngularVelocity);
155+
}
156+
else {
157+
v = parent->GetLinearVelocity(m_bitLocalFlag.LinearVelocity);
158+
}
159+
152160
if (m_reference) {
153-
const MT_Vector3& mypos = parent->NodeGetWorldPosition();
154-
const MT_Vector3& refpos = m_reference->NodeGetWorldPosition();
155-
MT_Vector3 relpos;
156-
relpos = (mypos - refpos);
157-
MT_Vector3 vel = m_reference->GetVelocity(relpos);
158-
if (m_bitLocalFlag.LinearVelocity) {
159-
// must convert in local space
160-
vel = parent->NodeGetWorldOrientation().transposed() * vel;
161+
if (m_bitLocalFlag.ServoControlAngular) {
162+
const MT_Vector3 vel = m_reference->GetAngularVelocity(m_bitLocalFlag.AngularVelocity);
163+
v -= vel;
164+
}
165+
else {
166+
const MT_Vector3& mypos = parent->NodeGetWorldPosition();
167+
const MT_Vector3& refpos = m_reference->NodeGetWorldPosition();
168+
const MT_Vector3 relpos = (mypos - refpos);
169+
MT_Vector3 vel = m_reference->GetVelocity(relpos);
170+
if (m_bitLocalFlag.LinearVelocity) {
171+
// must convert in local space
172+
vel = parent->NodeGetWorldOrientation().transposed() * vel;
173+
}
174+
v -= vel;
161175
}
162-
v -= vel;
163176
}
164-
MT_Vector3 e = m_linear_velocity - v;
177+
178+
MT_Vector3 e;
179+
if (m_bitLocalFlag.ServoControlAngular) {
180+
e = m_angular_velocity - v;
181+
}
182+
else {
183+
e = m_linear_velocity - v;
184+
}
185+
165186
MT_Vector3 dv = e - m_previous_error;
166187
MT_Vector3 I = m_error_accumulator + e;
167188

168-
m_force = m_pid.x() * e + m_pid.y() * I + m_pid.z() * dv;
189+
MT_Vector3& f = (m_bitLocalFlag.ServoControlAngular) ? m_force : m_torque;
190+
f = m_pid.x() * e + m_pid.y() * I + m_pid.z() * dv;
169191
// to automatically adapt the PID coefficient to mass;
170-
m_force *= mass;
171-
if (m_bitLocalFlag.Torque) {
172-
if (m_force[0] > m_dloc[0]) {
173-
m_force[0] = m_dloc[0];
174-
I[0] = m_error_accumulator[0];
175-
}
176-
else if (m_force[0] < m_drot[0]) {
177-
m_force[0] = m_drot[0];
178-
I[0] = m_error_accumulator[0];
179-
}
180-
}
181-
if (m_bitLocalFlag.DLoc) {
182-
if (m_force[1] > m_dloc[1]) {
183-
m_force[1] = m_dloc[1];
184-
I[1] = m_error_accumulator[1];
185-
}
186-
else if (m_force[1] < m_drot[1]) {
187-
m_force[1] = m_drot[1];
188-
I[1] = m_error_accumulator[1];
192+
f *= mass;
193+
194+
const bool limits[3] = {m_bitLocalFlag.Torque, m_bitLocalFlag.DLoc, m_bitLocalFlag.DRot};
195+
196+
for (unsigned short i = 0; i < 3; ++i) {
197+
if (!limits[i]) {
198+
continue;
189199
}
190-
}
191-
if (m_bitLocalFlag.DRot) {
192-
if (m_force[2] > m_dloc[2]) {
193-
m_force[2] = m_dloc[2];
194-
I[2] = m_error_accumulator[2];
200+
201+
if (f[i] > m_dloc[i]) {
202+
f[i] = m_dloc[i];
203+
I[i] = m_error_accumulator[i];
195204
}
196-
else if (m_force[2] < m_drot[2]) {
197-
m_force[2] = m_drot[2];
198-
I[2] = m_error_accumulator[2];
205+
else if (f[i] < m_drot[i]) {
206+
f[i] = m_drot[i];
207+
I[i] = m_error_accumulator[i];
199208
}
200209
}
210+
201211
m_previous_error = e;
202212
m_error_accumulator = I;
203-
parent->ApplyForce(m_force, (m_bitLocalFlag.LinearVelocity) != 0);
213+
214+
if (m_bitLocalFlag.ServoControlAngular) {
215+
parent->ApplyTorque(f, m_bitLocalFlag.AngularVelocity);
216+
}
217+
else {
218+
parent->ApplyForce(f, m_bitLocalFlag.LinearVelocity);
219+
}
204220
}
205221
else if (m_bitLocalFlag.CharacterMotion) {
206222
MT_Vector3 dir = m_dloc;

source/gameengine/Ketsji/KX_ObjectActuator.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ struct KX_LocalFlags {
8181
bool ZeroDLoc;
8282
bool ZeroLinearVelocity;
8383
bool ZeroAngularVelocity;
84+
bool ServoControlAngular;
8485
};
8586

8687
class KX_ObjectActuator : public SCA_IActuator

0 commit comments

Comments
 (0)