Bläddra i källkod

1. 多配方修改。2. 调试窗体界面编写。

master
Nah 1 år sedan
förälder
incheckning
459f51ea6e
9 ändrade filer med 280 tillägg och 97 borttagningar
  1. +1
    -1
      BPA.Model/Enums/MoveConveyerStep.cs
  2. +1
    -1
      BPA.Model/GlobalData.cs
  3. +2
    -0
      BPA.Model/Recipe/RecipeData.cs
  4. +1
    -1
      BPA.SingleDevice/Business/Conveyer.cs
  5. +193
    -58
      BPA.SingleDevice/Business/ProcessControl.cs
  6. +1
    -1
      BPA.SingleDevice/View/AddRawMaterialDialogView.xaml
  7. +68
    -23
      BPA.SingleDevice/View/DebugView.xaml
  8. +10
    -6
      BPA.SingleDevice/ViewModel/DebugViewModel.cs
  9. +3
    -6
      BPA.SingleDevice/ViewModel/OrderMainViewModel.cs

BPA.Model/Enums/MoveConveyer.cs → BPA.Model/Enums/MoveConveyerStep.cs Visa fil

@@ -6,7 +6,7 @@ using System.Threading.Tasks;

namespace BPA.Model.Enums
{
public enum MoveConveyer:int
public enum MoveConveyerStep:int
{
WaitMove=0,
Moveing=100,

+ 1
- 1
BPA.Model/GlobalData.cs Visa fil

@@ -22,7 +22,7 @@ namespace BPA.Model
#endregion

#region 传送带
public MoveConveyer MoveConveyerStep { get; set; }
public MoveConveyerStep MoveConveyerStep { get; set; }
#endregion
}
}

+ 2
- 0
BPA.Model/Recipe/RecipeData.cs Visa fil

@@ -37,6 +37,8 @@ namespace BPA.Model.Recipe
Name = name;
MaterialData = materialData;
//取决于工位数量,本案例中,有五个工位,但是第三个工位没有设备。

CurrentStation = 1;//初始默认为1。
IsMakeComplete = new bool[stationCount];
IssueTime = DateTime.Now;
BatchStatus = new();


+ 1
- 1
BPA.SingleDevice/Business/Conveyer.cs Visa fil

@@ -47,7 +47,7 @@ namespace BPA.SingleDevice.Business
{
HaveVessel[0] = haveVessel.GetBitValue(1);
HaveVessel[1] = haveVessel.GetBitValue(2);
//HaveVessel[2] = false;
HaveVessel[2] = true;
HaveVessel[3] = haveVessel.GetBitValue(3);
HaveVessel[4] = haveVessel.GetBitValue(4);
});


+ 193
- 58
BPA.SingleDevice/Business/ProcessControl.cs Visa fil

@@ -1,6 +1,7 @@
using Amazon.SecurityToken.Model;
using BPA.Model.Enums;
using BPA.Model.Recipe;
using BPA.Model.Table;
using BPA.SingleDevice.Interface;
using BPA.SingleDevice.Json;
using BPA.SingleDevice.Services;
@@ -32,6 +33,8 @@ namespace BPA.SingleDevice.Business
List<TaskServer> currentTask = new();
//ConcurrentDictionary<int, TaskServer> test = new();

List<RecipeData> currentRecipes = new();

IConveyer conveyer = new Conveyer();
private readonly ILogService logService;
private GlobalData global;
@@ -60,23 +63,23 @@ namespace BPA.SingleDevice.Business
batchers.TryAdd(4, new Batcher());
batchers.TryAdd(5, new Batcher());

SetBatcherComm(1, "192.168.6.100");
SetBatcherComm(2, "192.168.6.101");
SetBatcherComm(4, "192.168.6.102");
SetBatcherComm(5, "192.168.6.103");
//SetBatcherComm(1, "192.168.6.100");
//SetBatcherComm(2, "192.168.6.101");
//SetBatcherComm(4, "192.168.6.102");
//SetBatcherComm(5, "192.168.6.103");

//SetBatcherComm(1, "127.0.0.1", 503);
//SetBatcherComm(2, "127.0.0.1", 504);
//SetBatcherComm(4, "127.0.0.1", 505);
//SetBatcherComm(5, "127.0.0.1", 506);
SetBatcherComm(1, "127.0.0.1", 503);
SetBatcherComm(2, "127.0.0.1", 504);
SetBatcherComm(4, "127.0.0.1", 505);
SetBatcherComm(5, "127.0.0.1", 506);
foreach (var batcher in batchers.Values)
{
await batcher.Initial();
}
#endregion

conveyer.SetCommParam(1, "192.168.6.104",508);
//conveyer.SetCommParam(1, "127.0.0.1",510);
//conveyer.SetCommParam(1, "192.168.6.104",508);
conveyer.SetCommParam(1, "127.0.0.1",510);
await conveyer.Initial();

currentTask.Clear();
@@ -86,40 +89,68 @@ namespace BPA.SingleDevice.Business
{
InterActive();

for (int i = 0; i < currentTask.Count; i++)
//for (int i = 0; i < currentTask.Count; i++)
//{
// if (currentTask[i].CurrentRecipe.IsMakeComplete.All(b=>b==true))
// {
// currentTask.RemoveAt(i);
// break;
// }
//}

for (int i = 0; i < currentRecipes.Count; i++)
{
if (currentTask[i].CurrentRecipe.IsMakeComplete.All(b=>b==true))
if (currentRecipes[i].IsMakeComplete.All(b => b == true))
{
currentTask.RemoveAt(i);
var recipeName = currentRecipes[i].Name;
var time = DateTime.Now.Subtract(currentRecipes[i].IssueTime);
currentRecipes.RemoveAt(i);
logService.LogRecipeCompleteInfo($"【{recipeName}】,耗时【{time.Seconds}】秒。");
logService.LogRunInfo($"配方【{recipeName}】-- 整体配料完成,已从配料队列移除。");
break;
}
}

if (global.RecipeQueue.Count>0/* && currentRecipe is null*/ )
{
//多配方情况下,必须在工位1没有碗位置,才能进行下发,否则会与之前的配方冲突。
if (/*!conveyer.HaveVessel[0] &&*/ global.RecipeQueue.ElementAt(0) is not null && global.RecipeQueue.ElementAt(0) is RecipeData && currentTask.Count <5 )
{
//if (/*!conveyer.HaveVessel[0] &&*/ global.RecipeQueue.ElementAt(0) is not null && global.RecipeQueue.ElementAt(0) is RecipeData && currentTask.Count <5 )
//{

//global.RecipeQueue.TryDequeue(out currentRecipe);
//cts = new();
//Task.Run(() => { Batching(currentRecipe); }, cts.Token);
//logService.LogRunInfo($"配方【{currentRecipe.Name}】-- 开始执行配料。");

//global.RecipeQueue.TryDequeue(out currentRecipe);
//cts = new();
//Task.Run(() => { Batching(currentRecipe); }, cts.Token);
//logService.LogRunInfo($"配方【{currentRecipe.Name}】-- 开始执行配料。");
//global.RecipeQueue.TryDequeue(out RecipeData recipe);
//if (recipe !=null)
//{
// currentTask.Add(new TaskServer() { RunTask = Task.Run(() => { Batching(recipe); }),
// ID = recipe.IssueTime.Ticks,CurrentRecipe=recipe });
// logService.LogRunInfo($"配方【{recipe.Name}】-- 开始执行配料。");
//}
//}


if (/*!conveyer.HaveVessel[0] &&*/ global.RecipeQueue.ElementAt(0) is not null && global.RecipeQueue.ElementAt(0) is RecipeData && currentRecipes.Count <5 )
{
global.RecipeQueue.TryDequeue(out RecipeData recipe);
if (recipe !=null)
if (recipe != null)
{
currentTask.Add(new TaskServer() { RunTask = Task.Run(() => { Batching(recipe); }),
ID = recipe.IssueTime.Ticks,CurrentRecipe=recipe });
currentRecipes.Add(recipe);
logService.LogRunInfo($"配方【{recipe.Name}】-- 开始执行配料。");
}
}
}

Batching();
}, "MonitorRecipeIssue", true);
}
/// <summary>
/// 配料。
/// </summary>
/// <param name="recipe">需要配料的配方</param>
[Obsolete("流程有错误")]
private async void Batching(RecipeData recipe)
{
if (recipe is null)
@@ -129,7 +160,7 @@ namespace BPA.SingleDevice.Business
}
while (recipe.IsMakeComplete[0] == false)
{
await StationBatching(recipe, 1);
//await StationBatching(recipe, 1);
}
for (int stationNum = 2; stationNum <= 5; stationNum++)
{
@@ -146,23 +177,21 @@ namespace BPA.SingleDevice.Business
/// </summary>
/// <param name="recipe">配方</param>
/// <param name="stationNum">工位数。</param>
private async Task StationBatching(RecipeData recipe,int stationNum)
private void StationBatching(RecipeData recipe,int stationNum)
{
#region 数据验证
if (recipe is null)
{
logService.LogRunInfo($"参数<recipe>值为null,配料流程结束。");
return;
}
//if (recipe is null)
//{
// logService.LogRunInfo($"参数<recipe>值为null,配料流程结束。");
// return;
//}
//如果配料机里没连接该工位的配料机,则直接完成。
if (!batchers.ContainsKey(stationNum))
{
recipe.BatchStatus[stationNum] = BatchStep.BatchCompleted;
recipe.IsMakeComplete[stationNum - 1] = true;
logService.LogRunInfo($"参数<stationNum>值为[{stationNum}],目前该工位无配料机或连接配料机失败。");
//工位3无到位检测。
//recipe.CurrentStation = stationNum;
logService.LogRunInfo($"参数【工位】值为[{stationNum}],目前该工位无配料机或连接配料机失败。");
return;
}
#endregion
@@ -170,7 +199,6 @@ namespace BPA.SingleDevice.Business
//数组起始索引是0,工位起始ID是1。
if (conveyer.HaveVessel[stationNum-1])
{
recipe.CurrentStation = stationNum;
ushort[] materialList=new ushort[14];
//获取工位需要的配料数据。
if (recipe.MaterialData.ContainsKey(stationNum))
@@ -185,7 +213,7 @@ namespace BPA.SingleDevice.Business
logService.LogRunInfo($"参数<stationNum>值为[{stationNum}],该配方无该工位配料需求。");
return;
}
//配料完成的上升沿检测。
//配料机配料完成的上升沿检测。
var completeTrig =RTrig.GetInstance($"Batchers[{stationNum}].BatchComplete").Start(batchers[stationNum].BatchComplete);
//配料流程。
@@ -205,7 +233,7 @@ namespace BPA.SingleDevice.Business
else
{
logService.LogRunInfo($"配方【{recipe.Name}】写入工位【{stationNum}】的下料参数失败,稍后重试。");
await Task.Delay(3000);
Task.Delay(3000).Wait();
}
}
else
@@ -218,18 +246,15 @@ namespace BPA.SingleDevice.Business
if (batchers[stationNum].StartBatching())
{
recipe.BatchStatus[stationNum] = BatchStep.WaitBatchComplete;
logService.LogRunInfo($"配方【{recipe.Name}】工位【{stationNum}】开始配料,等待配料完成信号上升沿。");
logService.LogRunInfo($"配方【{recipe.Name}】工位【{stationNum}】开始配料,等待配料完成信号上升沿。");
}
else
{
logService.LogRunInfo($"配方【{recipe.Name}】写入工位【{stationNum}】开始配料失败,3S后重试。");
await Task.Delay(3000);
logService.LogRunInfo($"配方【{recipe.Name}】写入工位【{stationNum}】开始配料失败,3S后重试。");
Task.Delay(3000).Wait();
}
break;
case BatchStep.WaitBatchComplete:
//先延时,以免味魔方还没开始工作,未把配料完成写为false。
//await Task.Delay(500);
//if (batchers[stationNum].BatchComplete)
if (completeTrig)
{
logService.LogRunInfo($"配方【{recipe.Name}】工位【{stationNum}】的配料完成。");
@@ -244,25 +269,25 @@ namespace BPA.SingleDevice.Business
else
{
logService.LogRunInfo($"配方【{recipe.Name}】工位【{stationNum}】未检测到容器到位,请检查,3秒后重新检测。");
await Task.Delay(3000);
Task.Delay(3000).Wait();
}
}
[Obsolete("流程有错误")]
private async Task MoveOnceAndBatach(RecipeData recipe,int stationNum)
{
global.MoveConveyerStep = MoveConveyer.WaitMove;
while (global.MoveConveyerStep != MoveConveyer.MoveComplete)
global.MoveConveyerStep = MoveConveyerStep.WaitMove;
while (global.MoveConveyerStep != MoveConveyerStep.MoveComplete)
{
var moveCompleteTrig = RTrig.GetInstance("MoveCompleted").Start(conveyer.MoveComplete);
switch (global.MoveConveyerStep)
{
case MoveConveyer.WaitMove:
case MoveConveyerStep.WaitMove:
conveyer.InitalMoveParam();
await Task.Delay(500);
if (conveyer.MoveOnce())
{
logService.LogRunInfo($"配方【{recipe.Name}】控制传送带去下个工位,等待动作完成信号上升沿。");
global.MoveConveyerStep = MoveConveyer.Moveing;
global.MoveConveyerStep = MoveConveyerStep.Moveing;
}
else
{
@@ -270,19 +295,19 @@ namespace BPA.SingleDevice.Business
await Task.Delay(3000);
}
break;
case MoveConveyer.Moveing:
case MoveConveyerStep.Moveing:
if (moveCompleteTrig)
{
logService.LogRunInfo($"配方【{recipe.Name}】控制传送带移动结束。");
conveyer.InitalMoveParam();
while (recipe.IsMakeComplete[stationNum - 1] == false)
{
await StationBatching(recipe, stationNum);
//await StationBatching(recipe, stationNum);
}
global.MoveConveyerStep = MoveConveyer.MoveComplete;
global.MoveConveyerStep = MoveConveyerStep.MoveComplete;
}
break;
case MoveConveyer.MoveComplete:
case MoveConveyerStep.MoveComplete:
//logService.LogRunInfo($"配方【{recipe.Name}】控制传送带移动结束。");
//await StationBatching(recipe, stationNum);
break;
@@ -291,6 +316,49 @@ namespace BPA.SingleDevice.Business
}
/// <summary>
/// 移动传送带。
/// </summary>
/// <returns></returns>
private void MoveConveyer()
{
//global.MoveConveyerStep = MoveConveyerStep.WaitMove;
//while (global.MoveConveyerStep != MoveConveyerStep.MoveComplete)
//{
var moveCompleteTrig = RTrig.GetInstance("MoveCompleted").Start(conveyer.MoveComplete);
switch (global.MoveConveyerStep)
{
case MoveConveyerStep.WaitMove:
conveyer.InitalMoveParam();
Task.Delay(500).Wait();
if (conveyer.MoveOnce())
{
logService.LogRunInfo($"控制传送带去下个工位,等待动作完成信号上升沿。");
global.MoveConveyerStep = MoveConveyerStep.Moveing;
}
else
{
logService.LogRunInfo($"控制传送带去下个工位失败,可能连接异常或不允许移动,3S后重试。");
Task.Delay(3000).Wait();
}
break;
case MoveConveyerStep.Moveing:
if (moveCompleteTrig)
{
logService.LogRunInfo($"控制传送带移动结束。");
global.MoveConveyerStep = MoveConveyerStep.MoveComplete;
}
break;
case MoveConveyerStep.MoveComplete:
conveyer.InitalMoveParam();
UpdateRecipe();
global.MoveConveyerStep = MoveConveyerStep.WaitMove;
//不会执行该步骤,会直接跳出循环。
break;
}
//}
}
/// <summary>
/// 设置相应设备ID的配料机的通讯参数。
/// </summary>
/// <param name="id">该设备对应的工位ID。</param>
@@ -313,11 +381,20 @@ namespace BPA.SingleDevice.Business
ActionManage.GetInstance.Register<bool>(new Func<bool>(() =>
{
//目前如果工位1 没有碗或者当前没配方就可以下配方。
//bool result =(currentTask.Count > 0 && !conveyer.HaveVessel[0]) || (currentTask.Count==0);
foreach (var item in currentTask)
//foreach (var item in currentTask)
//{
// //起始工位没完成的不允许下配方。
// if (!item.CurrentRecipe.IsMakeComplete[0])
// {
// return false;
// }
//}
//return true;

//2023.10.14修改:如果在配方队列里,有配方的当前工位是1,则不允许下发新的配方。
foreach (var item in currentRecipes)
{
//起始工位没完成的不允许下配方。
if (!item.CurrentRecipe.IsMakeComplete[0])
if (item.CurrentStation==1)
{
return false;
}
@@ -364,6 +441,21 @@ namespace BPA.SingleDevice.Business
}
return true;
}
/// <summary>
/// 2023.10.14:新增,所有在队列的配方,必须等当前工位的配料完成后才可以移动,否则不允许移动。
/// </summary>
/// <returns></returns>
private bool IsAllowConveyerMove()
{
foreach (var item in currentRecipes)
{
if (item.IsMakeComplete[item.CurrentStation-1]==false)
{
return false;
}
}
return true;
}
private void SingleDetect()
{
//TODO:上升沿信号检测。
@@ -375,8 +467,6 @@ namespace BPA.SingleDevice.Business
{
ConveyerConfig conveyerConfig = new() { IP = "192.168.6.104", Port = 502, ID = 1, IsConnect = true };
Json<ConnectConfig>.Data.ConveyerConfigs.Add(conveyerConfig);

}
/// <summary>
/// 初始化配料机配置。
@@ -389,7 +479,10 @@ namespace BPA.SingleDevice.Business
Json<ConnectConfig>.Data.BatcherConfigs.Add(batcherConfig);
}
}

/// <summary>
/// 初始化配料机。
/// </summary>
/// <param name="configs"></param>
private void InitalBatcher(IList<BatcherConfig> configs)
{
foreach (var item in configs)
@@ -402,6 +495,48 @@ namespace BPA.SingleDevice.Business
}
}
}

/// <summary>
/// 刷新配方的当前工站。
/// </summary>
private void UpdateRecipe()
{
foreach (var item in currentRecipes)
{
//if (item.CurrentStation<5 && conveyer.HaveVessel[item.CurrentStation])
//{
// item.CurrentStation++;
//}

if (item.CurrentStation<5)
{
while (!conveyer.HaveVessel[item.CurrentStation])
{
logService.LogRunInfo($"未检测到配方【{item.Name}】在工位【{item.CurrentStation + 1}】的容器到位信号,请检查。");
Task.Delay(3000).Wait();
}
item.CurrentStation++;
}
}
}
/// <summary>
/// 适用于多配方的配料。
/// </summary>
private void Batching()
{
if (currentRecipes.Count>0 && IsAllowConveyerMove())
{
MoveConveyer();
}
foreach (var item in currentRecipes)
{
if (!item.IsMakeComplete[item.CurrentStation-1])
{
StationBatching(item, item.CurrentStation);
}
}
}
}

}

+ 1
- 1
BPA.SingleDevice/View/AddRawMaterialDialogView.xaml Visa fil

@@ -38,7 +38,7 @@
<TextBox
Grid.Row="0"
Grid.Column="1"
Width="200"
Width="340"
Style="{StaticResource DarkTextBox}"
Text="{Binding RawMaterResultInfo.Name}" />



+ 68
- 23
BPA.SingleDevice/View/DebugView.xaml Visa fil

@@ -12,32 +12,77 @@
mc:Ignorable="d">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="auto" />
<RowDefinition Height="1*" />
<RowDefinition Height="1*" />
</Grid.RowDefinitions>

<ToggleButton
Margin="10"
HorizontalAlignment="Right"
bpa:ToggleButtonHelper.CheckedContent="调试模式"
Command="{Binding SwitchSystemModeCommand}"
CommandParameter="{Binding RelativeSource={RelativeSource Self}, Path=IsChecked}"
Content="配料模式"
FontSize="22"
Style="{DynamicResource SwitchAccentToggleButton}" />

<!-- 流水线手动控制移动 -->
<StackPanel VerticalAlignment="Top" Orientation="Horizontal">
<Button
Width="100"
Height="50"
Margin="10"
Command="{Binding MoveInchCommand}"
Content="流水线寸动" />
<ToggleButton
Margin="10"
bpa:ToggleButtonHelper.CheckedContent="反转"
Content="正转"
IsChecked="{Binding IsReverse}"
Style="{DynamicResource SwitchAccentToggleButton}" />
<TextBlock
FontSize="16"
Foreground="White"
Text="寸动速度:" />
</StackPanel>
<!--味魔方手动控制-->
<StackPanel VerticalAlignment="Top" Orientation="Horizontal" Grid.Row="1">
</StackPanel>
<Border
Grid.Row="1"
Margin="10"
BorderBrush="Gray"
BorderThickness="3">
<StackPanel
HorizontalAlignment="Stretch"
VerticalAlignment="Top"
Orientation="Horizontal">
<Button
Width="100"
Height="50"
Margin="10"
Command="{Binding StartMoveInchCommand}"
Content="寸动开始"
FontSize="18" />
<Button
Width="100"
Height="50"
Margin="10"
Command="{Binding StopMoveInchCommand}"
Content="寸动停止"
FontSize="18" />
<ToggleButton
Margin="10"
bpa:ToggleButtonHelper.CheckedContent="反转"
Content="正转"
FontSize="22"
IsChecked="{Binding IsReverse}"
Style="{DynamicResource SwitchAccentToggleButton}" />
<TextBlock
FontSize="22"
Foreground="White"
Text="寸动速度:" />

<TextBox
Width="150"
Height="45" FontSize="16"
Margin="10" Text="{Binding InchSpeed}"/>


</StackPanel>
</Border>


<!-- 味魔方手动控制 -->
<Border
Grid.Row="2"
Margin="10"
BorderBrush="Gray"
BorderThickness="3">
<StackPanel
Grid.Row="1"
VerticalAlignment="Top"
Orientation="Horizontal" />
</Border>
</Grid>
</UserControl>

+ 10
- 6
BPA.SingleDevice/ViewModel/DebugViewModel.cs Visa fil

@@ -10,18 +10,22 @@ namespace BPA.SingleDevice.ViewModel
{
public DebugViewModel()
{
MoveInchCommand = new(() =>
{

});
}

public BPARelayCommand<bool> SwitchSystemModeCommand { get; set; }
/// <summary>
/// 开始寸动。
/// </summary>
public BPARelayCommand StartMoveInchCommand { get; set; }
/// <summary>
/// 流水线寸动。
/// 开始寸动。
/// </summary>
public BPARelayCommand MoveInchCommand { get; set; }
public BPARelayCommand EndMoveInchCommand { get; set; }
/// <summary>
/// 寸动是否反转。
/// </summary>
public bool IsReverse { get; set; }
public float InchSpeed { get; set; }
}
}

+ 3
- 6
BPA.SingleDevice/ViewModel/OrderMainViewModel.cs Visa fil

@@ -39,7 +39,7 @@ namespace BPA.SingleDevice.ViewModel
{
if (o != null && !string.IsNullOrEmpty(o.ToString()))
{
if (MessageBoxR.ConfirmGlobal("是否下发配方?","提示")==MessageBoxResult.Yes)
if (MessageBoxR.ConfirmGlobal("是否下发配方?","提示")==MessageBoxResult.Yes)
{
var result= ActionManage.GetInstance.Send<bool>("CanIssueRecipe");
if (result != null && result.IsSuccess && result.Content==true)
@@ -48,7 +48,7 @@ namespace BPA.SingleDevice.ViewModel
}
else
{
Message.ErrorGlobal("下发配方失败,下发配方时工位【1】不可有碗,请检查后重试。");
Message.ErrorGlobal("下发配方失败,当前有配方在执行工位【1】的配料流程,请检查后重试。");
}
}
}
@@ -59,7 +59,7 @@ namespace BPA.SingleDevice.ViewModel

public BPARelayCommand<object> DownRecipeCommand { get; set; }

private RecipeData GenerateRecipe(string recipeID)
private void GenerateRecipe(string recipeID)
{
if (string.IsNullOrEmpty(recipeID))
{
@@ -126,9 +126,6 @@ namespace BPA.SingleDevice.ViewModel
logService.LogRunInfo($"解析配方数据失败,未找到【{recipeID}】对应的配方。");
}
}

return null;
}
/// <summary>
/// 之前的配方数据解析。


Laddar…
Avbryt
Spara