here is another example. In this example when a package gets to the end of the conveyor, the conveyor stops until the package is removed. The trick illustrated here is how a group of packages start and stop in sync with each other.
"""
A simple conveyor
has a load hopper to queue packanges
waiting to be conveyed.
When a package gets to the end of the
conveyor the conveyor stops until the
package is removed from the conveyor.
programmer: Michael R. Gibbs
"""
import simpy
import random
convey_time = 20 # time to move package to end of conveyor
convey_load_time = 2 # minimum time between packages placed on conveyor
class Package():
"""
simple package class
gives a id to each package
"""
next_id = 1
def __init__(self):
self.pack_id = self.__class__.next_id
self.__class__.next_id += 1
class Conveyor():
"""
Simple conveyor that move stuff from point A to point B.
Conveyor stops when a package gets to the end and
restarts when the package is removed from the conveyor
"""
def __init__(self, env):
self.env = env
self.load_hopper = simpy.Store(env)
self.pick_up_pile = simpy.Store(env,1)
# events to cordinate when the conveyor starts and stops
self.start_event = simpy.Event(env)
self.stop_event = simpy.Event(env)
# start the conveyor processes
env.process(self._start_stop())
# starts the loop that waits for stuff
# to be put onto the conveyor
env.process(self._load_convayor())
def _load_convayor(self):
"""
Loads the conveyor from the load hopper
After a package is placed on the convey
it will wait for the package to move
down the conveyor to make enough room
for the next package.
"""
while True:
pack = yield self.load_hopper.get()
# starts the package moving down the conveyor
env.process(self._move_pack(pack))
print(f"{env.now:.2f} pack {pack.pack_id} on convayor")
# wait for space befor placing the next package
remaining_wait_time = convey_load_time
while remaining_wait_time > 0:
last_start = self.env.now
wait_event = env.timeout(remaining_wait_time)
# also stops when conveyor stops
triggered = yield env.any_of([wait_event, self.stop_event])
if wait_event in triggered:
# space is open for another package
remaining_wait_time = 0
else:
# conveyor stopped, wait for start
remaining_wait_time -= self.env.now - last_start
yield self.start_event
def _move_pack(self, pack):
"""
Moves a package down the conveyor
When a package gets to the end of the
conveyor, it stops the conveyor
"""
remaining_travel_time = convey_time
while remaining_travel_time > 0:
last_start = self.env.now
travle_timeout = env.timeout(remaining_travel_time)
# package also stops moving if conveyor stops
triggered = yield env.any_of([travle_timeout, self.stop_event])
if travle_timeout in triggered:
# at end of conveyor
remaining_travel_time = 0
else:
# conveyor has stopped, wait for restart
remaining_travel_time -= self.env.now - last_start
yield self.start_event
# at end of conveyor, stop conveyor
self.stop_event.succeed()
self.stop_event = simpy.Event(self.env)
yield self.pick_up_pile.put(pack)
print(f"{env.now:.2f} pack {pack.pack_id} end of convayor")
def pick_up(self):
"""
Removes a package from the end of the conveyor
"""
pack = yield self.pick_up_pile.get()
# restart conveyor
self.start_event.succeed()
self.start_event = simpy.Event(self.env)
return pack
def queue_package(self, pack):
"""
Puts a package into the queue to
be conveyed on the conveyor
"""
self.load_hopper.put(pack)
print(f"{env.now:.2f} package {pack.pack_id} is queued")
def _start_stop(self):
"""
logs when the conveyor starts or stops
"""
while True:
yield self.stop_event
print(f"{env.now:.2f} conveyor has stopped")
yield self.start_event
print(f"{env.now:.2f} conveyor has started")
def unload_conveyor(env, conveyor):
"""
Unload the conveyor
Unloader takes some time to process a package
so there is a chance a package will sit at the
end of the conveyor and block everything for
a short time.
"""
while True:
print(f"{env.now:.2f} unloader waiting for a package")
pack = yield env.process(conveyor.pick_up())
print(f"{env.now:.2f} pack {pack.pack_id} unloaded from conveyor")
# process the package
yield env.timeout(random.triangular(1,6))
def package_arrivals(env, conveyor):
"""
queues packages for the conveyor
tries to show when convey is at compacity.
If queue is empty a added package is
immeditaly placed onthe conveyor.
If queue is not empty, new packages
wait their turn to be put on the conveyor
"""
# prime the queue with a full load
for i in range(15):
conveyor.queue_package(Package())
yield env.timeout(60)
for i in range(4):
conveyor.queue_package(Package())
yield env.timeout(5)
for i in range(4):
conveyor.queue_package(Package())
env = simpy.Environment()
conveyor = Conveyor(env)
env.process(unload_conveyor(env, conveyor))
# make stream of packages
env.process(package_arrivals(env, conveyor))
env.run(200)