main
hy.kim 1 year ago
parent d9b2089213
commit 13f0f7511a

@ -0,0 +1,555 @@
{
"cells": [
{
"attachments": {},
"cell_type": "markdown",
"metadata": {},
"source": [
"# Durable Rules로 규칙 구현하기\n",
"- 산업인공지능학과 대학원\n",
" 2022254026\n",
" 김홍열"
]
},
{
"attachments": {},
"cell_type": "markdown",
"metadata": {},
"source": [
"### Durable Rules 란?\n",
"* 비즈니스 룰 엔진을 구현하기 위한 라이브러리로 python, ruby, nodejs로 구현할 수 있다."
]
},
{
"attachments": {},
"cell_type": "markdown",
"metadata": {},
"source": [
"### Durable Rules 설치하기 (Python)\n",
"``` plantext\n",
"pip install durable_rules"
]
},
{
"attachments": {},
"cell_type": "markdown",
"metadata": {},
"source": [
"### Durable Rules 다운로드\n",
"[github - jruizgit/rules](https://github.com/jruizgit/rules)"
]
},
{
"attachments": {},
"cell_type": "markdown",
"metadata": {},
"source": [
"##### 패키지 불러오기"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [],
"source": [
"from durable.lang import *"
]
},
{
"attachments": {},
"cell_type": "markdown",
"metadata": {},
"source": [
"#### 구현할 규칙\n",
"![2차전지 라인 구성도](./images/2ndBatteryLine.png)\n",
"> 규칙\n",
"``` plain\n",
"1. IF Input Left_JR AND Right_JR\n",
"\t\tTHEN Form JR\n",
"\t\t\n",
"2. IF Form Left_JR AND Right_JR\n",
"\t\tTHEN Cut Left_JR AND Right_JR\n",
"\t\t\n",
"3. IF Cut Left_JR AND Right_JR\n",
"\t\tTHEN Align Left_JR AND Right_JR\n",
"\t\t\n",
"4. IF Pass Align Vision_Inspection\n",
"\t\tTHEN Return Result_None\n",
"\t\tAND F&C&T\n",
"\n",
"5. ELSE Align Vision_Inspection\n",
"\t\tTHEN Move Left Point\n",
"\t\tAND Move Right Point\n",
"\n",
"6. IF Move Left And Right Point\n",
"\t\tTHEN Align Vision_Inspection\n",
"\t\tAND Retrun Result_OK\n",
"\t\t\tOR Retrun Result_NG\n",
"\t\tAND F&C&T\n",
"\t\t\n",
"7. IF Pass F&C&T Vision_Inspection\n",
"\t\tTHEN Return Result_None\n",
"\t\tAND I&T\n",
"\n",
"8. ELSE F&C&T Vision_Inspection\n",
"\t\tTHEN Front Vision_Inspection\n",
"\t\tAND Rear Vision_Inspection\n",
"\t\tAND Retrun Result_OK\n",
"\t\t\tOR Retrun Result_NG\n",
"\n",
"9. IF Front AND Rear Vision_Inspection\n",
"\t\tTHEN Rotate JR\n",
"\n",
"10. IF Rotate JR\n",
"\t\tTHEN Left Vision_Inspection\n",
"\t\tAND Right Vision_Inspection\n",
"\t\tAND Retrun Result_OK\n",
"\t\t\tOR Retrun Result_NG\n",
"\t\tAND I&T\n",
"\n",
"11. IF Pass I&T Vision_Inspection\n",
"\t\tTHEN Return Result_None\n",
"\t\tAND C&W\n",
"\t\t\n",
"12. ELSE I&T Vision_Inspection\n",
"\t\tTHEN Left Vision_Inspection\n",
"\t\tAND Right Vision_Inspection\n",
"\t\tAND Retrun Result_OK\n",
"\t\t\tOR Retrun Result_NG\n",
"\t\t\n",
"13. IF Left AND Right Vision_Inspection\n",
"\t\tTHEN Move Up JR\n",
"\t\tAND Rotate JR\n",
"\t\t\n",
"14. IF Rotate JR\n",
"\t\tTHEN Front Vision_Inspection\n",
"\t\tAND Rear Vision_Inspection\n",
"\t\tAND Retrun Result_OK\n",
"\t\t\tOR Retrun Result_NG\n",
"\t\tAND C&W\n",
"\t\t\n",
"15. IF Pass C&W Vision_Inspection\n",
"\t\tTHEN Return None Result\n",
"\t\tAND R&T\n",
"\t\t\n",
"16. ELSE C&W Vision_Inspection\n",
"\t\tTHEN Left Vision_Inspection\n",
"\t\tAND Right Vision_Inspection\n",
"\t\tAND Retrun Result_OK\n",
"\t\t\tOR Retrun Result_NG\n",
"\t\tAND R&T\n",
"\t\t\n",
"17. IF Pass R&T Vision_Inspection\n",
"\t\tTHEN Return Result_None\n",
"\t\tAND Wrapping\n",
"\t\t\n",
"18. ELSE R&T Vision_Inspection\n",
"\t\tTHEN Left Vision_Inspection\n",
"\t\tAND Right Vision_Inspection\n",
"\t\tAND Retrun Result_OK\n",
"\t\t\tOR Retrun Result_NG\n",
"\t\tAND Wrapping\n",
"\t\t\n",
"19. IF Pass Wrapping Vision_Inspection\n",
"\t\tTHEN Return Result_None\n",
"\t\tAND C&C&W\n",
"\t\t\n",
"20. ELSE Wrapping Vision_Inspection\n",
"\t\tTHEN Front Vision_Inspection\n",
"\t\tAND Rear Vision_Inspection\n",
"\t\tAND Retrun Result_OK\n",
"\t\t\tOR Retrun Result_NG\n",
"\t\t\n",
"21. IF Front AND Rear Vision_Inspection\n",
"\t\tTHEN Rotate JR\n",
"\t\t\n",
"22. IF Rotate JR\n",
"\t\tTHEN Left Vision_Inspection\n",
"\t\tAND Right Vision_Inspection\n",
"\t\tAND Retrun Result_OK\n",
"\t\t\tOR Retrun Result_NG\n",
"\t\t\n",
"23. IF Left AND Right Vision_Inspection\n",
"\t\tTHEN Retrun Result_OK\n",
"\t\t\tOR Retrun Result_NG\n",
"\t\tAND C&C&W\n",
"\t\t\n",
"24. IF Pass C&C&W Vision_Inspection\n",
"\t\tTHEN Return Result_None\n",
"\t\t\n",
"25. ELSE C&C&W Vision_Inspection\n",
"\t\tTHEN Long_Axis Vision_Inspection\n",
"\t\tAND Retrun Result_OK\n",
"\t\t\tOR Retrun Result_NG\n",
"\n",
"26. IF Long_Axis Vision_Inspection\n",
"\t\tTHEN Retrun Result_OK\n",
"\t\t\tOR Retrun Result_NG\n",
"\t\tAND Rotate JR\n",
"\n",
"27. IF Rotate JR\n",
"\t\tTHEN Short_Axis Vision_Inspection\n",
"\t\tAND Retrun Result_OK\n",
"\t\t\tOR Retrun Result_NG"
]
},
{
"attachments": {},
"cell_type": "markdown",
"metadata": {},
"source": [
"### 1. 각 라인 공정별 StateFlow 구현"
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [],
"source": [
"from durable.lang import *\n",
"\n",
"inspectionResult = ['OK','OK','OK','OK','OK','OK','OK'] #\n",
"def updateState(s, m): # \n",
" s.JobID = m.JobID\n",
" s.Pass = m.Pass\n",
" s.Left = m.Left\n",
" s.Right = m.Right\n",
" s.Judge0 = m.Judge0\n",
" s.Judge1 = m.Judge1\n",
" s.Judge2 = m.Judge2\n",
" s.Judge3 = m.Judge3\n",
" s.Judge4 = m.Judge4\n",
" s.Judge5 = m.Judge5\n",
" s.Judge6 = m.Judge6\n",
"\n",
"\n",
"with flowchart('battery_assembley_process'):\n",
" with stage('Input'):\n",
" @run\n",
" def nextToJR(c):\n",
" print('>> current stage is Input')\n",
" updateState(c.s, c.m)\n",
" print ('Input JobID: {0}'.format(c.m.JobID))\n",
"\n",
" to('JR').when_all((m.JobID != None))\n",
" to('Alarm').when_all((m.JobID == None))\n",
" \n",
" \n",
" with stage('JR'):\n",
" @run\n",
" def nextToF_C(c):\n",
" print('> current stage is JR')\n",
" updateState(c.s, c.m) # JobID는 전달되나 나머지 파라미터들은 전달되지 않음\n",
" print(c.s.Judge)\n",
" if c.m.Left is None: # @when_all(m.Left != None) 조건으로 함수를 별도로도 생성해보았으나 인식 안 됨\n",
" print('Alarm: Did not receive the Left JR.')\n",
" if c.m.Right is None:\n",
" print('Alarm: Did not receive the Right JR.')\n",
" if c.m.Left is not None and c.m.Right is not None:\n",
" print ('Both the Left JR[{0}] and the Right JR[{1}] have been assembled.'.format(c.m.Left, c.m.Right))\n",
" \n",
" to('Alarm').when_any((m.Left == None),\n",
" (m.Right == None))\n",
" to('F&C')\n",
"\n",
" with stage('F&C'):\n",
" @run\n",
" def NextToAlign(c):\n",
" print ('> current stage is F&C')\n",
" updateState(c.s, c.m)\n",
" if c.m.Pass is False:\n",
" print('F&C Inspection has been processed.')\n",
" print(f'F&C Judgement: {inspectionResult[0]}.')\n",
" else:\n",
" print('F&C Inspection is passed.')\n",
"\n",
" to('Align')\n",
"\n",
" with stage('Align'):\n",
" @run\n",
" def NextToI_T(c):\n",
" print ('> current stage is Align')\n",
" updateState(c.s, c.m)\n",
" if c.m.Pass is False:\n",
" print('Align Inspection has been processed.')\n",
" print(f'F&C Judgement: {inspectionResult[1]}.')\n",
" else:\n",
" print('Align Inspection is passed.')\n",
"\n",
" to('I&T')\n",
"\n",
" with stage('I&T'):\n",
" @run\n",
" def NextToCAPWelding(c):\n",
" print ('> current stage is I&T')\n",
" updateState(c.s, c.m)\n",
" if c.m.Pass is False:\n",
" print('I&T Inspection has been processed.')\n",
" print(f'F&C Judgement: {inspectionResult[2]}.')\n",
" else:\n",
" print('I&T Inspection is passed.')\n",
"\n",
" to('CAPWelding')\n",
"\n",
" with stage('CAPWelding'):\n",
" @run\n",
" def NextToRetainer(c):\n",
" print ('> current stage is CAPWelding')\n",
" updateState(c.s, c.m)\n",
" if c.m.Pass is False:\n",
" print('CAPWelding Inspection has been processed.')\n",
" print(f'F&C Judgement: {inspectionResult[3]}.')\n",
" else:\n",
" print('CAPWelding Inspection is passed.')\n",
"\n",
" to('Retainer')\n",
"\n",
" with stage('Retainer'):\n",
" @run\n",
" def NextToWrapping(c):\n",
" print ('> current stage is Retainer')\n",
" updateState(c.s, c.m)\n",
" if c.m.Pass is False:\n",
" print('Retainer Inspection has been processed.')\n",
" print(f'F&C Judgement: {inspectionResult[4]}.')\n",
" else:\n",
" print('Retainer Inspection is passed.')\n",
"\n",
" to('Wrapping')\n",
"\n",
" with stage('Wrapping'):\n",
" @run\n",
" def NextToC_CWelding(c):\n",
" print ('> current stage is Wrapping')\n",
" updateState(c.s, c.m)\n",
" if c.m.Pass is False:\n",
" print('Wrapping Inspection has been processed.')\n",
" print(f'F&C Judgement: {inspectionResult[5]}.')\n",
" else:\n",
" print('Wrapping Inspection is passed.')\n",
"\n",
" to('C&CWelding')\n",
"\n",
" with stage('C&CWelding'):\n",
" @run\n",
" def InspectionComplete(c):\n",
" print ('> current stage is C&CWelding')\n",
" updateState(c.s, c.m)\n",
" # c.s.JobID = c.m.JobID\n",
" # c.s.Pass = c.m.Pass\n",
" # c.s.Left = c.m.Left\n",
" # c.s.Right = c.m.Right\n",
" # c.s.Judge0 = c.m.Judge0\n",
" # c.s.Judge1 = c.m.Judge1\n",
" # c.s.Judge2 = c.m.Judge2\n",
" # c.s.Judge3 = c.m.Judge3\n",
" # c.s.Judge4 = c.m.Judge4\n",
" # c.s.Judge5 = c.m.Judge5\n",
" # c.s.Judge6 = c.m.Judge6\n",
" if c.m.Pass is False:\n",
" print('C&CWelding Inspection has been processed.')\n",
" # inspectionResult[6] = 'TEST'\n",
" # c.s.Judge6 = c.m.Judge6 = 'NG'\n",
" print(f'F&C Judgement: {inspectionResult[6]}.')\n",
" else:\n",
" print('C&CWelding Inspection is passed.')\n",
"\n",
" to('Output')\n",
"\n",
" with stage('Output'):\n",
" @run\n",
" def InspectionComplete(c):\n",
" print ('> current stage is Output')\n",
" result = 'OK'\n",
" for rst in inspectionResult:\n",
" if rst == 'NG':\n",
" result = 'NG'\n",
" break\n",
" # print(inspectionResult)\n",
" # print (result)\n",
" # print(c.s.JobID)\n",
" # print(c.s.Judge)\n",
" # print(c.s.Judge6)\n",
" print ('JobID[{0}]\\'s Result is {1}'.format(c.s.JobID, result))\n",
"\n",
" with stage('Alarm'):\n",
" @run\n",
" def Log(c):\n",
" print ('The process will not proceed due to an alarm being triggered. - [JobID: ' + str(c.m.JobID) + ']')"
]
},
{
"attachments": {},
"cell_type": "markdown",
"metadata": {},
"source": [
"### 2. Input Data 구현"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
">> current stage is Input\n",
"The process will not proceed due to an alarm being triggered. - [JobID: None]\n",
">> current stage is Input\n",
"> current stage is JR\n",
"> current stage is F&C\n",
"> current stage is Align\n",
"> current stage is I&T\n",
"> current stage is CAPWelding\n",
"> current stage is Retainer\n",
"> current stage is Wrapping\n",
"> current stage is C&CWelding\n",
"> current stage is Output\n",
"JobID[20230417]'s Result is OK\n",
">> current stage is Input\n",
"> current stage is JR\n",
"> current stage is F&C\n",
"> current stage is Align\n",
"> current stage is I&T\n",
"> current stage is CAPWelding\n",
"> current stage is Retainer\n",
"> current stage is Wrapping\n",
"> current stage is C&CWelding\n",
"> current stage is Output\n",
"JobID[20230418]'s Result is OK\n",
">> current stage is Input\n",
"> current stage is JR\n",
"> current stage is F&C\n",
"> current stage is Align\n",
"> current stage is I&T\n",
"> current stage is CAPWelding\n",
"> current stage is Retainer\n",
"> current stage is Wrapping\n",
"> current stage is C&CWelding\n",
"> current stage is Output\n",
"JobID[20230419]'s Result is NG\n"
]
},
{
"data": {
"text/plain": [
"{'sid': '3',\n",
" 'id': 'sid-3',\n",
" '$s': 1,\n",
" 'running': True,\n",
" 'exception': 'exception caught \\'NoneType\\' object has no attribute \\'JobID\\', traceback [\\' File \"/config/.local/lib/python3.10/site-packages/durable/engine.py\", line 241, in run\\\\n self._func(c)\\\\n\\', \\' File \"/tmp/ipykernel_31962/4233634066.py\", line 129, in InspectionComplete\\\\n updateState(c.s, c.m)\\\\n\\', \\' File \"/tmp/ipykernel_31962/4233634066.py\", line 5, in updateState\\\\n s.JobID = m.JobID\\\\n\\']',\n",
" 'JobID': '20230419',\n",
" 'Pass': False,\n",
" 'Left': 100,\n",
" 'Right': 100}"
]
},
"execution_count": 2,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# 만들어진 규칙에 넣을 데이터들, 라인에 들어가는 각 배터리의 정보\n",
"post('battery_assembley_process', { 'JobID': None,\n",
" 'Pass': False,\n",
" 'Left': 100,\n",
" 'Right': 100,\n",
" # 'Judge0': None,\n",
" # 'Judge1': None,\n",
" # 'Judge2': None,\n",
" # 'Judge3': None,\n",
" # 'Judge4': None,\n",
" # 'Judge5': None,\n",
" # 'Judge6': None})\n",
" 'Judge':[None, None, None, None, None, None, None]})\n",
"post('battery_assembley_process', { 'sid': 1,\n",
" 'JobID': '20230417', \n",
" 'Pass': False,\n",
" 'Left': 100,\n",
" 'Right': None,\n",
" # 'Judge0': None,\n",
" # 'Judge1': None,\n",
" # 'Judge2': None,\n",
" # 'Judge3': None,\n",
" # 'Judge4': None,\n",
" # 'Judge5': None,\n",
" # 'Judge6': None})\n",
" 'Judge':[None, None, None, None, None, None, None]})\n",
"post('battery_assembley_process', { 'sid': 2,\n",
" 'JobID': '20230418', \n",
" 'Pass': False,\n",
" 'Left': None,\n",
" 'Right': 100,\n",
" # 'Judge0': None,\n",
" # 'Judge1': None,\n",
" # 'Judge2': None,\n",
" # 'Judge3': None,\n",
" # 'Judge4': None,\n",
" # 'Judge5': None,\n",
" # 'Judge6': None})\n",
" 'Judge':[None, None, None, None, None, None, None]})\n",
"\n",
"inspectionResult = ['OK','OK','OK','OK','NG','OK','OK'] # 내부적으로 Judege를 접근해서 변경할 수 없어서 테스트용으로 생성함\n",
"post('battery_assembley_process', { 'sid': 3,\n",
" 'JobID': '20230419', \n",
" 'Pass': False,\n",
" 'Left': 100,\n",
" 'Right': 100,\n",
" 'Judge0': None,\n",
" 'Judge1': None,\n",
" 'Judge2': None,\n",
" 'Judge3': None,\n",
" 'Judge4': None,\n",
" 'Judge5': None,\n",
" 'Judge6': 'OK'})\n",
" # 'Judge':[None, None, None, None, None, None, None]}) # Array를 제공하는듯 보이지만 allitems 같은 불편함을 감수해야됨\n"
]
},
{
"attachments": {},
"cell_type": "markdown",
"metadata": {},
"source": [
"### 결과\n",
"* Durable_rule에서 사용되는 규칙을 별도로 습득 해야됨\n",
"* 내부적으로 메모리에 저장되는 것들을 접근하거나 디버깅할 수 없음\n",
"* 위 코드는 flowchart를 사용하였지만, statechart나 ruleset을 사용하여도 post를 상태마다 날려야 됨\n",
"* 내부적으로 어떻게 병렬처리 되는지 커스터마이징 할 수 없음\n",
"* 실무에 적용하기에 라이센스나 개발환경에 제약이 많음\n",
"* 상태패턴을 구현해서 직접 제어하는 것이 훨씬 효율적으로 보임"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": []
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.10.6"
},
"orig_nbformat": 4
},
"nbformat": 4,
"nbformat_minor": 2
}

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff
Loading…
Cancel
Save