BGE: Servo Control needs a rewrite #43538

Closed
opened 2015-02-02 23:55:44 +01:00 by Sybren A. Stüvel · 16 comments

The Servo Control option of the Motion logic brick needs some reworking. There are things that I perceive as bugs, some strange things in the documentation, and I have an idea for a new feature that shouldn't be too hard to implement. But, before I create tasks for all those things separately, I think it would be better to have an overall discussion about where we want to go with this logic brick.

Issues:

Naming: according to Wikipedia a servo controller uses pulse width modulation to control the angle of a motor. This is something different from a PID controller, which is used to control all kinds of signals. In other words, a servo controller only modulates thetimeduring which a certain constant-power force is applied. In contrast, PID controllers modulate thepowerof the force. Blender mixes "Servo" and "PID" both in the software and the documentation, as if they were the same thing. I think a more suitable name for the logic brick would be "PID Control" (roughly as much in-crowd as "Servo Control"), or something less in-crowd along the lines of "Force control" or "Match position/orientation"*Documentation:*The manual states that it controls the velocity of an object. However, it also mentions using a moving platform as a reference object, in which case only matching its velocity would be silly, implying that positon is also controlled. Confusingly, none of the explanations of the PID components mention position. Typically a PID controller controls both the position and the velocity. This makes the P component proportional to the error in position (not velocity, as stated in the docs); the I component proportional to the integrated error so far; and the D component proportional to the error in velocity.

Feature bloat?: In physical simulations, the I-component is usually removed. It is useful for things like controlling the temperature of your brew when you're brewing beer, but not so much in physical simulation. This means that in these cases people generally implement PD controllers, or set I=0.

GUI: Setting the I-coefficient resets the P-coefficient to 60x I, regardless of what the user set before. A typical setup of I=0 as described above is thus hard to do. Typically a user of a PID controller wants to set all three parameters independently.

Missing features: Matching position & linear velocity of a reference object is nice. However, there is no support for matching orientation & angular velocity. In some cases it is also desirable to be able to implement "gravity compensation" - a way to turn off gravity for a specific object before the PD controller applies its force.

More granular control: Currenly (AFAIK, but I could be wrong) the logic bricks only run on every logic tick. This makes perfect sense given the name and goal of the logic bricks. However, to get the best motion out of your PID, it is better to have it update its output for every physics tick (so "substeps" times per logic tick). This would mean separating the update of the controller from the logic brick.

It may just be for lack of understanding on my part, but I simply couldn't get the servo control to lift a box and move it to an empty.

Proposal:

Give free reign over the code (which I don't have), I would do the following:

  • Describe the desired behavour of positional and orientational PD controllers in Blender, in a non-ambiguous and technically correct way.
  • Decide whether we want to alter the Servo Control logic brick to suit the intended functionality, or create new bricks and deprecate Servo Control.
  • Investigate Bullet to see how much support there already is for the type of control we want. This forum thread seems to suggest that Bullet has some support. However, the documentation seems to be rather sparse, and PD controllers are quite easy to implement ourselves. As a matter of fact, I have simple positional and orientational PD controllers implemented in Python, and they shouldn't be too hard to port to C.
  • Either make the Bullet controllers easily accesible in C, or implement our own.
  • If we write our own controllers, hook up the update functions of the PD controllers to the physics update tick. This could be done directly, but I think a clearer way would be to have some pre-physics/post-physics callback system that the PD controllers can hook into.
  • Write Python wrappers.
  • Make the PD controllers manageable through logic bricks. Maybe one type is enough for both linear and angular types, or maybe we want a brick (sub)type for each.

I'm curious as to your opinion on all of this.

The Servo Control option of the Motion logic brick needs some reworking. There are things that I perceive as bugs, some strange things in the documentation, and I have an idea for a new feature that shouldn't be too hard to implement. But, before I create tasks for all those things separately, I think it would be better to have an overall discussion about where we want to go with this logic brick. **Issues:** *Naming:* according to [Wikipedia](http:*en.wikipedia.org/wiki/Servo_control) a servo controller uses pulse width modulation to control the angle of a motor. This is something different from a PID controller, which is used to control all kinds of signals. In other words, a servo controller only modulates the*time*during which a certain constant-power force is applied. In contrast, PID controllers modulate the*power*of the force. Blender mixes "Servo" and "PID" both in the software and the documentation, as if they were the same thing. I think a more suitable name for the logic brick would be "PID Control" (roughly as much in-crowd as "Servo Control"), or something less in-crowd along the lines of "Force control" or "Match position/orientation"*Documentation:*The [manual](http:*www.blender.org/manual/game_engine/logic/actuators/motion.html#servo-control) states that it controls the *velocity* of an object. However, it also mentions using a moving platform as a reference object, in which case only matching its velocity would be silly, implying that positon is also controlled. Confusingly, none of the explanations of the PID components mention position. Typically a PID controller controls both the position and the velocity. This makes the P component proportional to the error in position (not velocity, as stated in the docs); the I component proportional to the integrated error so far; and the D component proportional to the error in velocity. *Feature bloat?:* In physical simulations, the I-component is usually removed. It is useful for things like controlling the temperature of your brew when you're brewing beer, but not so much in physical simulation. This means that in these cases people generally implement PD controllers, or set I=0. *GUI:* Setting the I-coefficient resets the P-coefficient to 60x I, regardless of what the user set before. A typical setup of I=0 as described above is thus hard to do. Typically a user of a PID controller wants to set all three parameters independently. *Missing features:* Matching position & linear velocity of a reference object is nice. However, there is no support for matching orientation & angular velocity. In some cases it is also desirable to be able to implement "gravity compensation" - a way to turn off gravity for a specific object before the PD controller applies its force. *More granular control:* Currenly (AFAIK, but I could be wrong) the logic bricks only run on every logic tick. This makes perfect sense given the name and goal of the logic bricks. However, to get the best motion out of your PID, it is better to have it update its output for every physics tick (so "substeps" times per logic tick). This would mean separating the update of the controller from the logic brick. It may just be for lack of understanding on my part, but I simply couldn't get the servo control to lift a box and move it to an empty. **Proposal:** Give free reign over the code (which I don't have), I would do the following: - Describe the desired behavour of positional and orientational PD controllers in Blender, in a non-ambiguous and technically correct way. - Decide whether we want to alter the Servo Control logic brick to suit the intended functionality, or create new bricks and deprecate Servo Control. - Investigate Bullet to see how much support there already is for the type of control we want. This forum thread seems to suggest that Bullet has some support. However, the documentation seems to be rather sparse, and PD controllers are quite easy to implement ourselves. As a matter of fact, I have simple positional and orientational PD controllers implemented in Python, and they shouldn't be too hard to port to C. - Either make the Bullet controllers easily accesible in C, or implement our own. - If we write our own controllers, hook up the update functions of the PD controllers to the physics update tick. This could be done directly, but I think a clearer way would be to have some pre-physics/post-physics callback system that the PD controllers can hook into. - Write Python wrappers. - Make the PD controllers manageable through logic bricks. Maybe one type is enough for both linear and angular types, or maybe we want a brick (sub)type for each. I'm curious as to your opinion on all of this.
Author
Member

Changed status to: 'Open'

Changed status to: 'Open'
Author
Member

Added subscriber: @dr.sybren

Added subscriber: @dr.sybren
Benoit Bolsee was assigned by Dalai Felinto 2015-02-03 14:44:09 +01:00

Added subscribers: @BenoitBolsee, @dfelinto

Added subscribers: @BenoitBolsee, @dfelinto

@BenoitBolsee was the original author of this actuator. He wrote quite a comprehensive documentation, but maybe it is only in the commit log?
Either way, I hope he can jump in and share some insights on the matter.

@BenoitBolsee was the original author of this actuator. He wrote quite a comprehensive documentation, but maybe it is only in the commit log? Either way, I hope he can jump in and share some insights on the matter.
Author
Member

The words "this forum post" should have been linked to this forum post.

Bullet motor constraints seems to use ERP and CFM instead of P and D gains. The ODE documentation shows how to convert between the two. The Bullet implementation is huge and complex, though, whereas a PD Controller is very simple to implement:

class PDController:
    ZERO = 0.0

    def __init__(self, kp=1.0, kd=1.0):
        self.kp = kp  # Proportional gain
        self.kd = kd  # Derivative-of-error gain

        self._setpoint = self.ZERO  # Desired value
        self.last_error = self.ZERO  # Last seen error, for calculating derivative of error
        self._last_time = 0.0  # Last time we've seen an update

    @property
    def setpoint(self):
        return self._setpoint

    @setpoint.setter
    def setpoint(self, new_setpoint):
        self._setpoint = new_setpoint

        - By resetting we set the differential error to 0.0 in the first update.
        - This prevents large differential errors, and thus creates a smooth transition.
        self.reset()

    def reset(self):
        self.last_error = self.ZERO
        self._last_time = 0.0

    def calc_error(self, process_value):
        return self._setpoint - process_value

    def update(self, process_value, current_time: float) -> float:
        """Calculates the new manipulated value, given the current value and time."""

        error = self.calc_error(process_value)

        # Calculate the derivative of the error
        timediff = current_time - self._last_time
        if timediff > 0:
            error_diff = (error - self.last_error) / timediff
        else:
            error_diff = self.ZERO

        # Remember values for next time
        self.last_error = error
        self._last_time = current_time

        # Calculate & return the result
        p = self.kp * error
        d = self.kd * error_diff

        return p + d

This controller calculates the differential of the error. Alternatively, if it's desired to match a certain velocity, you can also calculate the error of the differential. It won't make it much more complex, so my point "look at how simple a PD controller can be" is still valid ;-)

The words "this forum post" should have been linked to [this forum post](http://www.bulletphysics.org/Bullet/phpBB3/viewtopic.php?p=&f=&t=3895). Bullet motor constraints seems to use ERP and CFM instead of P and D gains. [The ODE documentation](http://ode.org/ode-0.5-userguide.html#sec_3_8_2) shows how to convert between the two. The Bullet implementation is huge and complex, though, whereas a PD Controller is very simple to implement: ``` class PDController: ZERO = 0.0 def __init__(self, kp=1.0, kd=1.0): self.kp = kp # Proportional gain self.kd = kd # Derivative-of-error gain self._setpoint = self.ZERO # Desired value self.last_error = self.ZERO # Last seen error, for calculating derivative of error self._last_time = 0.0 # Last time we've seen an update @property def setpoint(self): return self._setpoint @setpoint.setter def setpoint(self, new_setpoint): self._setpoint = new_setpoint - By resetting we set the differential error to 0.0 in the first update. - This prevents large differential errors, and thus creates a smooth transition. self.reset() def reset(self): self.last_error = self.ZERO self._last_time = 0.0 def calc_error(self, process_value): return self._setpoint - process_value def update(self, process_value, current_time: float) -> float: """Calculates the new manipulated value, given the current value and time.""" error = self.calc_error(process_value) # Calculate the derivative of the error timediff = current_time - self._last_time if timediff > 0: error_diff = (error - self.last_error) / timediff else: error_diff = self.ZERO # Remember values for next time self.last_error = error self._last_time = current_time # Calculate & return the result p = self.kp * error d = self.kd * error_diff return p + d ``` This controller calculates the differential of the error. Alternatively, if it's desired to match a certain velocity, you can also calculate the error of the differential. It won't make it much more complex, so my point "look at how simple a PD controller can be" is still valid ;-)
Member

Hello Sybren. Thanks for looking at the BGE, new developers are always welcome.
Now down to your list:

Naming: I choose the name based on my engineering studies almost 30 years ago. The naming convention has probably changed since then. I have no problem with the renaming of the brick to something more explicit: Force Control sounds good.

Documentation: I didn't write the documentation you referring to. My original doc is in the commit log (https://git.blender.org/gitweb/gitweb.cgi/blender.git/commitdiff/70d239ef). I confirm that the servo control sets the force in order to achieve a certain velocity, the position is not controlled. The idea behind the servo control is to replace the dloc motion that doesn't produce physically correct velocity (but rather a series of instant displacements). Controlling the position was not necessary in that respect: it is left to the player who moves the object through WASD type of control (each W-A-S-D sensor is attached to a different servo controls). Note that if you set a reference in the GUI, the brick controls the velocity relative to the reference. This allows to easily control an object on a moving platform (the target velocity is relative to the reference).
All the PID components refer to the velocity error:
P = the force is proportional to the velocity error
I = the velocity error is integrated over time and the force is proportional to the integral.
D = the force is proportional to the variation of the velocity error between successive frames.

Using only the P component results in a systematic velocity error if there is friction: some velocity delta is necessary to produce the force that compensates the friction.
Using the I component suppresses this effect (the target velocity is achieved on the average) but can create oscillations: the control will speed to compensate the initial velocity error. To avoid the oscillation, the P component must be used with the I component (the P component damps the control). This is why the GUI sets the P systematically when you change the I. I agree that this is confusing.
The D component is meant to produce rapid reaction on change of velocity target but it tends to introduce great instability. I rarely used it.

Missing feature: as said above, the original goal of the servo control was to replace dloc and provide smooth and stable WASD type of the control. This explains that you don't have position control or rotation control. Still you can use the control is many ways. For example you can achive gravity compensation by setting the absolute target velocity on the world Z axis to 0 and set the force limit to 0 for along other axis: the control will produce a force that compensates the gravity (to make the object stay still on the Z axis) but allows free movements on X and Y axis (because the force is 0).

More granularity: indeed the servo control updates the force once per logic tick. Your idea of running the PID in the physics engine is good. The poor granularity is probably the cause of the instability of the D component.

Note that the source code of the servo control is very simple: it is merely a few lines of code in KX_ObjectActuator.cpp. You can easily make sense of it if you remember that it reuses some fields of the simple motion control, which explains the rather poor variable names (for example, m_bitLocalFlag.Torque is reused in servo control to enable force limit on the X axis).

Proposal: if you intend to create a positional and orientation control, then I suggest to create a new brick for that purpose; servo control has a different objective and should remain available.

Hello Sybren. Thanks for looking at the BGE, new developers are always welcome. Now down to your list: Naming: I choose the name based on my engineering studies almost 30 years ago. The naming convention has probably changed since then. I have no problem with the renaming of the brick to something more explicit: Force Control sounds good. Documentation: I didn't write the documentation you referring to. My original doc is in the commit log (https://git.blender.org/gitweb/gitweb.cgi/blender.git/commitdiff/70d239ef). I confirm that the servo control sets the force in order to achieve a certain velocity, the position is not controlled. The idea behind the servo control is to replace the dloc motion that doesn't produce physically correct velocity (but rather a series of instant displacements). Controlling the position was not necessary in that respect: it is left to the player who moves the object through WASD type of control (each W-A-S-D sensor is attached to a different servo controls). Note that if you set a reference in the GUI, the brick controls the velocity relative to the reference. This allows to easily control an object on a moving platform (the target velocity is relative to the reference). All the PID components refer to the velocity error: P = the force is proportional to the velocity error I = the velocity error is integrated over time and the force is proportional to the integral. D = the force is proportional to the variation of the velocity error between successive frames. Using only the P component results in a systematic velocity error if there is friction: some velocity delta is necessary to produce the force that compensates the friction. Using the I component suppresses this effect (the target velocity is achieved on the average) but can create oscillations: the control will speed to compensate the initial velocity error. To avoid the oscillation, the P component must be used with the I component (the P component damps the control). This is why the GUI sets the P systematically when you change the I. I agree that this is confusing. The D component is meant to produce rapid reaction on change of velocity target but it tends to introduce great instability. I rarely used it. Missing feature: as said above, the original goal of the servo control was to replace dloc and provide smooth and stable WASD type of the control. This explains that you don't have position control or rotation control. Still you can use the control is many ways. For example you can achive gravity compensation by setting the absolute target velocity on the world Z axis to 0 and set the force limit to 0 for along other axis: the control will produce a force that compensates the gravity (to make the object stay still on the Z axis) but allows free movements on X and Y axis (because the force is 0). More granularity: indeed the servo control updates the force once per logic tick. Your idea of running the PID in the physics engine is good. The poor granularity is probably the cause of the instability of the D component. Note that the source code of the servo control is very simple: it is merely a few lines of code in KX_ObjectActuator.cpp. You can easily make sense of it if you remember that it reuses some fields of the simple motion control, which explains the rather poor variable names (for example, m_bitLocalFlag.Torque is reused in servo control to enable force limit on the X axis). Proposal: if you intend to create a positional and orientation control, then I suggest to create a new brick for that purpose; servo control has a different objective and should remain available.
Author
Member

Thank you for your extensive answer! This makes things a lot clearer.

As for the gravity compensation: that's not the type of compensation I wanted to refer to, but in hindsight I feel my description could use some clarification. Anyway, it's not relevant to the Servo Control.

My proposal for improving the Servo Control brick:

  • Rename Servo Control to Velocity Control, as that's what it is controlling. My planned new controller(s) can then be called Position Control and Orientation Control (or something along those lines). We could also create names like "Force Control: Velocity", "Force Control: Position" and "Force Control: Orientation".
  • Not sure what to do with the P and I gains in the user interface. If it were a new controller I'd remove them from the UI and replace them with a single property that controls both gains. However, this would probably break some games out there. Alternatively, I just remove the override that sets P when you set I, as this is really confusing, and clearly document your suggested ratio.

Integrate the documentation from your commit with the new Blender manual.

In another task:

  • Create a PID controller that can be updated at every physics tick.
  • Change the existing Servo Control such that it uses that PID controller.

Create positional and orientational control that use that PID controller.

What do you think of such an approach?

Thank you for your extensive answer! This makes things a lot clearer. As for the gravity compensation: that's not the type of compensation I wanted to refer to, but in hindsight I feel my description could use some clarification. Anyway, it's not relevant to the Servo Control. My proposal for improving the Servo Control brick: - Rename Servo Control to Velocity Control, as that's what it is controlling. My planned new controller(s) can then be called Position Control and Orientation Control (or something along those lines). We could also create names like "Force Control: Velocity", "Force Control: Position" and "Force Control: Orientation". - Not sure what to do with the P and I gains in the user interface. If it were a new controller I'd remove them from the UI and replace them with a single property that controls both gains. However, this would probably break some games out there. Alternatively, I just remove the override that sets P when you set I, as this is really confusing, and clearly document your suggested ratio. # Integrate the documentation from your commit with the new Blender manual. In another task: - Create a PID controller that can be updated at every physics tick. - Change the existing Servo Control such that it uses that PID controller. # Create positional and orientational control that use that PID controller. What do you think of such an approach?
Member

Sounds like a good plan. Ok on all the points.
I vote for the "Force Control: Velocity/Position/Orientation" names.

Sounds like a good plan. Ok on all the points. I vote for the "Force Control: Velocity/Position/Orientation" names.
Author
Member

I started simple, by updating the documentation so that it reflects the current state of things: D1118

I started simple, by updating the documentation so that it reflects the current state of things: [D1118](https://archive.blender.org/developer/D1118)
Member

Added subscriber: @JorgeBernalMartinez

Added subscriber: @JorgeBernalMartinez

Added subscriber: @ekyah411

Added subscriber: @ekyah411

Hi all,
(Apology if I have missed the update of this task during my search)
May I know if there is any update on the implementation of the position and orientation Motion controller?
I have been working on implementing these controllers using Python script for my project and I have been experiencing some difficulty.

My model is a 6 legged robot whereas each leg consists of a universal joint and a prismatic joint. There are in total 3 Motion controllers in each leg controlling 2 rotations and one translation, each one with a set of P, I, D parameters. I have been experiencing difficulty tuning the PID parameters for the legs and didn't manage to obtain a stable working model after a lot of effort in tuning. I believe one of the problems is that this is an interconnected system with many parts. Has anyone worked on a similar project before or know of an existing solution in BGE that can do this?

Please pardon me if this is not exactly the place for this type of question. If so, I would really appreciate it if you can direct me to the right place.
Thank you very much!
Best regards,
Anh

Hi all, (Apology if I have missed the update of this task during my search) May I know if there is any update on the implementation of the position and orientation Motion controller? I have been working on implementing these controllers using Python script for my project and I have been experiencing some difficulty. My model is a 6 legged robot whereas each leg consists of a universal joint and a prismatic joint. There are in total 3 Motion controllers in each leg controlling 2 rotations and one translation, each one with a set of P, I, D parameters. I have been experiencing difficulty tuning the PID parameters for the legs and didn't manage to obtain a stable working model after a lot of effort in tuning. I believe one of the problems is that this is an interconnected system with many parts. Has anyone worked on a similar project before or know of an existing solution in BGE that can do this? Please pardon me if this is not exactly the place for this type of question. If so, I would really appreciate it if you can direct me to the right place. Thank you very much! Best regards, Anh
Author
Member

Hi Anh,

Due to time constraints I haven't been able to work on this further. I have every intention to, but had to focus on more pressing matters. Tweaking PID controllers can be hard, and a stable system can usually only be obtained with a small enough time step. Unfortunately, the Python controllers only run for every logic tick, and not for every physics tick. You could try setting a high FPS rate, max logic steps = 1, max physics steps = 1 and physics substeps = 1. That way at least your Python code uses the same ticks as the physics code.

You're right in that this may not be the best place to discuss this. The BlenderArtists forum might be a better place, or #blender or #gameblender on Freenode IRC.

Cheers,
Sybren

Hi Anh, Due to time constraints I haven't been able to work on this further. I have every intention to, but had to focus on more pressing matters. Tweaking PID controllers can be hard, and a stable system can usually only be obtained with a small enough time step. Unfortunately, the Python controllers only run for every logic tick, and not for every physics tick. You could try setting a high FPS rate, max logic steps = 1, max physics steps = 1 and physics substeps = 1. That way at least your Python code uses the same ticks as the physics code. You're right in that this may not be the best place to discuss this. The BlenderArtists forum might be a better place, or #blender or #gameblender on Freenode IRC. Cheers, Sybren
Member

Added subscriber: @Blendify

Added subscriber: @Blendify
Member

Changed status from 'Open' to: 'Archived'

Changed status from 'Open' to: 'Archived'
Member

This task is being closed because the BGE has been removed in Blender 2.8.

This task is being closed because the BGE has been removed in Blender 2.8.
Sign in to join this conversation.
No Label
Interest
Alembic
Interest
Animation & Rigging
Interest
Asset Browser
Interest
Asset Browser Project Overview
Interest
Audio
Interest
Automated Testing
Interest
Blender Asset Bundle
Interest
BlendFile
Interest
Collada
Interest
Compatibility
Interest
Compositing
Interest
Core
Interest
Cycles
Interest
Dependency Graph
Interest
Development Management
Interest
EEVEE
Interest
EEVEE & Viewport
Interest
Freestyle
Interest
Geometry Nodes
Interest
Grease Pencil
Interest
ID Management
Interest
Images & Movies
Interest
Import Export
Interest
Line Art
Interest
Masking
Interest
Metal
Interest
Modeling
Interest
Modifiers
Interest
Motion Tracking
Interest
Nodes & Physics
Interest
OpenGL
Interest
Overlay
Interest
Overrides
Interest
Performance
Interest
Physics
Interest
Pipeline, Assets & IO
Interest
Platforms, Builds & Tests
Interest
Python API
Interest
Render & Cycles
Interest
Render Pipeline
Interest
Sculpt, Paint & Texture
Interest
Text Editor
Interest
Translations
Interest
Triaging
Interest
Undo
Interest
USD
Interest
User Interface
Interest
UV Editing
Interest
VFX & Video
Interest
Video Sequencer
Interest
Virtual Reality
Interest
Vulkan
Interest
Wayland
Interest
Workbench
Interest: X11
Legacy
Blender 2.8 Project
Legacy
Milestone 1: Basic, Local Asset Browser
Legacy
OpenGL Error
Meta
Good First Issue
Meta
Papercut
Meta
Retrospective
Meta
Security
Module
Animation & Rigging
Module
Core
Module
Development Management
Module
EEVEE & Viewport
Module
Grease Pencil
Module
Modeling
Module
Nodes & Physics
Module
Pipeline, Assets & IO
Module
Platforms, Builds & Tests
Module
Python API
Module
Render & Cycles
Module
Sculpt, Paint & Texture
Module
Triaging
Module
User Interface
Module
VFX & Video
Platform
FreeBSD
Platform
Linux
Platform
macOS
Platform
Windows
Priority
High
Priority
Low
Priority
Normal
Priority
Unbreak Now!
Status
Archived
Status
Confirmed
Status
Duplicate
Status
Needs Info from Developers
Status
Needs Information from User
Status
Needs Triage
Status
Resolved
Type
Bug
Type
Design
Type
Known Issue
Type
Patch
Type
Report
Type
To Do
No Milestone
No project
No Assignees
6 Participants
Notifications
Due Date
The due date is invalid or out of range. Please use the format 'yyyy-mm-dd'.

No due date set.

Dependencies

No dependencies set.

Reference: blender/blender#43538
No description provided.