flexsim--第二周

本周说明及总结:

本周我继续学习了Flexsim的相关基础操作,同时,我本周主要探索了Flexsim与MySQL的互通,以及Flexsim在强化学习和调度策略优化上的内容。

主要目的是探索一下Flexsim在编程方面的自由度以及可以与我们目前的系统交互的程度。

目前明确的信息有:

  1. Flexsim支持与MySQL的互通,支持SQL语句,内部可以进行查询和过滤,具备一定的实时通信能力,但是可靠性、通信效率还需要进一步验证
  2. Flexsim支持编程式的任务调度,灵活性尚可。
  3. Flexsim 2019支持深度学习和强化学习,目前2019没有找到非试用版的资源,所以这个功能目前无法体验,但是根据其他博文和官网的说明,flexsim强化学习和部分数据分析的实现方式是python,可以通过自训练模型,自行编程的方式进行优化和定制,示例见正文。

目前的学习和研究方向:

  1. Flexsim可以实现的调度算法和策略优化,以及其对python的支持
  2. Flexsim与MySQL通信的可靠性、查询的效率
  3. 进一步对C++相关语言和flexsim的任务调度模块进行熟悉,争取下周实现一个模块。

Flexsim与Python连接样例:

import gym
import os
import subprocess
import socket
import json
from gym import error, spaces, utils
from gym.utils import seeding
import numpy as np

class FlexSimEnv(gym.Env):
    metadata = {'render.modes': ['human', 'rgb_array', 'ansi']}

    def __init__(self, flexsimPath, modelPath, address='localhost', port=5005, verbose=False, visible=False):
        self.flexsimPath = flexsimPath
        self.modelPath = modelPath
        self.address = address
        self.port = port
        self.verbose = verbose
        self.visible = visible

        self.lastObservation = ""

        self._launch_flexsim()
        
        self.action_space = self._get_action_space()
        self.observation_space = self._get_observation_space()

    def reset(self):
        self._reset_flexsim()
        state, reward, done = self._get_observation()
        return state

    def step(self, action):
        self._take_action(action)
        state, reward, done = self._get_observation()
        info = {}
        return state, reward, done, info

    def render(self, mode='human'):
        if mode == 'rgb_array':
            return np.array([0,0,0])
        elif mode == 'human':
            print(self.lastObservation)
        elif mode == 'ansi':
            return self.lastObservation
        else:
            super(FlexSimEnv, self).render(mode=mode)

    def close(self):
        self._close_flexsim()
        
    def seed(self, seed=None):
        self.seedNum = seed
        return self.seedNum

    
    def _launch_flexsim(self):
        if self.verbose:
            print("Launching " + self.flexsimPath + " " + self.modelPath)

        args = [self.flexsimPath, self.modelPath, "-training", self.address + ':' + str(self.port)]
        if self.visible == False:
            args.append("-maintenance")
            args.append("nogui")
        self.flexsimProcess = subprocess.Popen(args)

        self._socket_init(self.address, self.port)
    
    def _close_flexsim(self):
        self.flexsimProcess.kill()

    def _release_flexsim(self):
        if self.verbose:
            print("Sending StopWaiting message")
        self._socket_send(b"StopWaiting?")

    def _get_action_space(self):
        self._socket_send(b"ActionSpace?")
        if self.verbose:
            print("Waiting for ActionSpace message")
        actionSpaceBytes = self._socket_recv()
        
        return self._convert_to_gym_space(actionSpaceBytes)

    def _get_observation_space(self):
        self._socket_send(b"ObservationSpace?")
        if self.verbose:
            print("Waiting for ObservationSpace message")
        observationSpaceBytes = self._socket_recv()
        
        return self._convert_to_gym_space(observationSpaceBytes)

    def _reset_flexsim(self):
        if self.verbose:
            print("Sending Reset message")
        resetString = "Reset?"
        if hasattr(self, "seedNum"):
            resetString = "Reset:" + str(self.seedNum) + "?"
        self._socket_send(resetString.encode())

    def _get_observation(self):
        if self.verbose:
            print("Waiting for Observation message")
        observationBytes = self._socket_recv()
        self.lastObservation = observationBytes.decode('utf-8')
        state, reward, done = self._convert_to_observation(observationBytes)

        return state, reward, done
    
    def _take_action(self, action):
        actionStr = json.dumps(action, cls=NumpyEncoder)
        if self.verbose:
            print("Sending Action message: " + actionStr)
        actionMessage = "TakeAction:" + actionStr + "?"
        self._socket_send(actionMessage.encode())


    def _socket_init(self, host, port):
        if self.verbose:
            print("Waiting for FlexSim to connect to socket on " + self.address + ":" + str(self.port))

        self.serversocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.serversocket.bind((host, port))
        self.serversocket.listen();

        (self.clientsocket, self.socketaddress) = self.serversocket.accept()
        if self.verbose:
            print("Socket connected")
        
        if self.verbose:
            print("Waiting for READY message")
        message = self._socket_recv()
        if self.verbose:
            print(message.decode('utf-8'))
        if message != b"READY":
            raise RuntimeError("Did not receive READY! message")

    def _socket_send(self, msg):
        totalsent = 0
        while totalsent < len(msg):
            sent = self.clientsocket.send(msg[totalsent:])
            if sent == 0:
                raise RuntimeError("Socket connection broken")
            totalsent = totalsent + sent

    def _socket_recv(self):
        chunks = []
        while 1:
            chunk = self.clientsocket.recv(2048)
            if chunk == b'':
                raise RuntimeError("Socket connection broken")
            if chunk[-1] == ord('!'):
                chunks.append(chunk[:-1])
                break;
            else:
                chunks.append(chunk)
        return b''.join(chunks)


    def _convert_to_gym_space(self, spaceBytes):
        paramsStartIndex = spaceBytes.index(ord('('))
        paramsEndIndex = spaceBytes.index(ord(')'), paramsStartIndex)
        
        type = spaceBytes[:paramsStartIndex]
        params = json.loads(spaceBytes[paramsStartIndex+1:paramsEndIndex])
        
        if type == b'Discrete':
            return gym.spaces.Discrete(params)
        elif type == b'Box':
            return gym.spaces.Box(np.array(params[0]), np.array(params[1]))
        elif type == b'MultiDiscrete':
            return gym.spaces.MultiDiscrete(params)
        elif type == b'MultiBinary':
            return gym.spaces.MultiBinary(params)

        raise RuntimeError("Could not parse gym space string")

    def _convert_to_observation(self, spaceBytes):
        observation = json.loads(spaceBytes)
        state = observation["state"]
        if isinstance(state, list):
            state = np.array(observation["state"])
        reward = observation["reward"]
        done = (observation["done"] == 1)
        return state, reward, done


class NumpyEncoder(json.JSONEncoder):
    def default(self, obj):
        if isinstance(obj, np.integer):
            return int(obj)
        elif isinstance(obj, np.floating):
            return float(obj)
        elif isinstance(obj, np.ndarray):
            return obj.tolist()
        return json.JSONEncoder.default(self, obj)


def main():

    env = FlexSimEnv(
        flexsimPath = "C:/Program Files/FlexSim 2022/program/flexsim.exe",
        modelPath = "E:/Flexsim/demo/ChangeoverTimesRL.fsm",
        verbose = True,
        visible = True
        )

    for i in range(2):
        env.seed(i)
        observation = env.reset()
        env.render()
        done = False
        rewards = []
        while not done:
            action = env.action_space.sample()
            observation, reward, done, info = env.step(action)
            env.render()
            rewards.append(reward)
            if done:
                cumulative_reward = sum(rewards)
                print("Reward: ", cumulative_reward, "\n")
    env._release_flexsim()
    input("Waiting for input to close FlexSim...")
    env.close()


if __name__ == "__main__":
    main()

Flexsim与MySQL数据库连接

 可以通过查询语句对数据进行过滤,将其配置到flexsim的全局表中,以备后续的处理。

  •  flexsim本身内部支持查询和过滤,但仍然建议在导入数据源时进行过滤,因为数据库引擎的查询过滤速度比flexsim内部快得多

示例:

Database.Connection con=Database.Connection("DBConnector1");//“DBConnector1”是Database Connectors 上连接的名字。
con.connect();//连接
Table table=Model.find("Source1>variables/schedule");//获取发生器Schedule的表结构。
Database.ResultSet set1=con.query("SELECT * FROM new_table");//new_table 是在SQL数据库里创建的一个Table的名字。

int rowCount=1;
while(set1.fetchNext())//自动调到数据库下一行数据(如果没有下一行就跳出)
{
	if(table.numRows<rowCount)
	{
		table.addRow();
	}

	for(int i=1;i<=set1.numFields;i++)//numFields是数据库中Table的字段数。
	{
		Variant val = set1[i];
		table[rowCount][i]=val;
	}
	rowCount++;
}
con.disconnect();//断开连接

部分触发和任务调度样例

//进入触发
if (port == 2) 
{  
	int de=item.B_ID;
  Table thelist = getvarnode(current, "componentlist");
  treenode thesum = getvarnode(current, "targetcomponentsum");
 // thesum.value = 0;
  for(int index = 1; index <= thelist.numRows; index++) 
  {
   thelist[index][1] = item.B_ID;
    //inc(thesum, item.B_ID);
  }
}
//离开触发
item.labels.assert("B_ID").value = item.first.B_ID;
item.labels.assert("ID").value = item.first.ID;
//把产品上的标识赋值给下面的托盘。
treenode BF=Model.find("BasicFR1");//就是之前拉入的BasicFR,这边需要注意名字要一样,或者改成你model中BF的名字;
int Queue_num=token.Q_01.subnodes.length;//再次获取缓存区中产品的数量值,确定for循环的次数。
Array save_item=Model.find("BasicFR1").save_item;//获取BF上的Array数组(以下简称BF);
Array Save=up(token.Pallet).save;//获取Tote存放的Queue上的Array数组(以下简称Qu);
for(int i=1;i<=Queue_num;i++)
{
	treenode item=token.Q_01.subnodes[i];
	string item_id=item.ID;
	for(int j=1;j<=Save.length;j++)
	{
		string order_id=Save[j];
		if(item_id==order_id)//如果缓存区中有产品属于当前订单组成部分,则把Qu中该产品编号从数组中剔除出去,并在BF中添加被剔除的产品编号
		{
			Save.splice(j,1);
			save_item.append([order_id]);
			break;
		}
	}	
}
int array_num=save_item.length;
if(array_num == 4)//获取BF数组长度,如果长度==4,说明目前产品已满足订单需求;如果长度==0,说明目前产品不属于该订单;
{
	BF.panduan = 1;
}
else if(array_num ==0)
{
	BF.panduan = 3;
}
else
{
	BF.panduan = 2;
}

  • 0
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值