diff --git a/AGVEmulator/RunCode/_BMS.cs b/AGVEmulator/RunCode/_BMS.cs index e58fc8e..7d09e4a 100644 --- a/AGVEmulator/RunCode/_BMS.cs +++ b/AGVEmulator/RunCode/_BMS.cs @@ -12,9 +12,9 @@ namespace AGVEmulator { private void BMS_Message(object sender, AR.Dev.RS232.MessageEventArgs e) { - - logBMS.Add(e.Message); - + + logBMS.Add(e.Message); + } private void BMS_RequestVoltageData(object sender, DevBMS.RequestVoltageDataArgs e) @@ -26,7 +26,7 @@ namespace AGVEmulator this.cellvolt[i] = (UInt16)rnd.Next(3300, 3350); } Array.Copy(this.cellvolt, 0, e.cellVolt, 0, 8); - + this.btc1.Invoke(new Action(() => { var idx = 0; @@ -46,8 +46,12 @@ namespace AGVEmulator if (checkBox1.Checked) this.trackBar1.Invoke(new Action(() => { - this.trackBar1.Value -= 1; - trackBar1_Scroll(null, null); + if (this.trackBar1.Value > 0) + { + this.trackBar1.Value -= 1; + trackBar1_Scroll(null, null); + } + })); e.CurA = (int)BMS_CurA; diff --git a/NewMap.json b/NewMap.json new file mode 100644 index 0000000..7e4b542 --- /dev/null +++ b/NewMap.json @@ -0,0 +1,1030 @@ +{ + "Nodes": [ + { + "Text": "Unloader", + "StationType": 3, + "CanDocking": true, + "DockDirection": 2, + "ConnectedNodes": [ + "12" + ], + "CanTurnLeft": true, + "CanTurnRight": true, + "DisableCross": false, + "SpeedLimit": 0, + "AliasName": "", + "IsActive": true, + "RfidId": 1, + "NodeTextForeColor": "White", + "NodeTextFontSize": 30.0, + "ID2": "0001(*N001)", + "Id": "N001", + "Type": 0, + "Position": "298, 270" + }, + { + "Text": "Cleaner", + "StationType": 2, + "CanDocking": true, + "DockDirection": 2, + "ConnectedNodes": [ + "5" + ], + "CanTurnLeft": true, + "CanTurnRight": true, + "DisableCross": false, + "SpeedLimit": 0, + "AliasName": "", + "IsActive": true, + "RfidId": 11, + "NodeTextForeColor": "", + "NodeTextFontSize": 7.0, + "ID2": "0011(*N010)", + "Id": "N010", + "Type": 0, + "Position": "298, 446" + }, + { + "Text": "Loader", + "StationType": 1, + "CanDocking": true, + "DockDirection": 0, + "ConnectedNodes": [ + "6" + ], + "CanTurnLeft": true, + "CanTurnRight": true, + "DisableCross": false, + "SpeedLimit": 0, + "AliasName": "", + "IsActive": true, + "RfidId": 8, + "NodeTextForeColor": "", + "NodeTextFontSize": 7.0, + "ID2": "0008(*N014)", + "Id": "N014", + "Type": 0, + "Position": "520, 653" + }, + { + "Text": "Chg #1", + "StationType": 5, + "CanDocking": true, + "DockDirection": 1, + "ConnectedNodes": [], + "CanTurnLeft": true, + "CanTurnRight": true, + "DisableCross": false, + "SpeedLimit": 0, + "AliasName": "", + "IsActive": true, + "RfidId": 15, + "NodeTextForeColor": "", + "NodeTextFontSize": 7.0, + "ID2": "0015(*N019)", + "Id": "N019", + "Type": 0, + "Position": "402, 375" + }, + { + "Text": "Chg #2", + "StationType": 5, + "CanDocking": true, + "DockDirection": 1, + "ConnectedNodes": [], + "CanTurnLeft": true, + "CanTurnRight": true, + "DisableCross": false, + "SpeedLimit": 0, + "AliasName": "", + "IsActive": true, + "RfidId": 19, + "NodeTextForeColor": "", + "NodeTextFontSize": 7.0, + "ID2": "0019(*N026)", + "Id": "N026", + "Type": 0, + "Position": "541, 570" + }, + { + "Text": "", + "StationType": 0, + "CanDocking": false, + "DockDirection": 0, + "ConnectedNodes": [ + "N030", + "N005", + "1" + ], + "CanTurnLeft": true, + "CanTurnRight": true, + "DisableCross": false, + "SpeedLimit": 0, + "AliasName": "", + "IsActive": true, + "RfidId": 34, + "NodeTextForeColor": "", + "NodeTextFontSize": 7.0, + "ID2": "0034(*N018)", + "Id": "N018", + "Type": 0, + "Position": "213, 630" + }, + { + "Text": "", + "StationType": 0, + "CanDocking": false, + "DockDirection": 0, + "ConnectedNodes": [ + "N018", + "N020", + "N029" + ], + "CanTurnLeft": true, + "CanTurnRight": true, + "DisableCross": false, + "SpeedLimit": 0, + "AliasName": "", + "IsActive": true, + "RfidId": 33, + "NodeTextForeColor": "", + "NodeTextFontSize": 7.0, + "ID2": "0033(*N005)", + "Id": "N005", + "Type": 0, + "Position": "113, 629" + }, + { + "Text": "", + "StationType": 0, + "CanDocking": false, + "DockDirection": 0, + "ConnectedNodes": [ + "N005", + "N021", + "N028" + ], + "CanTurnLeft": true, + "CanTurnRight": true, + "DisableCross": false, + "SpeedLimit": 0, + "AliasName": "", + "IsActive": true, + "RfidId": 32, + "NodeTextForeColor": "", + "NodeTextFontSize": 7.0, + "ID2": "0032(*N020)", + "Id": "N020", + "Type": 0, + "Position": "38, 626" + }, + { + "Text": "", + "StationType": 0, + "CanDocking": false, + "DockDirection": 0, + "ConnectedNodes": [ + "N020", + "N027" + ], + "CanTurnLeft": true, + "CanTurnRight": true, + "DisableCross": false, + "SpeedLimit": 0, + "AliasName": "", + "IsActive": true, + "RfidId": 31, + "NodeTextForeColor": "", + "NodeTextFontSize": 7.0, + "ID2": "0031(*N021)", + "Id": "N021", + "Type": 0, + "Position": "-54, 626" + }, + { + "Text": "Buf #1", + "StationType": 4, + "CanDocking": true, + "DockDirection": 2, + "ConnectedNodes": [ + "N021" + ], + "CanTurnLeft": true, + "CanTurnRight": true, + "DisableCross": false, + "SpeedLimit": 0, + "AliasName": "", + "IsActive": true, + "RfidId": 41, + "NodeTextForeColor": "", + "NodeTextFontSize": 7.0, + "ID2": "0041(*N027)", + "Id": "N027", + "Type": 0, + "Position": "-76, 676" + }, + { + "Text": "Buf #2", + "StationType": 4, + "CanDocking": true, + "DockDirection": 2, + "ConnectedNodes": [ + "N020" + ], + "CanTurnLeft": true, + "CanTurnRight": true, + "DisableCross": false, + "SpeedLimit": 0, + "AliasName": "", + "IsActive": true, + "RfidId": 40, + "NodeTextForeColor": "", + "NodeTextFontSize": 7.0, + "ID2": "0040(*N028)", + "Id": "N028", + "Type": 0, + "Position": "12, 676" + }, + { + "Text": "Buf #3", + "StationType": 4, + "CanDocking": true, + "DockDirection": 2, + "ConnectedNodes": [ + "N005" + ], + "CanTurnLeft": true, + "CanTurnRight": true, + "DisableCross": false, + "SpeedLimit": 0, + "AliasName": "", + "IsActive": true, + "RfidId": 39, + "NodeTextForeColor": "", + "NodeTextFontSize": 7.0, + "ID2": "0039(*N029)", + "Id": "N029", + "Type": 0, + "Position": "89, 674" + }, + { + "Text": "Buf #4", + "StationType": 4, + "CanDocking": true, + "DockDirection": 2, + "ConnectedNodes": [ + "N018" + ], + "CanTurnLeft": true, + "CanTurnRight": true, + "DisableCross": false, + "SpeedLimit": 0, + "AliasName": "", + "IsActive": true, + "RfidId": 38, + "NodeTextForeColor": "", + "NodeTextFontSize": 7.0, + "ID2": "0038(*N030)", + "Id": "N030", + "Type": 0, + "Position": "183, 675" + }, + { + "Text": "", + "StationType": 0, + "CanDocking": false, + "DockDirection": 0, + "ConnectedNodes": [ + "N018", + "2" + ], + "CanTurnLeft": true, + "CanTurnRight": true, + "DisableCross": false, + "SpeedLimit": 0, + "AliasName": "", + "IsActive": true, + "RfidId": 2, + "NodeTextForeColor": "", + "NodeTextFontSize": 7.0, + "ID2": "0002(*1)", + "Id": "1", + "Type": 0, + "Position": "285, 628" + }, + { + "Text": "", + "StationType": 0, + "CanDocking": false, + "DockDirection": 0, + "ConnectedNodes": [ + "1", + "3" + ], + "CanTurnLeft": true, + "CanTurnRight": true, + "DisableCross": false, + "SpeedLimit": 0, + "AliasName": "", + "IsActive": true, + "RfidId": 4, + "NodeTextForeColor": "", + "NodeTextFontSize": 7.0, + "ID2": "0004(*2)", + "Id": "2", + "Type": 0, + "Position": "354, 628" + }, + { + "Text": "", + "StationType": 0, + "CanDocking": false, + "DockDirection": 0, + "ConnectedNodes": [ + "2", + "4" + ], + "CanTurnLeft": true, + "CanTurnRight": true, + "DisableCross": false, + "SpeedLimit": 0, + "AliasName": "", + "IsActive": true, + "RfidId": 3, + "NodeTextForeColor": "", + "NodeTextFontSize": 7.0, + "ID2": "0003(*3)", + "Id": "3", + "Type": 0, + "Position": "400, 578" + }, + { + "Text": "", + "StationType": 0, + "CanDocking": false, + "DockDirection": 0, + "ConnectedNodes": [ + "3", + "5" + ], + "CanTurnLeft": true, + "CanTurnRight": true, + "DisableCross": false, + "SpeedLimit": 0, + "AliasName": "", + "IsActive": true, + "RfidId": 5, + "NodeTextForeColor": "", + "NodeTextFontSize": 7.0, + "ID2": "0005(*4)", + "Id": "4", + "Type": 0, + "Position": "400, 499" + }, + { + "Text": "", + "StationType": 0, + "CanDocking": false, + "DockDirection": 0, + "ConnectedNodes": [ + "N010", + "4", + "6", + "7" + ], + "CanTurnLeft": true, + "CanTurnRight": true, + "DisableCross": false, + "SpeedLimit": 0, + "AliasName": "", + "IsActive": true, + "RfidId": 6, + "NodeTextForeColor": "", + "NodeTextFontSize": 7.0, + "ID2": "0006(*5)", + "Id": "5", + "Type": 0, + "Position": "462, 451" + }, + { + "Text": "", + "StationType": 0, + "CanDocking": false, + "DockDirection": 0, + "ConnectedNodes": [ + "N014", + "5", + "7" + ], + "CanTurnLeft": true, + "CanTurnRight": true, + "DisableCross": false, + "SpeedLimit": 0, + "AliasName": "", + "IsActive": true, + "RfidId": 13, + "NodeTextForeColor": "", + "NodeTextFontSize": 7.0, + "ID2": "0013(*6)", + "Id": "6", + "Type": 0, + "Position": "518, 519" + }, + { + "Text": "", + "StationType": 0, + "CanDocking": false, + "DockDirection": 0, + "ConnectedNodes": [ + "5", + "8", + "6", + "9" + ], + "CanTurnLeft": true, + "CanTurnRight": true, + "DisableCross": false, + "SpeedLimit": 0, + "AliasName": "", + "IsActive": true, + "RfidId": 7, + "NodeTextForeColor": "", + "NodeTextFontSize": 7.0, + "ID2": "0007(*7)", + "Id": "7", + "Type": 0, + "Position": "517, 400" + }, + { + "Text": "", + "StationType": 0, + "CanDocking": false, + "DockDirection": 0, + "ConnectedNodes": [ + "7", + "9", + "13" + ], + "CanTurnLeft": true, + "CanTurnRight": true, + "DisableCross": false, + "SpeedLimit": 0, + "AliasName": "", + "IsActive": true, + "RfidId": 9, + "NodeTextForeColor": "", + "NodeTextFontSize": 7.0, + "ID2": "0009(*8)", + "Id": "8", + "Type": 0, + "Position": "474, 353" + }, + { + "Text": "", + "StationType": 0, + "CanDocking": false, + "DockDirection": 0, + "ConnectedNodes": [ + "8", + "10", + "7" + ], + "CanTurnLeft": true, + "CanTurnRight": true, + "DisableCross": false, + "SpeedLimit": 0, + "AliasName": "", + "IsActive": true, + "RfidId": 10, + "NodeTextForeColor": "", + "NodeTextFontSize": 7.0, + "ID2": "0010(*9)", + "Id": "9", + "Type": 0, + "Position": "517, 311" + }, + { + "Text": "", + "StationType": 0, + "CanDocking": false, + "DockDirection": 0, + "ConnectedNodes": [ + "9", + "12" + ], + "CanTurnLeft": true, + "CanTurnRight": true, + "DisableCross": false, + "SpeedLimit": 0, + "AliasName": "", + "IsActive": true, + "RfidId": 12, + "NodeTextForeColor": "", + "NodeTextFontSize": 7.0, + "ID2": "0012(*10)", + "Id": "10", + "Type": 0, + "Position": "458, 268" + }, + { + "Text": "", + "StationType": 0, + "CanDocking": false, + "DockDirection": 0, + "ConnectedNodes": [ + "N001", + "10" + ], + "CanTurnLeft": true, + "CanTurnRight": true, + "DisableCross": false, + "SpeedLimit": 0, + "AliasName": "", + "IsActive": true, + "RfidId": 16, + "NodeTextForeColor": "", + "NodeTextFontSize": 7.0, + "ID2": "0016(*12)", + "Id": "12", + "Type": 0, + "Position": "389, 270" + }, + { + "Text": "", + "StationType": 0, + "CanDocking": false, + "DockDirection": 0, + "ConnectedNodes": [ + "8" + ], + "CanTurnLeft": true, + "CanTurnRight": true, + "DisableCross": false, + "SpeedLimit": 0, + "AliasName": "", + "IsActive": true, + "RfidId": 17, + "NodeTextForeColor": "", + "NodeTextFontSize": 7.0, + "ID2": "0017(*13)", + "Id": "13", + "Type": 0, + "Position": "350, 353" + } + ], + "Labels": [ + { + "Text": "Limit", + "ForeColor": "White", + "BackColor": "Transparent", + "FontFamily": "Arial", + "FontSize": 7.0, + "FontStyle": 0, + "Padding": 5, + "Id": "11", + "Type": 1, + "Position": "-120, 625" + }, + { + "Text": "Limit", + "ForeColor": "White", + "BackColor": "Transparent", + "FontFamily": "Arial", + "FontSize": 7.0, + "FontStyle": 0, + "Padding": 5, + "Id": "14", + "Type": 1, + "Position": "224, 272" + }, + { + "Text": "Limit", + "ForeColor": "White", + "BackColor": "Transparent", + "FontFamily": "Arial", + "FontSize": 7.0, + "FontStyle": 0, + "Padding": 5, + "Id": "15", + "Type": 1, + "Position": "247, 449" + }, + { + "Text": "Limit", + "ForeColor": "White", + "BackColor": "Transparent", + "FontFamily": "Arial", + "FontSize": 7.0, + "FontStyle": 0, + "Padding": 5, + "Id": "16", + "Type": 1, + "Position": "517, 721" + }, + { + "Text": "Amkor Technology Korea", + "ForeColor": "White", + "BackColor": "MidnightBlue", + "FontFamily": "Arial", + "FontSize": 20.0, + "FontStyle": 0, + "Padding": 5, + "Id": "LBL001", + "Type": 1, + "Position": "180, 105" + } + ], + "Images": [ + { + "Name": "Image", + "ImagePath": "", + "ImageBase64": "", + "Scale": "1, 1", + "Opacity": 1.0, + "Rotation": 0.0, + "Id": "IMG001", + "Type": 2, + "Position": "633, 310" + } + ], + "Marks": [ + { + "X": 520.0, + "Y": 690.0, + "Rotation": -178.01940688369234, + "Id": "2cb51787-c8cf-4ddb-97f0-b71f519d47dc", + "Type": 3, + "Position": "520, 690" + }, + { + "X": -74.0, + "Y": 624.0, + "Rotation": 90.0, + "Id": "f704ebe0-1653-4559-b06f-1eaecafbefba", + "Type": 3, + "Position": "-74, 624" + }, + { + "X": 12.0, + "Y": 625.0, + "Rotation": 90.0, + "Id": "d5b27365-79a2-4351-84c3-6767941ec0be", + "Type": 3, + "Position": "12, 625" + }, + { + "X": 91.0, + "Y": 625.0, + "Rotation": 89.2872271068898, + "Id": "0367cafb-9f85-4440-b6b4-c802a58e6181", + "Type": 3, + "Position": "91, 625" + }, + { + "X": 183.0, + "Y": 622.0, + "Rotation": 88.405167720722616, + "Id": "1f4ab2c9-07f8-4675-802d-9b4824b55198", + "Type": 3, + "Position": "183, 622" + }, + { + "X": 275.0, + "Y": 269.0, + "Rotation": 91.712220129051758, + "Id": "15fddfa4-ff74-48ff-b922-4aacdce1960b", + "Type": 3, + "Position": "275, 269" + }, + { + "X": 89.0, + "Y": 697.0, + "Rotation": 0.38243447796178032, + "Id": "4b699847-36d4-471c-b990-4ad37967c2dc", + "Type": 3, + "Position": "89, 697" + }, + { + "X": 183.0, + "Y": 699.0, + "Rotation": -1.3380194104322385, + "Id": "a9f68317-f1c2-47d8-b029-348b5428be9f", + "Type": 3, + "Position": "183, 699" + }, + { + "X": 9.0, + "Y": 699.0, + "Rotation": 0.84311038333069632, + "Id": "fe227205-2a65-4ba9-bb4a-4efb4ed0a7b0", + "Type": 3, + "Position": "9, 699" + }, + { + "X": -74.0, + "Y": 697.0, + "Rotation": 1.659829660758831, + "Id": "5dd29191-798c-480c-b066-7947bfcc4fb7", + "Type": 3, + "Position": "-74, 697" + }, + { + "X": -71.0, + "Y": 596.0, + "Rotation": 0.0, + "Id": "649729f0-ff04-4e11-8869-f6a39d815427", + "Type": 3, + "Position": "-71, 596" + }, + { + "X": 10.0, + "Y": 601.0, + "Rotation": 0.0, + "Id": "2bb9a821-f86b-4190-a182-64abe2c940ed", + "Type": 3, + "Position": "10, 601" + }, + { + "X": 91.0, + "Y": 598.0, + "Rotation": 0.0, + "Id": "821598e1-091a-4884-96fe-6ed5f43c4f62", + "Type": 3, + "Position": "91, 598" + }, + { + "X": 184.0, + "Y": 596.0, + "Rotation": 0.0, + "Id": "66c1bbee-89a8-45a9-b585-ddfd59768f6b", + "Type": 3, + "Position": "184, 596" + }, + { + "X": 381.0, + "Y": 355.0, + "Rotation": 91.245364266768377, + "Id": "06a10f46-bda8-4b0f-9e7a-63d66bd2f7e4", + "Type": 3, + "Position": "381, 355" + }, + { + "X": 519.0, + "Y": 550.0, + "Rotation": 0.0, + "Id": "835b8982-042b-4e2e-a83b-19b32e55cd5b", + "Type": 3, + "Position": "519, 550" + } + ], + "Magnets": [ + { + "P1": { + "X": 358.53781512605048, + "Y": 628.438429217841 + }, + "P2": { + "X": -119.57759581805529, + "Y": 626.78449598889756 + }, + "ControlPoint": null, + "Id": "5a0edec2-7ac3-4c99-bbb4-8debde0c1d07", + "Type": 4 + }, + { + "P1": { + "X": -75.0847526191485, + "Y": 716.14155614369508 + }, + "P2": { + "X": -73.1298113651053, + "Y": 561.63119233707459 + }, + "ControlPoint": null, + "Id": "def7c4b9-86db-42eb-aae6-0c6c9bedcc30", + "Type": 4 + }, + { + "P1": { + "X": 12.69302515862924, + "Y": 717.25266725480617 + }, + "P2": { + "X": 11.870188634894689, + "Y": 560.25023995612207 + }, + "ControlPoint": null, + "Id": "624327ee-be0f-4373-b60a-786a93c1eabf", + "Type": 4 + }, + { + "P1": { + "X": 90.470802936406983, + "Y": 716.14155614369508 + }, + "P2": { + "X": 89.727331492037507, + "Y": 560.91690662278882 + }, + "ControlPoint": null, + "Id": "f1e885ae-55f7-42e9-b3aa-648541e97da0", + "Type": 4 + }, + { + "P1": { + "X": 185.470802936407, + "Y": 725.03044503258388 + }, + "P2": { + "X": 181.87018863489462, + "Y": 563.059763765646 + }, + "ControlPoint": null, + "Id": "dc3e8061-2c99-4f24-ac9b-4020dd91fa8b", + "Type": 4 + }, + { + "P1": { + "X": 343.98784548784573, + "Y": 353.92216117216128 + }, + "P2": { + "X": 472.59413991107186, + "Y": 353.73144759338567 + }, + "ControlPoint": null, + "Id": "f4c97a5a-2c2c-4b5e-9dd5-332b1670b827", + "Type": 4 + }, + { + "P1": { + "X": 519.32722832722823, + "Y": 720.25490196078408 + }, + "P2": { + "X": 516.16556848250036, + "Y": 309.44573330767145 + }, + "ControlPoint": null, + "Id": "a5424add-e8c9-483c-a5db-733dca1b8f57", + "Type": 4 + }, + { + "P1": { + "X": 249.62404756406329, + "Y": 449.77059623383167 + }, + "P2": { + "X": 518.08558602560174, + "Y": 452.84751931075476 + }, + "ControlPoint": null, + "Id": "0bbb27a4-2355-4294-9f2d-a40e4d3d2930", + "Type": 4 + }, + { + "P1": { + "X": 225.77789371790945, + "Y": 271.30905777229322 + }, + "P2": { + "X": 463.66556848250042, + "Y": 269.44573330767145 + }, + "ControlPoint": null, + "Id": "92527d4a-8e63-404f-86e8-37568bd4790e", + "Type": 4 + }, + { + "P1": { + "X": 463.41452991452985, + "Y": 270.25490196078431 + }, + "P2": { + "X": 515.08119658119654, + "Y": 310.25490196078425 + }, + "ControlPoint": { + "X": 517.85897435897425, + "Y": 266.3660130718954 + }, + "Id": "0db9553a-f203-478d-8c17-e07f00987828", + "Type": 4 + }, + { + "P1": { + "X": 473.41452991452985, + "Y": 353.032679738562 + }, + "P2": { + "X": 515.63675213675208, + "Y": 399.14379084967311 + }, + "ControlPoint": { + "X": 521.74786324786317, + "Y": 351.3660130718954 + }, + "Id": "0650b2cb-57f9-44ec-9787-fab878cf2b47", + "Type": 4 + }, + { + "P1": { + "X": 465.08119658119654, + "Y": 450.2549019607842 + }, + "P2": { + "X": 518.24918584253533, + "Y": 519.05971509141114 + }, + "ControlPoint": { + "X": 522.85897435897425, + "Y": 450.8104575163398 + }, + "Id": "7007db10-b61b-4726-9775-417951454ddf", + "Type": 4 + }, + { + "P1": { + "X": 473.30842562535759, + "Y": 351.58859045052856 + }, + "P2": { + "X": 515.4512827682147, + "Y": 309.80287616481428 + }, + "ControlPoint": { + "X": 519.02271133964325, + "Y": 358.01716187909994 + }, + "Id": "4ef4bfd0-8fc4-48a5-a490-92b35c7fd1c3", + "Type": 4 + }, + { + "P1": { + "X": 464.73699705392903, + "Y": 450.51716187909989 + }, + "P2": { + "X": 516.52271133964325, + "Y": 402.66001902195711 + }, + "ControlPoint": { + "X": 516.16556848250036, + "Y": 454.44573330767133 + }, + "Id": "7d18ae7e-7926-4cf4-8dd6-861462e31352", + "Type": 4 + }, + { + "P1": { + "X": 399.76697627462613, + "Y": 521.72108802571984 + }, + "P2": { + "X": 462.61739821419411, + "Y": 449.66152357736206 + }, + "ControlPoint": { + "X": 391.99239821419411, + "Y": 447.16152357736206 + }, + "Id": "532be14d-170e-45c5-adcf-0d555b83b010", + "Type": 4 + }, + { + "P1": { + "X": 399.05269056034041, + "Y": 523.50680231143417 + }, + "P2": { + "X": 400.11132581222392, + "Y": 580.622765294022 + }, + "ControlPoint": null, + "Id": "086955e0-0542-4ab5-9ccf-8880e749722a", + "Type": 4 + }, + { + "P1": { + "X": 353.86132581222392, + "Y": 629.37276529402186 + }, + "P2": { + "X": 400.11132581222392, + "Y": 576.87276529402186 + }, + "ControlPoint": { + "X": 404.48632581222392, + "Y": 630.62276529402186 + }, + "Id": "2ac7d720-a6df-4174-be74-15ddfe96459b", + "Type": 4 + } + ], + "Settings": { + "BackgroundColorArgb": -14671840, + "ShowGrid": false + }, + "CreatedDate": "2026-01-07T10:51:37.9312214+09:00", + "Version": "1.3" +} \ No newline at end of file diff --git a/agv_log_report_v1.py b/agv_log_report_v1.py deleted file mode 100644 index 29c8311..0000000 --- a/agv_log_report_v1.py +++ /dev/null @@ -1,948 +0,0 @@ -""" -AGV 종합 분석 리포트 생성 스크립트 -- BMS 배터리 데이터 분석 (0x03: 배터리 상태, 0x04: 셀 전압) -- 상차작업완료 집계 -- 충전상태전환 이벤트 분석 -- 셀 전압 불균형 분석 -- 시간대별 종합 리포트 및 엑셀 차트 생성 -""" - -import re -from datetime import datetime, timedelta -from collections import defaultdict -import pandas as pd -from openpyxl import load_workbook -from openpyxl.chart import LineChart, Reference, BarChart, AreaChart -from openpyxl.styles import Font, Alignment, PatternFill -import os -import glob - -print("=" * 80) -print("AGV 종합 분석 리포트 생성 (셀 전압 분석 포함)") -print("=" * 80) - -# ============================================================================ -# 1. BMS 배터리 데이터 파싱 (0x03: 배터리 상태) -# ============================================================================ - -def parse_bms_packet(hex_string): - """BMS 배터리 상태 패킷 파싱 (0x03)""" - try: - bytes_data = [int(x, 16) for x in hex_string.split()] - if len(bytes_data) < 34 or bytes_data[0] != 0xDD or bytes_data[-1] != 0x77: - return None - if bytes_data[1] != 0x03: # 배터리 상태 정보만 - return None - - volt_raw = (bytes_data[4] << 8) | bytes_data[5] - voltage = volt_raw / 100.0 - cur_amp = (bytes_data[8] << 8) | bytes_data[9] - max_amp = (bytes_data[10] << 8) | bytes_data[11] - level_direct = bytes_data[23] - temp1_raw = (bytes_data[27] << 8) | bytes_data[28] - temp1 = (temp1_raw - 2731) / 10.0 - - return { - 'voltage': voltage, - 'current_amp': cur_amp, - 'max_amp': max_amp, - 'level': level_direct, - 'temp': temp1 - } - except: - return None - -def read_bms_log(file_path): - """BMS 로그 파일 읽기 (배터리 상태)""" - encodings = ['utf-8', 'cp949', 'euc-kr'] - for encoding in encodings: - try: - with open(file_path, 'r', encoding=encoding) as f: - lines = f.readlines() - break - except: - continue - else: - return [] - - pattern = r'(\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2})\s+\w+\s+BMS:(.*?)(?=\n|$)' - battery_data = [] - - for line in lines: - match = re.search(pattern, line) - if match: - timestamp_str = match.group(1) - packet_hex = match.group(2).strip() - parsed = parse_bms_packet(packet_hex) - if parsed: - timestamp = datetime.strptime(timestamp_str, '%Y-%m-%d %H:%M:%S') - battery_data.append({ - 'timestamp': timestamp, - **parsed - }) - - return battery_data - -# ============================================================================ -# 1-2. BMS 셀 전압 데이터 파싱 (0x04: 셀 전압) -# ============================================================================ - -def parse_cell_voltage_packet(hex_string): - """BMS 셀 전압 패킷 파싱 (0x04)""" - try: - bytes_data = [int(x, 16) for x in hex_string.split()] - if len(bytes_data) < 23 or bytes_data[0] != 0xDD or bytes_data[-1] != 0x77: - return None - if bytes_data[1] != 0x04: # 셀 전압 정보만 - return None - - # 8개 셀 전압 추출 - voltages = [] - for i in range(8): - v_raw = (bytes_data[4 + i*2] << 8) | bytes_data[5 + i*2] - voltages.append(v_raw / 1000.0) - - return { - 'cell1': voltages[0], - 'cell2': voltages[1], - 'cell3': voltages[2], - 'cell4': voltages[3], - 'cell5': voltages[4], - 'cell6': voltages[5], - 'cell7': voltages[6], - 'cell8': voltages[7], - 'max_voltage': max(voltages), - 'min_voltage': min(voltages), - 'voltage_diff': max(voltages) - min(voltages), - 'avg_voltage': sum(voltages) / len(voltages) - } - except: - return None - -def read_cell_voltage_log(file_path): - """셀 전압 로그 파일 읽기""" - encodings = ['utf-8', 'cp949', 'euc-kr'] - for encoding in encodings: - try: - with open(file_path, 'r', encoding=encoding) as f: - lines = f.readlines() - break - except: - continue - else: - return [] - - pattern = r'(\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2})\s+\w+\s+BMS:(.*?)(?=\n|$)' - cell_data = [] - - for line in lines: - match = re.search(pattern, line) - if match: - timestamp_str = match.group(1) - packet_hex = match.group(2).strip() - parsed = parse_cell_voltage_packet(packet_hex) - if parsed: - timestamp = datetime.strptime(timestamp_str, '%Y-%m-%d %H:%M:%S') - cell_data.append({ - 'timestamp': timestamp, - **parsed - }) - - return cell_data - -# ============================================================================ -# 2. 상차작업완료 카운트 -# ============================================================================ - -def read_loading_complete(file_path): - """상차작업완료 메시지 추출""" - encodings = ['utf-8', 'cp949', 'euc-kr'] - for encoding in encodings: - try: - with open(file_path, 'r', encoding=encoding) as f: - content = f.read() - break - except: - continue - else: - return [] - - pattern = r'(\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}).*상차작업완료\(([^)]+)\)' - matches = re.findall(pattern, content) - - results = [] - for timestamp_str, location in matches: - timestamp = datetime.strptime(timestamp_str, '%Y-%m-%d %H:%M:%S') - results.append({ - 'timestamp': timestamp, - 'location': location - }) - - return results - -# ============================================================================ -# 3. 충전상태전환 이벤트 -# ============================================================================ - -def read_charge_status(file_path): - """충전상태전환 메시지 추출""" - encodings = ['utf-8', 'cp949', 'euc-kr'] - for encoding in encodings: - try: - with open(file_path, 'r', encoding=encoding) as f: - lines = f.readlines() - break - except: - continue - else: - return [] - - pattern = r'(\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}).*충전상태전환\s+(True|False)' - results = [] - - for line in lines: - match = re.search(pattern, line) - if match: - timestamp_str = match.group(1) - status = match.group(2) - timestamp = datetime.strptime(timestamp_str, '%Y-%m-%d %H:%M:%S') - results.append({ - 'timestamp': timestamp, - 'status': status == 'True' - }) - - return results - -# ============================================================================ -# 4. 데이터 읽기 -# ============================================================================ - -print("\n데이터 로딩 중...") - -# 현재 실행 폴더 기준 (서브폴더 포함) -base_path = os.getcwd() -print(f" 분석 폴더: {base_path} (서브폴더 포함)") - -# 파일 패턴으로 자동 검색 (재귀 검색) -# BMS 파일들 찾기 (*_bms.txt) -bms_files = sorted(glob.glob(os.path.join(base_path, "**", "*_bms.txt"), recursive=True)) -print(f" BMS 파일: {len(bms_files)}개 발견") -for f in bms_files: - rel_path = os.path.relpath(f, base_path) - print(f" - {rel_path}") - -# 운용기록 로그 파일들 찾기 (202*.txt, 단 _bms.txt 제외) -log_files = sorted([f for f in glob.glob(os.path.join(base_path, "**", "202*.txt"), recursive=True) - if not f.endswith("_bms.txt")]) -print(f" 운용기록 파일: {len(log_files)}개 발견") -for f in log_files: - rel_path = os.path.relpath(f, base_path) - print(f" - {rel_path}") - -# BMS 배터리 상태 데이터 (0x03) -all_battery = [] -for bms_file in bms_files: - data = read_bms_log(bms_file) - all_battery.extend(data) - rel_path = os.path.relpath(bms_file, base_path) - print(f" {rel_path}: {len(data)}개 배터리 데이터") -all_battery.sort(key=lambda x: x['timestamp']) - -print(f" 배터리 데이터 총합: {len(all_battery)}개") - -# BMS 셀 전압 데이터 (0x04) -all_cells = [] -for bms_file in bms_files: - data = read_cell_voltage_log(bms_file) - all_cells.extend(data) - rel_path = os.path.relpath(bms_file, base_path) - print(f" {rel_path}: {len(data)}개 셀 전압 데이터") -all_cells.sort(key=lambda x: x['timestamp']) - -print(f" 셀 전압 데이터 총합: {len(all_cells)}개") - -# 상차작업완료 데이터 -all_loading = [] -for log_file in log_files: - data = read_loading_complete(log_file) - all_loading.extend(data) - rel_path = os.path.relpath(log_file, base_path) - print(f" {rel_path}: {len(data)}건 작업완료") -all_loading.sort(key=lambda x: x['timestamp']) - -print(f" 상차작업완료 총합: {len(all_loading)}건") - -# 충전상태전환 데이터 -all_charge = [] -for log_file in log_files: - data = read_charge_status(log_file) - all_charge.extend(data) - rel_path = os.path.relpath(log_file, base_path) - print(f" {rel_path}: {len(data)}건 충전이벤트") -all_charge.sort(key=lambda x: x['timestamp']) - -print(f" 충전상태전환 총합: {len(all_charge)}건") - -# ============================================================================ -# 4-2. 셀 불균형 분석 -# ============================================================================ - -print("\n셀 불균형 분석 중...") - -if all_cells: - # 불균형 기준: 0.1V 이상 차이 - critical_imbalance = [c for c in all_cells if c['voltage_diff'] > 0.1] - warning_imbalance = [c for c in all_cells if 0.05 < c['voltage_diff'] <= 0.1] - - print(f" 심각한 불균형 (>0.1V): {len(critical_imbalance)}건") - print(f" 경고 수준 불균형 (0.05~0.1V): {len(warning_imbalance)}건") - - # 일별 셀 전압 분석 - from collections import defaultdict - daily_cells = defaultdict(list) - for c in all_cells: - date_key = c['timestamp'].strftime('%Y-%m-%d') - daily_cells[date_key].append(c) - - for date_key in sorted(daily_cells.keys()): - day_data = daily_cells[date_key] - print(f"\n[{date_key} 셀 전압 분석]") - print(f" 측정 건수: {len(day_data)}건") - - max_diff = max(c['voltage_diff'] for c in day_data) - avg_diff = sum(c['voltage_diff'] for c in day_data) / len(day_data) - print(f" 최대 불균형: {max_diff:.3f}V") - print(f" 평균 불균형: {avg_diff:.3f}V") - - # 최대 불균형 시점 찾기 - max_imbalance = max(day_data, key=lambda x: x['voltage_diff']) - print(f" 최대 불균형 시점: {max_imbalance['timestamp'].strftime('%H:%M:%S')}") - print(f" 셀 전압: C1={max_imbalance['cell1']:.3f}V, C2={max_imbalance['cell2']:.3f}V, " - f"C3={max_imbalance['cell3']:.3f}V, C4={max_imbalance['cell4']:.3f}V") - print(f" C5={max_imbalance['cell5']:.3f}V, C6={max_imbalance['cell6']:.3f}V, " - f"C7={max_imbalance['cell7']:.3f}V, C8={max_imbalance['cell8']:.3f}V") - print(f" 전압 차이: {max_imbalance['voltage_diff']:.3f}V " - f"(최고 {max_imbalance['max_voltage']:.3f}V - 최저 {max_imbalance['min_voltage']:.3f}V)") - - # 해당 일의 심각한 불균형 건수 - day_critical = [c for c in day_data if c['voltage_diff'] > 0.1] - day_warning = [c for c in day_data if 0.05 < c['voltage_diff'] <= 0.1] - print(f" 심각한 불균형: {len(day_critical)}건, 경고 수준: {len(day_warning)}건") - -# ============================================================================ -# 5. 시간대별 집계 (1시간 단위) -# ============================================================================ - -print("\n시간대별 데이터 집계 중...") - -# 시작/종료 시간 결정 -if all_battery: - start_time = all_battery[0]['timestamp'] - end_time = all_battery[-1]['timestamp'] -else: - start_time = datetime(2025, 11, 5, 0, 0, 0) - end_time = datetime(2025, 11, 6, 23, 59, 59) - -# 1시간 단위 시간 슬롯 생성 -time_slots = [] -current = start_time.replace(minute=0, second=0, microsecond=0) -while current <= end_time: - time_slots.append(current) - current += timedelta(hours=1) - -# 각 시간대별 데이터 집계 -timeline_data = [] - -for slot in time_slots: - slot_end = slot + timedelta(hours=1) - - # 배터리 데이터 평균 - slot_battery = [b for b in all_battery if slot <= b['timestamp'] < slot_end] - if slot_battery: - avg_voltage = sum(b['voltage'] for b in slot_battery) / len(slot_battery) - avg_amp = sum(b['current_amp'] for b in slot_battery) / len(slot_battery) - avg_level = sum(b['level'] for b in slot_battery) / len(slot_battery) - avg_temp = sum(b['temp'] for b in slot_battery) / len(slot_battery) - battery_count = len(slot_battery) - else: - avg_voltage = avg_amp = avg_level = avg_temp = battery_count = 0 - - # 작업 완료 카운트 - slot_loading = [l for l in all_loading if slot <= l['timestamp'] < slot_end] - loading_count = len(slot_loading) - - # 작업 위치별 카운트 - location_counts = defaultdict(int) - for l in slot_loading: - location_counts[l['location']] += 1 - - # 충전 상태 - 현재 시간이 충전 구간에 포함되는지 확인 - is_charging = False - for c in all_charge: - if c['timestamp'] <= slot: - is_charging = c['status'] - elif c['timestamp'] > slot_end: - break - - # 슬롯 내 충전상태전환 이벤트 확인 - slot_charge = [c for c in all_charge if slot <= c['timestamp'] < slot_end] - if slot_charge: - is_charging = slot_charge[-1]['status'] - - charging = "충전중" if is_charging else "-" - charging_indicator = 100 if is_charging else 0 - - timeline_data.append({ - '시간대': slot.strftime('%Y-%m-%d %H:%M'), - '평균전압(V)': round(avg_voltage, 2) if avg_voltage > 0 else '', - '평균용량(mAh)': int(avg_amp) if avg_amp > 0 else '', - '평균잔량(%)': int(avg_level) if avg_level > 0 else '', - '평균온도(°C)': round(avg_temp, 1) if avg_temp > 0 else '', - '작업완료건수': loading_count, - 'F1': location_counts.get('F1', 0), - 'F2': location_counts.get('F2', 0), - 'F3': location_counts.get('F3', 0), - 'F4': location_counts.get('F4', 0), - 'F5': location_counts.get('F5', 0), - 'F6': location_counts.get('F6', 0), - '충전상태': charging, - '충전구간': charging_indicator, - '배터리측정수': battery_count - }) - -print(f" 시간대별 데이터: {len(timeline_data)}개 슬롯") - -# ============================================================================ -# 5-2. 일자별 집계 -# ============================================================================ - -print("\n일자별 데이터 집계 중...") - -# 일자별 작업 완료 건수 집계 -daily_summary = defaultdict(lambda: { - 'date': '', - 'total_work': 0, - 'F1': 0, 'F2': 0, 'F3': 0, 'F4': 0, 'F5': 0, 'F6': 0, - 'HOME': 0, - 'charge_count': 0, - 'battery_count': 0, - 'avg_battery_level': 0 -}) - -# 작업 완료 집계 -for work in all_loading: - date_key = work['timestamp'].strftime('%Y-%m-%d') - daily_summary[date_key]['date'] = date_key - daily_summary[date_key]['total_work'] += 1 - daily_summary[date_key][work['location']] += 1 - -# 충전 이벤트 집계 -for charge in all_charge: - date_key = charge['timestamp'].strftime('%Y-%m-%d') - daily_summary[date_key]['charge_count'] += 1 - -# 배터리 데이터 집계 -battery_by_day = defaultdict(list) -for bat in all_battery: - date_key = bat['timestamp'].strftime('%Y-%m-%d') - battery_by_day[date_key].append(bat['level']) - -for date_key, levels in battery_by_day.items(): - daily_summary[date_key]['battery_count'] = len(levels) - daily_summary[date_key]['avg_battery_level'] = sum(levels) / len(levels) - -# DataFrame 생성 -daily_data = [] -for date_key in sorted(daily_summary.keys()): - data = daily_summary[date_key] - daily_data.append({ - '일자': data['date'], - '총작업건수': data['total_work'], - 'F1': data['F1'], - 'F2': data['F2'], - 'F3': data['F3'], - 'F4': data['F4'], - 'F5': data['F5'], - 'F6': data['F6'], - '충전이벤트': data['charge_count'] - }) - -print(f" 일자별 데이터: {len(daily_data)}일") - -# ============================================================================ -# 5-3. 일자별 교대조(Shift)별 집계 -# ============================================================================ - -print("\n교대조별 데이터 집계 중...") - -def get_shift(timestamp): - """시간대별 교대조 분류""" - hour = timestamp.hour - if 6 <= hour < 14: - return 'Day' - elif 14 <= hour < 22: - return 'Swing' - else: # 22:00~06:00 - return 'Night' - -# 일자별 교대조별 작업 집계 -shift_summary = defaultdict(lambda: {'date': '', 'Day': 0, 'Swing': 0, 'Night': 0}) - -for work in all_loading: - date_key = work['timestamp'].strftime('%Y-%m-%d') - shift = get_shift(work['timestamp']) - shift_summary[date_key]['date'] = date_key - shift_summary[date_key][shift] += 1 - -# DataFrame 생성 -shift_data = [] -for date_key in sorted(shift_summary.keys()): - data = shift_summary[date_key] - total = data['Day'] + data['Swing'] + data['Night'] - avg = round(total / 3, 1) if total > 0 else 0 - shift_data.append({ - '일자': data['date'], - 'day': data['Day'], - 'swing': data['Swing'], - 'night': data['Night'], - '합계': total, - '평균': avg - }) - -print(f" 교대조별 데이터: {len(shift_data)}일") - -# ============================================================================ -# 6. 엑셀 리포트 생성 -# ============================================================================ - -print("\n엑셀 리포트 생성 중...") - -# 출력 파일명 동적 생성 (시작일~종료일) -if all_battery: - start_date = all_battery[0]['timestamp'].strftime('%Y%m%d') - end_date = all_battery[-1]['timestamp'].strftime('%Y%m%d') - output_filename = f"agv_log_report_{start_date}~{end_date}.xlsx" -else: - output_filename = "agv_log_report.xlsx" - -output_file = os.path.join(base_path, output_filename) -print(f" 출력 파일: {output_filename}") - -# DataFrame 생성 -df_timeline = pd.DataFrame(timeline_data) - -# 배터리 상세 데이터 -df_battery = pd.DataFrame([{ - '시간': b['timestamp'].strftime('%Y-%m-%d %H:%M:%S'), - '전압(V)': round(b['voltage'], 2), - '남은용량(mAh)': b['current_amp'], - '총용량(mAh)': b['max_amp'], - '잔량(%)': b['level'], - '온도(°C)': round(b['temp'], 1) -} for b in all_battery]) - -# 작업 상세 데이터 -df_loading = pd.DataFrame([{ - '시간': l['timestamp'].strftime('%Y-%m-%d %H:%M:%S'), - '위치': l['location'] -} for l in all_loading]) - -# 충전 이벤트 데이터 -df_charge = pd.DataFrame([{ - '시간': c['timestamp'].strftime('%Y-%m-%d %H:%M:%S'), - '충전상태': '시작' if c['status'] else '종료' -} for c in all_charge]) - -# 셀 전압 상세 데이터 -df_cells = pd.DataFrame([{ - '시간': c['timestamp'].strftime('%Y-%m-%d %H:%M:%S'), - 'Cell1(V)': round(c['cell1'], 3), - 'Cell2(V)': round(c['cell2'], 3), - 'Cell3(V)': round(c['cell3'], 3), - 'Cell4(V)': round(c['cell4'], 3), - 'Cell5(V)': round(c['cell5'], 3), - 'Cell6(V)': round(c['cell6'], 3), - 'Cell7(V)': round(c['cell7'], 3), - 'Cell8(V)': round(c['cell8'], 3), - '최고전압(V)': round(c['max_voltage'], 3), - '최저전압(V)': round(c['min_voltage'], 3), - '전압차(V)': round(c['voltage_diff'], 3), - '평균전압(V)': round(c['avg_voltage'], 3) -} for c in all_cells]) if all_cells else pd.DataFrame() - -# 일자별 요약 DataFrame -df_daily = pd.DataFrame(daily_data) -df_shift = pd.DataFrame(shift_data) - -# 엑셀 저장 -with pd.ExcelWriter(output_file, engine='openpyxl') as writer: - df_daily.to_excel(writer, sheet_name='일자별작업요약', index=False) - # 교대조별 데이터를 같은 시트에 추가 (일자별 데이터 아래 3행 띄우고) - df_shift.to_excel(writer, sheet_name='일자별작업요약', startrow=len(df_daily)+3, index=False) - - df_timeline.to_excel(writer, sheet_name='시간대별종합', index=False) - df_battery.to_excel(writer, sheet_name='배터리상세', index=False) - df_loading.to_excel(writer, sheet_name='작업상세', index=False) - df_charge.to_excel(writer, sheet_name='충전이벤트', index=False) - if not df_cells.empty: - df_cells.to_excel(writer, sheet_name='셀전압상세', index=False) - -# ============================================================================ -# 7. 차트 추가 -# ============================================================================ - -print("차트 생성 중...") - -wb = load_workbook(output_file) - -# ============================================================================ -# 7-1. 일자별작업요약 시트 스타일 및 차트 -# ============================================================================ - -ws_daily = wb['일자별작업요약'] - -# 헤더 스타일 -header_fill = PatternFill(start_color="366092", end_color="366092", fill_type="solid") -header_font = Font(color="FFFFFF", bold=True) - -for cell in ws_daily[1]: - cell.fill = header_fill - cell.font = header_font - cell.alignment = Alignment(horizontal='center') - -# 열 너비 조정 -ws_daily.column_dimensions['A'].width = 12 -for col in ['B', 'C', 'D', 'E', 'F', 'G', 'H', 'I']: - ws_daily.column_dimensions[col].width = 12 - -# 일자별 작업 건수 차트 -chart_daily_work = BarChart() -chart_daily_work.type = "col" -chart_daily_work.title = "일자별 작업 완료 건수" -chart_daily_work.y_axis.title = '작업 건수' -chart_daily_work.x_axis.title = '일자' -chart_daily_work.height = 12 -chart_daily_work.width = 20 - -# 총작업건수 데이터 -data = Reference(ws_daily, min_col=2, min_row=1, max_row=len(daily_data)+1) -cats = Reference(ws_daily, min_col=1, min_row=2, max_row=len(daily_data)+1) -chart_daily_work.add_data(data, titles_from_data=True) -chart_daily_work.set_categories(cats) - -ws_daily.add_chart(chart_daily_work, "N2") - -# 일자별 위치별 작업 건수 차트 (누적 막대) -chart_daily_location = BarChart() -chart_daily_location.type = "col" -chart_daily_location.grouping = "stacked" -chart_daily_location.title = "일자별 위치별 작업 건수 (누적)" -chart_daily_location.y_axis.title = '작업 건수' -chart_daily_location.x_axis.title = '일자' -chart_daily_location.height = 12 -chart_daily_location.width = 20 - -# F1~F6 데이터 (3~8열) -data = Reference(ws_daily, min_col=3, max_col=8, min_row=1, max_row=len(daily_data)+1) -cats = Reference(ws_daily, min_col=1, min_row=2, max_row=len(daily_data)+1) -chart_daily_location.add_data(data, titles_from_data=True) -chart_daily_location.set_categories(cats) - -ws_daily.add_chart(chart_daily_location, "N22") - -# 교대조별 데이터 영역 스타일 및 차트 -shift_start_row = len(daily_data) + 4 # 일자별 데이터 + 빈 행 + 헤더 - -# 교대조별 헤더 스타일 -for col_idx in range(1, 7): # A~F 열 (일자, day, swing, night, 합계, 평균) - cell = ws_daily.cell(row=shift_start_row, column=col_idx) - cell.font = Font(bold=True, color="FFFFFF") - cell.fill = PatternFill(start_color="366092", end_color="366092", fill_type="solid") - cell.alignment = Alignment(horizontal='center') - -# 교대조별 작업 건수 차트 (혼합 차트: 막대 + 선) -chart_shift = BarChart() -chart_shift.type = "col" -chart_shift.grouping = "clustered" -chart_shift.title = "일자별 교대조별 작업 건수" -chart_shift.y_axis.title = '작업 건수' -chart_shift.x_axis.title = '일자' -chart_shift.height = 12 -chart_shift.width = 20 - -# Day, Swing, Night 데이터 (막대 차트) -data = Reference(ws_daily, min_col=2, max_col=4, min_row=shift_start_row, max_row=shift_start_row+len(shift_data)) -cats = Reference(ws_daily, min_col=1, min_row=shift_start_row+1, max_row=shift_start_row+len(shift_data)) -chart_shift.add_data(data, titles_from_data=True) -chart_shift.set_categories(cats) - -# 데이터 레이블 추가 (숫자만 표시) -from openpyxl.chart.label import DataLabelList -for series in chart_shift.series: - series.dLbls = DataLabelList() - series.dLbls.showVal = True - series.dLbls.showCatName = False - series.dLbls.showSerName = False - series.dLbls.showPercent = False - series.dLbls.showLeaderLines = False - -# 평균 데이터 (선 차트) -line_chart = LineChart() -line_data = Reference(ws_daily, min_col=6, min_row=shift_start_row, max_row=shift_start_row+len(shift_data)) -line_chart.add_data(line_data, titles_from_data=True) -line_chart.set_categories(cats) - -# 선 차트에 데이터 레이블 추가 -for series in line_chart.series: - series.dLbls = DataLabelList() - series.dLbls.showVal = True - series.dLbls.showCatName = False - series.dLbls.showSerName = False - series.dLbls.showPercent = False - series.dLbls.showLeaderLines = False - -# 혼합 차트 조합 -chart_shift += line_chart - -ws_daily.add_chart(chart_shift, "N42") - -# ============================================================================ -# 7-2. 시간대별종합 시트 스타일 -# ============================================================================ - -ws = wb['시간대별종합'] - -# 헤더 스타일 -for cell in ws[1]: - cell.fill = header_fill - cell.font = header_font - cell.alignment = Alignment(horizontal='center') - -# 열 너비 조정 -ws.column_dimensions['A'].width = 18 -ws.column_dimensions['B'].width = 12 -ws.column_dimensions['C'].width = 14 -ws.column_dimensions['D'].width = 12 -ws.column_dimensions['E'].width = 12 -ws.column_dimensions['F'].width = 12 -ws.column_dimensions['L'].width = 12 - -# 차트 1: 배터리 잔량 추이 -chart1 = LineChart() -chart1.title = "배터리 잔량 추이" -chart1.style = 10 -chart1.y_axis.title = '배터리 잔량 (%)' -chart1.x_axis.title = '시간대' -chart1.height = 10 -chart1.width = 20 - -data = Reference(ws, min_col=4, min_row=1, max_row=len(timeline_data)+1) -cats = Reference(ws, min_col=1, min_row=2, max_row=len(timeline_data)+1) -chart1.add_data(data, titles_from_data=True) -chart1.set_categories(cats) - -ws.add_chart(chart1, "N2") - -# 차트 2: 작업 건수 추이 -chart2 = BarChart() -chart2.type = "col" -chart2.title = "시간대별 작업 완료 건수" -chart2.y_axis.title = '작업 건수' -chart2.x_axis.title = '시간대' -chart2.height = 10 -chart2.width = 20 - -data = Reference(ws, min_col=6, min_row=1, max_row=len(timeline_data)+1) -cats = Reference(ws, min_col=1, min_row=2, max_row=len(timeline_data)+1) -chart2.add_data(data, titles_from_data=True) -chart2.set_categories(cats) - -ws.add_chart(chart2, "N22") - -# 차트 3: 전압 추이 -chart3 = LineChart() -chart3.title = "배터리 전압 추이" -chart3.style = 12 -chart3.y_axis.title = '전압 (V)' -chart3.x_axis.title = '시간대' -chart3.height = 10 -chart3.width = 20 - -data = Reference(ws, min_col=2, min_row=1, max_row=len(timeline_data)+1) -cats = Reference(ws, min_col=1, min_row=2, max_row=len(timeline_data)+1) -chart3.add_data(data, titles_from_data=True) -chart3.set_categories(cats) - -ws.add_chart(chart3, "N42") - -# 차트 4: 종합 혼합 차트 (배터리 잔량 + 전압 + 작업횟수 + 충전구간) -chart4_area = AreaChart() -chart4_area.title = "시간대별 종합 현황 (배터리/전압/작업/충전)" -chart4_area.style = 27 -chart4_area.y_axis.title = '배터리 잔량 (%) / 전압 (V × 10)' -chart4_area.x_axis.title = '시간대' -chart4_area.height = 15 -chart4_area.width = 30 - -# 충전 구간 배경 (면적 차트) -charging_data = Reference(ws, min_col=13, min_row=1, max_row=len(timeline_data)+1) -cats = Reference(ws, min_col=1, min_row=2, max_row=len(timeline_data)+1) -chart4_area.add_data(charging_data, titles_from_data=True) -chart4_area.set_categories(cats) - -# 배터리 잔량 선 추가 -battery_data = Reference(ws, min_col=4, min_row=1, max_row=len(timeline_data)+1) -chart4_area.add_data(battery_data, titles_from_data=True) - -# 전압 데이터 추가 -voltage_data = Reference(ws, min_col=2, min_row=1, max_row=len(timeline_data)+1) -chart4_area.add_data(voltage_data, titles_from_data=True) - -# 보조 차트: 작업횟수 (오른쪽 Y축 바 차트) -chart4_bar = BarChart() -chart4_bar.type = "col" -chart4_bar.grouping = "standard" - -work_data = Reference(ws, min_col=6, min_row=1, max_row=len(timeline_data)+1) -chart4_bar.add_data(work_data, titles_from_data=True) -chart4_bar.set_categories(cats) - -# 복합 차트 조합 -chart4_area.y_axis.crossAx = 500 -chart4_bar.y_axis.axId = 500 -chart4_bar.y_axis.title = "작업 횟수" -chart4_area += chart4_bar - -ws.add_chart(chart4_area, "A72") - -# ============================================================================ -# 8. 셀 전압 시트 스타일 및 차트 -# ============================================================================ - -if all_cells and '셀전압상세' in wb.sheetnames: - print("셀 전압 차트 생성 중...") - - ws_cells = wb['셀전압상세'] - - # 헤더 스타일 - for c_idx, col_name in enumerate(df_cells.columns, start=1): - cell = ws_cells.cell(row=1, column=c_idx) - cell.font = Font(bold=True, color="FFFFFF") - cell.fill = PatternFill(start_color="366092", end_color="366092", fill_type="solid") - cell.alignment = Alignment(horizontal='center') - - # 열 너비 조정 - ws_cells.column_dimensions['A'].width = 20 - for col in ['B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M']: - ws_cells.column_dimensions[col].width = 12 - - # 셀 전압 차이가 큰 행 강조 표시 - red_fill = PatternFill(start_color="FFCCCC", end_color="FFCCCC", fill_type="solid") - yellow_fill = PatternFill(start_color="FFFFCC", end_color="FFFFCC", fill_type="solid") - - for row_idx in range(2, len(df_cells) + 2): - voltage_diff = ws_cells.cell(row=row_idx, column=12).value - if voltage_diff and voltage_diff > 0.1: - for col_idx in range(1, 14): - ws_cells.cell(row=row_idx, column=col_idx).fill = red_fill - elif voltage_diff and voltage_diff > 0.05: - for col_idx in range(1, 14): - ws_cells.cell(row=row_idx, column=col_idx).fill = yellow_fill - - # 차트 5: 셀별 전압 추이 - chart5 = LineChart() - chart5.title = "셀별 전압 추이" - chart5.style = 10 - chart5.y_axis.title = '전압 (V)' - chart5.x_axis.title = '시간대' - chart5.height = 15 - chart5.width = 30 - - # 각 셀 데이터 추가 - for col_idx in range(2, 10): # Cell1~Cell8 - data = Reference(ws_cells, min_col=col_idx, min_row=1, max_row=len(df_cells)+1) - chart5.add_data(data, titles_from_data=True) - - cats = Reference(ws_cells, min_col=1, min_row=2, max_row=len(df_cells)+1) - chart5.set_categories(cats) - - ws_cells.add_chart(chart5, "O2") - - # 차트 6: 전압 불균형 추이 - chart6 = LineChart() - chart6.title = "셀 전압 불균형 추이 (최고-최저)" - chart6.style = 12 - chart6.y_axis.title = '전압 차이 (V)' - chart6.x_axis.title = '시간대' - chart6.height = 12 - chart6.width = 30 - - data = Reference(ws_cells, min_col=12, min_row=1, max_row=len(df_cells)+1) - chart6.add_data(data, titles_from_data=True) - chart6.set_categories(cats) - - ws_cells.add_chart(chart6, "O32") - -wb.save(output_file) - -print(f"\n리포트 생성 완료: {output_file}") - -# ============================================================================ -# 9. 요약 통계 -# ============================================================================ - -print("\n" + "=" * 80) -print("종합 분석 요약") -print("=" * 80) - -print(f"\n[분석 기간]") -print(f" {start_time.strftime('%Y-%m-%d %H:%M')} ~ {end_time.strftime('%Y-%m-%d %H:%M')}") - -print(f"\n[배터리 통계]") -if all_battery: - print(f" 최소 잔량: {min(b['level'] for b in all_battery)}%") - print(f" 최대 잔량: {max(b['level'] for b in all_battery)}%") - print(f" 평균 잔량: {sum(b['level'] for b in all_battery) / len(all_battery):.1f}%") - print(f" 최저 전압: {min(b['voltage'] for b in all_battery):.2f}V") - print(f" 최고 전압: {max(b['voltage'] for b in all_battery):.2f}V") - -print(f"\n[작업 통계]") -print(f" 총 작업 완료: {len(all_loading)}건") -location_stats = defaultdict(int) -for l in all_loading: - location_stats[l['location']] += 1 -for loc in sorted(location_stats.keys()): - print(f" {loc}: {location_stats[loc]}건") - -print(f"\n[충전 통계]") -charge_on_count = sum(1 for c in all_charge if c['status']) -charge_off_count = sum(1 for c in all_charge if not c['status']) -print(f" 충전 시작: {charge_on_count}회") -print(f" 충전 종료: {charge_off_count}회") - -# 셀 전압 통계 -if all_cells: - print(f"\n[셀 전압 통계]") - print(f" 최대 불균형: {max(c['voltage_diff'] for c in all_cells):.3f}V") - print(f" 평균 불균형: {sum(c['voltage_diff'] for c in all_cells) / len(all_cells):.3f}V") - print(f" 심각한 불균형 건수 (>0.1V): {len(critical_imbalance)}건") - print(f" 경고 수준 건수 (0.05~0.1V): {len(warning_imbalance)}건") - - print(f"\n[개별 셀 전압 범위]") - for i in range(1, 9): - cell_key = f'cell{i}' - cell_voltages = [c[cell_key] for c in all_cells] - print(f" Cell {i}: {min(cell_voltages):.3f}V ~ {max(cell_voltages):.3f}V " - f"(평균 {sum(cell_voltages)/len(cell_voltages):.3f}V)") - - # 가장 심각한 불균형 TOP 5 - print(f"\n[불균형 심각도 TOP 5]") - top5_imbalance = sorted(all_cells, key=lambda x: x['voltage_diff'], reverse=True)[:5] - for i, c in enumerate(top5_imbalance, 1): - print(f" {i}. {c['timestamp'].strftime('%Y-%m-%d %H:%M:%S')} - " - f"불균형: {c['voltage_diff']:.3f}V " - f"(최고 {c['max_voltage']:.3f}V - 최저 {c['min_voltage']:.3f}V)") - -print("\n" + "=" * 80) -print("분석 완료!") -print("=" * 80) diff --git a/경로계산백업.md b/경로계산백업.md new file mode 100644 index 0000000..e69de29 diff --git a/경로수동계산.md b/경로수동계산.md new file mode 100644 index 0000000..0d74db8 --- /dev/null +++ b/경로수동계산.md @@ -0,0 +1,158 @@ +AGV는 아래 태그사이에 존재한다면 해당 라인으로 간주하고 +각 라인별 목적지에 대한 경우의 수를 미리 계산 해본다 + +*1~10 : unloader line +*17~9 : charger 1 +*11~6 : cleanner +6~2 : buffer14 line +*8~13 : Loader Line + +충전기 #1 : 전진도킹 +충전기 #2 : 후진도킹 +로더,언로더,클리너,버퍼 : 후진도킹 + +AGV는 모니터반대방향에 리프트가 설치되어있고. 모니터쪽으로 이동하는 방향이 F방향이다. +충전소1(Chg#1)을 제외하고 나머지 포인트는 모두 리프트쪽으로 도킹을 해야한다(후면) +AGV에는 마그넷센서가달려있고 이 센서를 이용하여 좌/우/직진을 수행한다 L/R/S 로 명명함 + +Unloader line (모니터:우 -> F) + chg#1 : 0001(FS) 0016(FS) 0012(FS) 0010(FR) 0009(FS) 0015 [MARKSTOP] + chg#2 : 0001(FS) 0016(FS) 0012(FS) 0010(FR) 0009(BR) 0007(BS) 0013(BL) 0019 [MARKSTOP] + loader : 0001(FS) 0016(FS) 0012(FS) 0010(FR) 0009(BR) 0007(BS) 0013(BL) 0019(BR) 0008 [MARKSTOP] + unloader : 0012(FS) 0016(FS) 0001 [MARKSTOP] + cleanner : 0001(FS) 0016(FS) 0012(FS) 0010(FR) 0009(BR) 0007(BS) 0006(BR) 0011 [MARKSTOP] + buffer14 : 0001(FS) 0016(FS) 0012(FS) 0010(FR) 0009(BR) 0007(BS) 0006(BL) 0005(BL) 0003(BS) 0004(BR) 0002(FS) 0034 [MARKSTOP] + +Unloader line (모니터:좌 <- F) + chg#1 : 0001(BS) 0016(BS) 0012(BS) 0010(BL) 0007(FR) 0009(FS) 0015 [MARKSTOP] + chg#2 : 0001(BS) 0016(BS) 0012(BS) 0010(BL) 0007(BS) 0013(BL) 0019 [MARKSTOP] + loader : 0001(BS) 0016(BS) 0012(BS) 0010(BL) 0007(BS) 0013(BL) 0019(BR) 0008 [MARKSTOP] + unloader : 0001(BS) 0016(BS) 0012(BS) 0010(BL) 0009(FL) 0007(BR) 0010(BL) 0012(BL) 0016(BS) 0001 [MARKSTOP] + cleanner : 0001(BS) 0016(BS) 0012(BS) 0010(BL) 0007(BS) 0006(BR) 0011 [MARKSTOP] + buffer14 : 0001(BS) 0016(BS) 0012(BS) 0010(BL) 0007(BS) 0006(BL) 0005(BL) 0003(BS) 0004(BR) 0002(FS) [MARKSTOP] + +Charger #1 Line (모니터:우 ->F) + Chg#1: 0017(FS) 0009(FR) 0007(BR) 0010(FR) 0009(FS) 0015 [MARKSTOP] + Chg#2 : 0017(FS) 0009(FR) 0010(BR) 0007(BS) 0013(BL) 0019 [MARKSTOP] + Loader: 0017(FS) 0009(FR) 0010(BR) 0007(BS) 0013(BL) 0019(BR) 0008 [MARKSTOP] + Unloader: 0017(FS) 0009(FR) 0007(BS) 0010(BL) 0012(BL) 0016(BS) 0001 [MARKSTOP] + Cleanner: 0017(FS) 0009(FR) 0010(BR) 0007(BS) 0006(BR) 0011 [MARKSTOP] + Buffer14: 0017(FS) 0009(FR) 0010(BR) 0007(BS) 0006(BL) 0005(BL) 0003(BS) 0004(BR) 0002(FS) [MARKSTOP] + +Charger #1 Line (모니터:좌 <-F ) + Chg#1: 0017(BS) 0009(BL) 0015 [MARKSTOP] + Chg#2: 0017(BS) 0009(BS) 0007(FS) 0013(BL) 0019 [MARKSTOP] + Loader: 0017(BS) 0009(BS) 0007(FS) 0013(BL) 0019(BR) 0008 [MARKSTOP] + UnLoader: 0017(BS) 0009(BL) 0010(BL) 0012(BL) 0016(BS) 0001 [MARKSTOP] + Cleanner: 0017(BS) 0009(BS) 0007(FR) 0006(BR) 0011 [MARKSTOP] + Buffer: 0017(BS) 0009(BS) 0007(FR) 0006(BL) 0005(BL) 0003(BS) 0004(BR) 0002(FS) 0034 ~ 0031 [MARKSTOP] + +Cleanner Line (모니터:우 ->F) + Chg#1: 0011(FS) 0006(FL) 0007(FL) 0009(FL) 0015 [MARKSTOP] + Chg#2: 0011(FS) 0006(FL) 0007(BR) 0013(BL) 0019 [MARKSTOP] + Loader: 0011(FS) 0006(FL) 0007(BR) 0013(BL) 0019(BR) 0008 [MARKSTOP] + UnLoader: 0011(FS) 0006(FR) 0013(BL) 0007(BS) 0010(BL) 0012(BL) 0016(BS) 0001 [MARKSTOP] + Cleanner: 0006 0011 [MARKSTOP] + Buffer: 0011(FS) 0006(FL) 0007(BR) 0006(FR) 0005(BL) 0003(BS) 0004(BR) 0002(FS) [MARKSTOP] +Cleanner Line (모니터:좌 <- F) + Chg#1 0011(BS) 0006(BR) 0007(BL) 0010(BL) 0009(FL) 0015 [MARKSTOP] + Chg#2 0011(BS) 0006(BR) 0013(BS) 0019 [MARKSTOP] + Loader: 0011(BS) 0006(BR) 0013(BS) 0019(BR) 0008 [MARKSTOP] + UnLoader: 0011(BS) 0006(BR) 0007(BS) 0010(BL) 0012(BL) 0016(BS) 0001 [MARKSTOP] + Cleanner 0011(BS) 0006(BR) 0007(FL) 0013(BR) 0006(BR) 0011 [MARKSTOP] + Buffer 0011(BS) 0006(BR) 0007(FL) 0013(BR) 0006(FR) 0005(BL) 0003(BS) 0004(BR) 0002(FS) [MARKSTOP] +Buffer Line (모니터:우 -> F) - 교차로 : 0006 + Chg#1 0002(FS) 0004(FL) 0003(FL) 0005(FR) 0006(FS) 0007(FL) 0009(FL) 0015 [MARKSTOP] + Chg#2 0002(FS) 0004(FL) 0003(FL) 0005(FR) 0006(FS) 0007(BR) 0013(BL) 0019 [MARKSTOP] + Loader 0002(FS) 0004(FL) 0003(FL) 0005(FR) 0006(FS) 0007(BR) 0013(BL) 0019(BR) 0008 [MARKSTOP] + UnLoader 0002(FS) 0004(FL) 0003(FL) 0005(FR) 0006(FR) 0013(BL) 0007(BS) 0010(BL) 0012(BL) 0016(BS) 0001 [MARKSTOP] + Cleanner 0002(FS) 0004(FL) 0003(FL) 0005(FR) 0006(FR) 0013(BL) 0006(BR) 0011 [MARKSTOP] + Buffer 0005(B) 0003 0004 0002 0034 ~ 0031 [MARKSTOP] +Buffer Line(모니터:좌 <- F) - 교차로 : 0006 + Chg#1 0002(BS) 0004(BL) 0003(BL) 0005(BR) 0006(BR) 0013(FL) 0007(FL) 0009(FL) 0015 [MARKSTOP] + Chg#2 0002(BS) 0004(BL) 0003(BL) 0005(BR) 0006(BR) 0013(BS) 0019 [MARKSTOP] + Loader 0002(BS) 0004(BL) 0003(BL) 0005(BR) 0006(BR) 0013(BS) 0019(BR) 0008 [MARKSTOP] + UnLoader 0002(BS) 0004(BL) 0003(BL) 0005(BR) 0006(BR) 0007(BS) 0010(BL) 0012(BL) 0016(BS) 0001 [MARKSTOP] + Cleanner 0002(BS) 0004(BL) 0003(BL) 0005(BR) 0006(BR) 0013(FL) 0007(BR) 0006(BR) 0011 [MARKSTOP] + Buffer 0002(BS) 0004(BL) 0003(BL) 0005(BR) 0006(BR) 0013(FL) 0007(BR) 0006(FR) 0005(BL) 0003(BS) ~ 0034 [MARKSTOP] + +10 노드 시작 (모니터:우 -> F) + Chg#1 0010(FS) 0009(FL) 0015 [MARKSTOP] + Chg#2 0010(FR) 0009(BR) 0007(BS) 0013(BL) 0019 [MARKSTOP] + Loader 0010(FR) 0009(BR) 0007(BS) 0013(BL) 0019(BR) 0008 [MARKSTOP] + UnLoader 0010(BS) 0012(BL) 0016(BS) 0001 [MARKSTOP] + Cleanner 0010(FR) 0009(BR) 0007(BS) 0006(BR) 0011 [MARKSTOP] + Buffer 0010(FR) 0009(BR) 0007(BS) 0006(BL) 0005(BL) 0003(BS) 0004(BR) 0002(FS) [MARKSTOP] +10 노드 시작 (모니터:좌 <- F) + Chg#1 0010(BL) 0007(FR) 0009(FS) 0015 [MARKSTOP] + Chg#2 0010(BL) 0007(BS) 0013(BL) 0019 [MARKSTOP] + Loader 0010(BL) 0007(BS) 0013(BL) 0019(BR) 0008 [MARKSTOP] + UnLoader 0010(BL) 0009(FL) 0007(BS) 0010(BL) 0012(BL) 0016(BS) 0001 [MARKSTOP] + Cleanner 0010(BL) 0007(BS) 0006(BR) 0011 [MARKSTOP] + Buffer 0010(BL) 0007(BS) 0006(BL) 0005(BL) 0003(BS) 0004(BR) 0002(FS) [MARKSTOP] + +7 노드 시작 (모니터:우 -> F) + Chg#1 0007(BR) 0010(FR) 0009(FS) 0015 [MARKSTOP] + Chg#2 0007(BS) 0013(BL) 0019 [MARKSTOP] + Loader 0007(BS) 0013(BL) 0019(BR) 0008 [MARKSTOP] + UnLoader 0007(BR) 0009(FL) 0010(BL) 0012(BL) 0016(BS) 0001 [MARKSTOP] + Cleanner 0007(BS) 0013(BL) 0006(BR) 0011 [MARKSTOP] + Buffer 0007(BS) 0013(BL) 0006(FR) 0005(BL) 0003(BS) 0004(BR) 0002(FS) [MARKSTOP] + +7 노드 시작 (모니터:좌 <- F) + Chg#1 0007(FR) 0009(FL) 0015 [MARKSTOP] + Chg#2 0007(BS) 0013(BL) 0019 [MARKSTOP] + Loader 0007(BS) 0013(BL) 0019(BR) 0008 [MARKSTOP] + UnLoader 0007(FR) 0009(BR) 0010(BL) 0012(BL) 0016(BS) 0001 [MARKSTOP] + Cleanner 0007(BS) 0006(BR) 0011 [MARKSTOP] + Buffer 0007(BS) 0006(BL) 0005(BL) 0003(BS) 0004(BR) 0002(FS) 0034 [MARKSTOP] + +Buffer Internal Move 목표버퍼가 우측에 있는 경우 (모니터:우 -> F) : 도킹방향은 맞음 + Buf1->Buf4 0031(FS) 0032(FS) 0033(FS) 0034(FS) : 목표 노드까지는 전진방향으로 이동(전진은 우측으로 이동함) + 이동완료 후 R방향(반대)으로 MARSTOP 신호를 통해서 멈춤 +Buffer Internal Move 목표버퍼가 좌측에 있는 경우 (모니터:우 -> F) : 도킹방향은 맞음 + Buf4->Buf1 목표 노드까지는 후진방향으로 이동(후진은 좌측으로 이동함) + 이동완료 후 MARKSTOP 신호를 통해서 멈춤 + * NOTE: 정지 정밀도를 높이기 위해 항상 목표지점의 우측에서 좌측방향으로 진입하며 멈추도록 설계됨. (센서 히스테리시스 고려) +Buffer Internal Move (모니터:좌 <- F) : 도킹방향 맞지않음 (방향전환 필요하니 6에서 전환 필요) + ~ 0006(BS) 0005(BR) 0013(FS) 0007(BR) 0006(BL) 0005(BS) ~ 목표노드까지 이동한 후 MARKSTOP + +#노드범위 [0008,0019,0013] +Loader Line (모니터:우 -> F) : 전진(F)은 0008 -> 좌측/하단 방향. 따라서 19번(우측/상단)으로 가려면 후진(B)해야 함. + Chg#1 0008(BS) 0019(BS) 0013(BS) 0007(BS) 0010(FR) 0009(FS) 0015 [MARKSTOP] + Chg#2 0008(BS) 0019(BS) 0013(BS) 0007(FR) 0006(BR) 0013(BS) 0019 [MARKSTOP] + Loader 0008(BS) 0019(BS) 0013(BS) 0007(FR) 0006(BR) 0013(BS) 0019(BS) 0008 [MARKSTOP] + UnLoader 0008(BS) 0019(BS) 0013(BS) 0007(BS) 0010(BS) 0012(BS) 0016(BS) 0001 [MARKSTOP] + Cleanner 0008(BS) 0019(BS) 0013(BL) 0006(BS) 0011 [MARKSTOP] + Buffer 0008(BS) 0019(BS) 0013(BL) 0006(BL) 0005(BL) 0003(BS) 0004(BS) 0002(FS) 0034 [MARKSTOP] + +Loader Line (모니터:좌 <- F) : 전진(F)은 0008 -> 우측/상단(19번) 방향. 따라서 19번으로 가려면 전진(F)해야 함. + Chg#1 0008(FS) 0019(FS) 0013(FS) 0007(FL) 0009(FS) 0015 [MARKSTOP] + Chg#2 0008(FS) 0019(FS) BS(반대방향으로) [MARKSTOP] + Loader 0013(BS) 0019(BS) 0008(BS) [MARKSTOP] + UnLoader 0008(FS) 0019(FS) 0013(FS) 0007(FL) 0009(BL) 0010(BS) 0012(BS) 0016(BS) 0001 [MARKSTOP] + Cleanner 0008(FS) 0019(FS) 0013(FS) 0007(BR) 0006(BS) 0011 [MARKSTOP] + Buffer 0008(FS) 0019(FS) 0013(FS) 0007(BR) 0006(BL) 0005(BL) 0003(BS) 0004(BS) 0002(BS) 0034 [MARKSTOP] + +============ 각 노드별 모든 경우의 수를 표시한다 ======================================================== +도킹위치에따른 방향 : 0001(B),0015(F),0011(B),0019(B),0008(B),0034(B),0033(B),0032(B),0031(B) +==================================================================================================== +공용그룹이동 (해당 목표까지의 중요 사이의 경로) + [모니터방향:좌/상] - + [G1312ML] 0013(FS) 0007(FL) 0009(BL) 0010(BS) 0012(BS) + [G1913ML] 0019(FS) 0013(FS) 0007(FL) 0009(FS) + [G1309ML] 0013(FS) 0007(FL) 0009(FS) + [G0110ML] 0001(BS) 0016(BS) 0012(BS) 0010(BL) + [G0601ML] 0006(BR) 0007(BS) 0010(BS) 0012(BS) 0016(BS) 0001(BS) + [G0519ML] 0005(BR) 0006(BR) 0007(BS) 0013(BL) 0019(BS) + + [G1213ML] 0012(FS) 0010(FR) 0009(BR) 0007(BS) 0013(BL) + + [모니터방향:우/하] + [G1312MR] 0013(BS) 0007(BS) 0010(BS) 0012(BS) + [G1309MR] 0013(BS) 0007(BS) 0010(FR) 0009(FS) + [G1610MR] 0001(BS) 0016(BS) 0012(BS) 0010(BL) + +==================================================================================================== +모든 경우의 수 데이터 나열 값 순서 모니터방향(ML,MR) | 시작노드 | 목표노드 | 경로 +====================================================================================================