Skip to content

tielur/ex_pid_controller

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

11 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

ExPidController

A PID (Proportional-Integral-Derivative) controller implementation in Elixir. PID controllers are feedback loop mechanisms used in control systems to continuously calculate an error value and apply a correction. Common use cases include cruise control, temperature regulation, and robotics.

Concepts

Term Description
Set Point (SP) The target value (e.g. desired speed or temperature)
Process Value (PV) The current measured value being controlled
Error SP - PV — the difference between target and current
Output The correction signal sent to the actuator (e.g. throttle, valve)

The three terms that make up the output:

  • Proportional (P) — reacts to the current error: kP × Err
  • Integral (I) — accumulates past error over time: kI × Err × dt
  • Derivative (D) — reacts to the rate of error change: kD × (pErr - Err) / dt

Final output: P + integral_total + D

Installation

Add ex_pid_controller to your dependencies in mix.exs:

def deps do
  [
    {:ex_pid_controller, "~> 0.1.0"}
  ]
end

Usage

Create a controller with ExPidController.new/1, then call ExPidController.step/3 on each control loop cycle. Each call returns an updated struct with all state and output fields set — pass it directly into the next cycle.

# Initialize once
controller = ExPidController.new(
  kp: 1.0,
  ki: 0.5,
  kd: 0.25,
  cycle_time: 0.1   # seconds between cycles
)

# Each cycle:
controller = ExPidController.step(controller, 100, current_value)

# Read the output and apply to your actuator, then repeat next cycle
controller.output

Example

Simulate a car cruise control loop targeting 60 mph from a starting speed of 40 mph:

# Target speed and starting speed (mph)
set_point = 60
initial_speed = 40.0

# vehicle_response simulates how much the throttle moves the car each cycle
# (a simplified stand-in for real-world inertia and friction)
vehicle_response = 0.5

controller = ExPidController.new(kp: 0.8, ki: 0.2, kd: 0.1, cycle_time: 1)

# Simulate 10 one-second control cycles
{_controller, _speed} =
  Enum.reduce(1..10, {controller, initial_speed}, fn cycle, {controller, speed} ->
    controller = ExPidController.step(controller, set_point, speed)
    speed = speed + controller.output * vehicle_response
    IO.puts("Cycle #{cycle}: speed=#{Float.round(speed, 1)}, output=#{Float.round(controller.output, 2)}")
    {controller, speed}
  end)

# Cycle 1: speed=49.0, output=18.0
# Cycle 2: speed=57.0, output=15.9
# Cycle 3: speed=62.0, output=10.04
# Cycle 4: speed=64.6, output=5.34
# Cycle 5: speed=65.7, output=2.04
# Cycle 6: speed=65.6, output=-0.07
# Cycle 7: speed=65.0, output=-1.27
# Cycle 8: speed=64.1, output=-1.82
# Cycle 9: speed=63.1, output=-1.94
# Cycle 10: speed=62.2, output=-1.79

Running Tests

mix test

About

PID Controller Example in Elixir

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages