Simple Job Flow Shop, but part returns to first machine again

255 views
Skip to first unread message

Carter Frostad

unread,
Dec 22, 2023, 2:28:35 PM12/22/23
to python-simpy
Hi All, 

I'm just starting out with SimPy and I am attempting to model a factory. What I have is a process where a part goes through 6 stations, stations 1 and 6 use the same robot. So that robot is bouncing between those two stations as the parts travel through the factory cell. 

I think I want to build a queue of parts, then pass it to the one process but I keep getting an error stating that my process is not a generator. 

Attached is the simulation I've done so far, and a little picture of what I'm modelling. My process "make_part" seems to behave correctly, but the code is making an infinte series of parallel processes, then running all the parts through it's own private process with limited resources and in order of entry. 

Does anyone have any advice on how to approach this problem?

Regards,

Carter F




my_simpy.txt
Picture1.png

Sean Reed

unread,
Jan 25, 2024, 11:24:03 AM1/25/24
to python-simpy
Hi Carter,

I suggest the following:

Create a simpy.Store to hold the parts waiting processing by each operation in the manufacturing process (11 in total in this case). In part_generator, you simply put the parts in the store for the first step in the process instead of launching a self.make_part process. Then for each operation, define a process containing an infinite loop that, in each iteration, awaits getting a part from its queue and the necessary resources (e.g. Fix01 or R2), then launches the process to do the actual process steps (i.e. defined as a method and containing the timeouts like yield self.env.timeout(27) # operator loads parts, exits, hits start.). Then in your constructor, simply start the parts generation process and each of the 11 operation processes.

This way you will not get an ever growing list of processes as parts are generated, instead each operation will start a new process when a part is ready for it and the necessary resources are available, and you can easily see how many parts are queuing for each operation at any time.

Sean

Carter Frostad

unread,
Oct 6, 2024, 6:28:09 PM10/6/24
to python-simpy
Thanks for the advice Sean, I haven't been able to get back to this project until recently. 

I had to take some time to refresh myself on python. I wanted to start with an easier cell to model, get the turntable out of the equation. 1 Robot with a welding gun, 1 Man, 2 Part Fixtures. Man loads Fixture 1, Robot welds @ fixture 1, Man unloads Fixture 1, Man loads Fixture 2, man starts over at fixture 1. Ideally, he is loading fixture 1 while the robot is working on fixture 2 and vise versa when operating correctly. I made a bad picture.

I worked on some new code, the process chart tells me everything is happening in the correct sequence but, I want the operator to start loading part 2 into the empty fixture 1 as soon as he is done with loading fixture 2. What can I do to free up the resource from the context of the production_loop? Should I be doing the for loop for generating parts in another generator process?

Any help is appreciated!

Regards,

Carter
Screenshot 2024-10-06 181814.png
M.A.S.T.01.py

Carter Frostad

unread,
Oct 10, 2024, 4:10:47 PM10/10/24
to python-simpy
Did some noodling, I think I got it. 

During my process calls I was trying to call for all of the parts I needed to complete that process, then proceeding. Referring to load operator function, we see that I call for both the fixture and the operator using the with statement. This would assign op1 to the entire first series of processes in the production loop at once, so that's why he stays until the part is done. Instead, I yield request the fixture I need and then once I have that, I then call for the rest of the resources needed to complete the process. That way the robot/operator can go to the next part's process while the previous process is running.

The store part command isn't right so I commented it out for now, maybe it's more appropriate as an option on the unload function I have; unload + put away? Release the fixture but have an option to keep the operator longer after the unload process is complete and has released the fixture? Next to add pick and place for the robot and if I'm feeling brave a turntable class!

Wish me luck.

M.A.S.T.02.py

Harry

unread,
Oct 16, 2024, 3:41:56 PM10/16/24
to python-simpy
Hi Carter,

Great to see you've made progress with your simulation.

It sounds like you've correctly identified the issue with your resource management. By initially requesting just the fixture and then, once you have it, requesting the additional resources needed for the process, you're allowing the operator and robot to move on to other tasks while the current process is running. This more accurately reflects how resources would be utilised in a real-world scenario.

Regarding the `store_part` commmand, integrating it into your unload function as an optional step makes perfect sense. You can modify your `unload_part` method to include a parameter that determines whether the operator should 'put away' the part after unloading. This way, you have flexibility to keep the operator occupied for additional tasks without holding onto the fixture resource longer than you necessary.

Here's a simple way to implement this:

def unload_part(self, part, unload_time, fix, put_away=False):
    with fix.ownership.request() as own_req:
        yield own_req
        op_req = self.resource.request()
        yield op_req
        start_time = self.env.now
        print(f"{self.name} starts unloading {part} from {fix.name} at {start_time}")
        yield self.env.timeout(unload_time)
        end_time = self.env.now
        print(f"{self.name} finishes unloading {part} from {fix.name} at {end_time}")
        fix.part.release(fix.part_request)
        fix.part_request = None
        self.resource.release(op_req)

        # Optional put-away process
        if put_away:
            yield self.env.process(self.put_away_part(part))

    # Log the event as before


By adding the `put_away` parameter, you can decide for each unload operation whether the operator should perform the additional 'put away' task.

As for your question about freeing up resources from the contextt of the `production_loop`, restructuring your simulation to generate parts in a separate generator process is indeed a good approach. This allows each part to be processed independently, making it easier to manage resource allocation and release. Here's how you might adjust your code :

Part Generator:

def part_generator(env, robot, operator, fixture_01, fixture_02):
    for part_num in range(1, sim_cycles + 1):
        part = f'Part-{part_num:02}'
        env.process(part_process(env, robot, operator, fixture_01, fixture_02, part))
        yield env.timeout(0)  # Adjust if you want to introduce a delay between parts

Part Process:

def part_process(env, robot, operator, fixture_01, fixture_02, part):
    # Operator loads part into Fixture 1
    yield env.process(operator.load_part(part, 41, fixture_01))

    # Robot spot welds on Fixture 1
    yield env.process(robot.spot_weld(part, qty=35, fix=fixture_01))

    # Operator unloads part from Fixture 1
    yield env.process(operator.unload_part(part, 51, fixture_01))

    # Operator loads part into Fixture 2
    yield env.process(operator.load_part(part, 38, fixture_02))

    # Robot spot welds on Fixture 2
    yield env.process(robot.spot_weld(part, qty=65, fix=fixture_02))

    # Operator unloads part from Fixture 2
    yield env.process(operator.unload_part(part, 58, fixture_02, put_away=True))

By using a `part_process` for each part, you ensure that the operator can start loading the next part as soon as they're available, without being held up by the sequencing in the `production_loop`.

Introducing pick-and-place functionality and creating a turntable class will add a bit more complexity. When implementing the turntable, consider it as another resource that needs to be requested and released, similar to your fixtures and robots.

Best of luck with your continued development! Feel free to reach out if you have any more questions or need further assistance and look forward to hearing how you get on.

Kind regards,
Harry

Sean Reed

unread,
Oct 16, 2024, 3:53:45 PM10/16/24
to python-simpy
Hope you managed to solve it!

For this specific problem, I would probably create two stores to act as the job queues for the worker and the robot, then the worker would add a weld job to the robot's job queue when they loaded a part on a fixture and when the robot finished welding they would add an unload job to the worker's job queue (this job would actually comprise of unload, add load job to workers job queue if first fixture, and load next fixture if not last fixture). You can then bootstrap the whole process by adding the initial "load first fixture" to the job queue. The beauty of this approach is the worker and robot processes can then just pull from there respective job queues and work efficiently in parallel without needing to code any explicit coordination logic. It's also then straightforward to extend the model to more than 2 fixtures or multiple workers and robots working in parallel, since they don't need to know about each other, workers and robots just pull from the two job queues and the work remains coordinated.

Sean Reed

unread,
Oct 16, 2024, 4:25:06 PM10/16/24
to python-simpy
I see Harry posted a nice solution at the same time I posted my reply, cool! Here is an alternative solution using the worker and robot job queue idea: https://gist.github.com/sean-reed/81d3e5cd08f0ed6a5dcddfc54b5edd70

Carter Frostad

unread,
Oct 16, 2024, 4:26:36 PM10/16/24
to python-simpy
Looks like I'm on the right track. 

Theses cells I'm posting are not particularly interesting, they are just simple things to start on. I just want to explain some of the silliness in my coding approach.

This is the circus I ultimately hope simulate with it:
Picture1.png

I'm doing it with a pencil and graphing paper, then my boss says "what if we add a robot over there?", then I have to stop myself from leaping out the nearest open window.

An issue I was running into was that the operator was just "putting away" a part that shouldn't yet exist, just because he is available to do that put away process. I almost wanted to make the parts themselves resources, is this just a recipe for a huge disaster? Maybe just adding options to the process functions is the way to go.

I also think I might need to add something to "spin up" x amount of robots/operators/fixtures? idk, maybe I'll have time this weekend.

Thanks for the help boys!

Regards,

Carter Frostad



Sean Reed

unread,
Oct 16, 2024, 4:46:54 PM10/16/24
to python-simpy
For more complex manufacturing processes like the diagram, I would usually have each part "track" where it is in its process. If all parts follow the same process sequence, this could just be a central list of steps, then each part keeps the index of where it is in the process, otherwise each part will need to store its own process steps. Then each process station (e.g. machine / conveyor / buffer etc.)  has its own queue (again, this could be modelled as a Store or PriorityStore). After a part is processed at a step, increment the part to its next process step and add it to the queue of the corresponding station. Then each process station just pulls from its own queue to process parts and parts move through the process in the correct sequence. With this fairly simple framework, it should already be enough to model quite complex manufacturing processes.

Lipovszki György

unread,
Oct 17, 2024, 8:25:38 AM10/17/24
to Carter Frostad, python-simpy
Dear Carter,
 
I would like to suggest that you examine how the problem you raised could be solved in SimPy in a fundamentally different way than writing the usual low-level SimPy program in Python.
My suggestion is to use the SimPy Manufacture framework, which I developed.
The SimPy Manufacture simulation environment uses the SimPy runtime system, but implements simulation with higher-level blocks or their combination.
 
In SimPy Manufacture , there are the following objects:
Object naming
Task
TENTITY
The worker object.
TSOURCE
TENTITY emits objects with a specified time distribution.
TBUFFER
Implements staging of TENTITY objects.
TMACHINE
Delays the further progression of TENTITY objects.
TSINK
Removes TENTITY objects from the simulation system.
TWRAPPER
Stores ENTITIES in another entity according to a specified recipe.
TUNWRAPPER
Unzip TENTITY objects that are packaged with the TWRAPPER object.
and a few more...
 
 
The general structure of SimPy Objects is as follows:

The input and output channels of SimPy Objects can be connected using TCONNECTION objects. Only one input can be connected to an output!
With these basic objects, any manufacturing network can be created, using serial parallel or loopback network implementation. Each SimPy Object may contain a custom procedure.
 
(The illustration was created in LabVIEW.)
 
Objects in SimPy Manufacture models are stored in an TOBJECT_LIST, and relationships between objects are stored in a TCONNECT_LIST object. There is also a list of current TENTITIES in the model TENTITY_LIST, and TENTITIES that have left the simulation model are objects of the TSINKED_ENTITY_LIST. All these elements are contained in the TNET object, which provides a way to access data for all model elements.
SimPy Manufacture is primarily suitable for running simulation models with a large number of elements, which can solve any DES task.
 

 
For example, a diagram of a Circular Manufacturing System block might look like this:
 
 
Among the elements of the SimPy Manufacture system, the TBUFFER, TSINK, TWRAPPER, TUNWRAPPER elements determine the state of the object with a given sampling time (sampling_time). The sampling duration is cca. 0.1 (1/10) of the minimum "time_step" value of TMACHINE objects. Thus, results of sufficient accuracy with an acceptable calculation period are obtained. (The illustrations were created in LabVIEW.)
 
 My access options:
SkyPe Name: lipo...@gmail.com
  
Kind regards
Lipovszki György
 
Attachments:
  1. &_001_MAIN_SimPy_Manufacture_VERY_SIMPLE_01.png
    A very simple system block diagram.
  2. &_001_MAIN_SimPy_Manufacture_VERY_SIMPLE_01.py
    The former is a simple system SimPy Python program.
  3. SimPy_Result_ENTITY_LIST.txt
    Simple sample TENTITY result file
  4. SimPy_Result_SUMMARY_REPORT.txt
    A list of simple sample summary results.
  5. SimPy Python Presentation (ENG) (2024-10-07).pdf
    Presentation on how SimPy Manufacture works


Feladó: python...@googlegroups.com <python...@googlegroups.com>, meghatalmazó: Carter Frostad <carter...@gmail.com>
Elküldve: 2024. október 16., szerda 22:26
Címzett: python-simpy <python...@googlegroups.com>
Tárgy: [SimPy] Re: Simple Job Flow Shop, but part returns to first machine again
 
--
You received this message because you are subscribed to the Google Groups "python-simpy" group.
To unsubscribe from this group and stop receiving emails from it, send an email to python-simpy...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/python-simpy/89c07dd0-c6d2-4bd9-88af-6d7c6d69efdcn%40googlegroups.com.
&_001_MAIN_SimPy_Manufacture_VERY_SIMPLE_01.png
&_001_MAIN_SimPy_Manufacture_VERY_SIMPLE_01.py
SimPy Python Presentation (ENG) (2024-10-07).pdf
SimPy_Result_ENTITY_LIST.txt
SimPy_Result_SUMMARY_REPORT.txt
__Carter Frostad_01 (ENG).docx

rt.van....@gmail.com

unread,
Oct 17, 2024, 10:17:02 AM10/17/24
to python-simpy
@ Lipovszki György
Your SimPy Manufacture sounds very interesting.
Where can I find the required modules?
And: is LabView a requirement?

Lipovszki György

unread,
Oct 17, 2024, 10:29:51 AM10/17/24
to rt.van....@gmail.com, python-simpy
from György Lipovszki

>> And: is LabView a requirement?
No there is no requirement you can make the SimPy Manufacture source code "by hand".
(But if you have hundreds of blocks in the model the LabVIEW program is very useful.)

>>Where can I find the required modules?
Please call me on SkyPe to talk about the details.



Feladó: python...@googlegroups.com <python...@googlegroups.com>, meghatalmazó: rt.van....@gmail.com <rt.van....@gmail.com>
Elküldve: 2024. október 17., csütörtök 16:17
Címzett: python-simpy <python...@googlegroups.com>
Tárgy: Re: [SimPy] Re: Simple Job Flow Shop, but part returns to first machine again
 

Sean Reed

unread,
Oct 17, 2024, 10:55:41 AM10/17/24
to Lipovszki György, rt.van....@gmail.com, python-simpy
If you are looking for a library for manufacturing process simulation built on top of SimPy there is also the open source ManPy, although it is no longer actively maintained. This is a Python 3 port: 

Sean
You received this message because you are subscribed to a topic in the Google Groups "python-simpy" group.
To unsubscribe from this group and all its topics, send an email to python-simpy...@googlegroups.com.

ManPy_documentation.pdf

Carter Frostad

unread,
Oct 17, 2024, 11:03:10 AM10/17/24
to python-simpy
See now this is why I'm here. So I don't spend 2 months coding something where it's fundamental architecture prevents me from accomplishing what I'm ultimately trying to do. It seems like a similar concept to Sean, set up discrete entities that get fed a queue, do something, then pass to another entities queue. 

I was worried that his solution was great from a programming standpoint, but difficult to make quick iterations of different machines, so this graphical element is really interesting. I've seen ManPy before, but it doesn't have much support anymore so I didn't look too deeply at it. Is that the module you made?

Sean Reed

unread,
Oct 17, 2024, 11:47:18 AM10/17/24
to python-simpy
No, I'm not a contributor to ManPy. SimPy is "only" a discrete event simulation engine that manages the event synchronisation and clock, with a few extras such as resource models etc. So there are no fundamental architectural limitations that could prevent you from doing something, you are limited only by your imagination, programming abilities, and time. However, you will need to program or choose libraries, for everything you want, like graphics and logging. There is also salabim, which is a Python library for DES that is similar to SimPy but includes some additional built-in modules for things like animations and monitoring. If you want a drag and drop based tool with a GUI, similar to commercial DES software, where you can move machines around with your mouse in the model space etc. then I suggest you look at JaamSim.
You received this message because you are subscribed to a topic in the Google Groups "python-simpy" group.
To unsubscribe from this group and all its topics, send an email to python-simpy...@googlegroups.com.
Reply all
Reply to author
Forward
0 new messages