add - 机械臂逻辑实现,添加任务模板,点位,AGV的固定配置

master
SoulStar 3 months ago
parent e7f2c56687
commit cea1535523

@ -0,0 +1,13 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace SlnMesnac.Config
{
public class AGVConfig
{
public string AGVGUID { get; set; }
public string AGVName { get; set; }
}
}

@ -58,6 +58,24 @@ namespace SlnMesnac.Config
/// </summary>
public List<VisionConfig> visionConfig { get; set; }
/// <summary>
/// AGV配置
/// </summary>
public List<AGVConfig> AGVConfig { get; set; }
/// <summary>
/// 地图点位配置
/// </summary>
public List<PositionConfig> PositionConfig { get; set; }
/// <summary>
/// 模板配置
/// </summary>
public List<JobConfig> JobConfig { get; set; }
/// <summary>
/// Redis配置
/// </summary>

@ -0,0 +1,13 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace SlnMesnac.Config
{
public class JobConfig
{
public string JobGUID { get; set; }
public string JobName { get; set; }
}
}

@ -0,0 +1,15 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace SlnMesnac.Config
{
public class PositionConfig
{
public string PointGUID { get; set; }
public string PointName { get; set; }
public string PointParamName { get; set; }
}
}

@ -122,4 +122,41 @@ namespace SlnMesnac.Model.AirportApiEntity
/// </summary>
public string guid { get; set; }
}
public class NewAddTaskByAGV
{
public AGVRequestAddTaskEntity NewTaskEntity(string AGVGUID, string JobGUID, string PointGUID, string ParamName, string TaskName = "AGVCTask", string RobotType = "S800")
{
AGVRequestAddTaskEntity aGVRequestAddTaskEntity = new AGVRequestAddTaskEntity()
{
businessOrderId = TaskName,
priority = 0,
RobotType = RobotType,
robotId = AGVGUID,
group = "",
taskSource = "agvc",
taskType = 0,
verifyStatus = 0,
enableSplitCar = 0,
load = new List<LoadsEntity>()
{
new LoadsEntity()
{
jobid = JobGUID,
location = PointGUID,
param = new List<ParamEntity>()
{
new ParamEntity()
{
paramname = ParamName,
paramvalue = PointGUID,
}
},
robotPort = ""
}
},
};
return aGVRequestAddTaskEntity;
}
}
}

@ -86,6 +86,8 @@ namespace SlnMesnac.TouchSocket
private string TestClientID = "";
public int Vport;
public TcpServer(ILogger<TcpServer> logger, TcpService tcpService, AppConfig appConfig)
{
_logger = logger;
@ -108,40 +110,44 @@ namespace SlnMesnac.TouchSocket
{
_service.Connecting = (client, e) =>
{
_logger.LogInformation($"客户端{client.IP}正在接入服务");
_logger.LogInformation($"客户端{client.IP}:{client.Port}正在接入服务");
return EasyTask.CompletedTask;
};
_service.Connected = (client, e) =>
{
_logger.LogInformation($"客户端{client.IP}接入服务成功");
_logger.LogInformation($"客户端{client.IP}:{client.Port}接入服务成功");
RefreshClientInfoEvent?.Invoke(_service);
RefreshStateAction?.Invoke(client.IP, true);
client.ResetId(client.Port.ToString());
TestClientID = client.Port.ToString();
Vport = client.Port;
return EasyTask.CompletedTask;
};
_service.Disconnected = (client, e) =>
{
_logger.LogInformation($"客户端{client.IP}断开连接");
_logger.LogInformation($"客户端{client.IP}:{client.Port}断开连接");
RefreshStateAction?.Invoke(client.IP, false);
RefreshClientInfoEvent?.Invoke(_service);
return EasyTask.CompletedTask;
};
_service.Received = (client, e) =>
{
var mes = Encoding.UTF8.GetString(e.ByteBlock.Buffer, 0, e.ByteBlock.Len);//注意数据长度是byteBlock.Len
_logger.LogInformation($"客户端{client.IP}:" + mes);
//区分一下指令类型,委托传参
if (mes == "heartbeat")
{
RefreshStateAction?.Invoke(client.IP, true);
}
//var mes = Encoding.UTF8.GetString(e.ByteBlock.Buffer, 0, e.ByteBlock.Len);//注意数据长度是byteBlock.Len
//_logger.LogInformation($"客户端{client.IP}:{client.Port} " + mes);
//区分一下指令类型,委托传参
//if (mes == "heartbeat")
//{
// RefreshStateAction?.Invoke(client.IP, true);
//}
byte[] receivedBuffer = new byte[e.ByteBlock.Len];
Array.Copy(e.ByteBlock.Buffer, 0, receivedBuffer, 0, e.ByteBlock.Len);
var mes = ByteArrayToHexString(receivedBuffer);
_logger.LogInformation($"客户端{client.IP}:{client.Port} " + mes);
DataClassify(BufferDataAnalysis.BufferRootAnalysis(receivedBuffer), client.Id);
return EasyTask.CompletedTask;
@ -168,6 +174,21 @@ namespace SlnMesnac.TouchSocket
}
/// <summary>
/// byte数组转字符串
/// </summary>
/// <param name="byteArray"></param>
/// <returns></returns>
private string ByteArrayToHexString(byte[] byteArray)
{
if (byteArray == null || byteArray.Length == 0)
{
return string.Empty;
}
return string.Join(" ", byteArray.Select(b => b.ToString("X2")));
}
//private void Test()
//{
// try
@ -362,15 +383,20 @@ namespace SlnMesnac.TouchSocket
/// </summary>
public void VisionStateRequest(TcpVisionEntity entity, string id)
{
SendRequestVisionSysState(id);
if(entity.DataLength == 2)
{
}
//Thread.Sleep(1000);
//SendRequestVisionSysState(id);
}
/// <summary>
/// AMR就绪请求视觉开始工作
/// </summary>
public void RequestVisionStartWork(StackState state, int port)
public void RequestVisionStartWork(StackState state, string id)
{
SendAMRRequestVisionStartWork(new byte[1] { (byte)state }, port.ToString());
SendAMRRequestVisionStartWork(new byte[1] { (byte)state }, id);
}
/// <summary>
@ -404,67 +430,71 @@ namespace SlnMesnac.TouchSocket
_logger.LogInformation($"视觉系统收到开始工作状态:{result}");
}
int VCount = 1;
/// <summary>
/// 接受码垛结果
/// </summary>
public void StackResultSend(TcpVisionEntity entity, string id)
{
string result;
if (entity.DataLength == 1)
{
if (entity.DataBytes[0] == 0x00)
{
result = "码垛完成";
_logger.LogInformation($"视觉系统一次码垛结束,码垛完成");
//上位机回复收到码垛结果
SendReplayStackResult(id);
if (true) //这里写是否继续下一次码垛的判断条件
if (VCount < 5) //这里写是否继续下一次码垛的判断条件
{
//如果码垛没结束继续发下一次的码垛信号
if (true) //这里写向哪个机器人码垛的判断条件
{
//发送向搬运机器人AGVDeliver码垛的信号
SendAMRRequestVisionStartWork(new byte[] { 0x10 }, id);
RequestVisionStartWork(StackState.AGVNoPositioning, id);
_logger.LogInformation("下一次码垛开始,方向:搬运机器人");
}
else
{
//发送向复合机器人AMR码垛的信号
SendAMRRequestVisionStartWork(new byte[] { 0x01 }, id);
RequestVisionStartWork(StackState.AMRNoPositioning, id);
_logger.LogInformation("下一次码垛开始,方向:复合机器人");
}
VCount++;
}
else
{
//如果码垛结束就请求复位
SendStackOverRequestVisionSysReplace(id);
RequestVisionReplace(id);
_logger.LogInformation("本次码垛结束,请求复位");
VCount = 1;
}
}
else if (entity.DataBytes[0] == 0x01)
{
result = "码垛过程失败";
_logger.LogInformation($"视觉系统一次码垛结束,码垛过程失败");
}
else if (entity.DataBytes[0] == 0x02)
{
result = "码垛检查失败";
_logger.LogInformation($"视觉系统一次码垛结束,码垛检查失败");
}
else
{
result = "未知返回代码";
_logger.LogInformation($"视觉系统一次码垛结束,未知返回代码");
}
}
else
{
result = "返回数据格式错误";
_logger.LogInformation($"视觉系统一次码垛结束,返回数据格式错误");
}
_logger.LogInformation($"视觉系统一次码垛结束:{result}");
}
/// <summary>
/// 码垛结束,请求视觉系统复位
/// </summary>
public void RequestVisionReplace(int port)
public void RequestVisionReplace(string port)
{
SendStackOverRequestVisionSysReplace(port.ToString());
SendStackOverRequestVisionSysReplace(port);
}
/// <summary>
@ -509,12 +539,12 @@ namespace SlnMesnac.TouchSocket
/// <summary>
/// 搬运机器人码垛无需定位
/// </summary>
RGVNoPositioning = 0x10,
AGVNoPositioning = 0x10,
/// <summary>
/// 搬运机器人码垛需要定位
/// </summary>
RGVNeedPositioning = 0x11,
AGVNeedPositioning = 0x11,
}
}

@ -64,6 +64,10 @@
<StackPanel Grid.Column="0" VerticalAlignment="Center" HorizontalAlignment="Left" Orientation="Horizontal">
<Button Content="首 页" x:Name="Index" Command="{Binding ControlOnClickCommand}" CommandParameter="{Binding Name,ElementName=Index}" Style="{StaticResource BUTTON_AGREE}" Width="100" Height="30" Background="#009999" BorderBrush="#FF36B5C1" Margin="10,0,10,0"/>
<Button Content="代码生成" x:Name="Generate" Command="{Binding FormControlCommand}" CommandParameter="{Binding Name,ElementName=Generate}" Style="{StaticResource BUTTON_AGREE}" Width="100" Height="30" Background="#009999" BorderBrush="#FF36B5C1" Margin="0,0,10,0"/>
<Button Content="发送开始抓取" x:Name="TestButton1" Command="{Binding FormControlCommand}" CommandParameter="{Binding Name,ElementName=TestButton1}" Style="{StaticResource BUTTON_AGREE}" Width="100" Height="30" Background="#009999" BorderBrush="#FF36B5C1" Margin="0,0,10,0" Click="Button_Click_1"/>
<Button Content="发送结束抓取" x:Name="TestButton2" Command="{Binding FormControlCommand}" CommandParameter="{Binding Name,ElementName=TestButton2}" Style="{StaticResource BUTTON_AGREE}" Width="100" Height="30" Background="#009999" BorderBrush="#FF36B5C1" Margin="0,0,10,0" Click="Button_Click_2"/>
<Button Content="调用小车" x:Name="TestButton3" Command="{Binding FormControlCommand}" CommandParameter="{Binding Name,ElementName=TestButton3}" Style="{StaticResource BUTTON_AGREE}" Width="100" Height="30" Background="#009999" BorderBrush="#FF36B5C1" Margin="0,0,10,0" Click="Button_Click_3"/>
<Button Content="入库小车" x:Name="TestButton4" Command="{Binding FormControlCommand}" CommandParameter="{Binding Name,ElementName=TestButton4}" Style="{StaticResource BUTTON_AGREE}" Width="100" Height="30" Background="#009999" BorderBrush="#FF36B5C1" Margin="0,0,10,0" Click="Button_Click_4"/>
<Button Content="键 盘" Command="{Binding OpenSystemKeyboardCommand}" Style="{StaticResource BUTTON_AGREE}" Width="100" Height="30" Background="#009999" BorderBrush="#FF36B5C1" Margin="0,0,10,0"/>
<Button Content="最小化" x:Name="Minimized" Command="{Binding FormControlCommand}" CommandParameter="{Binding Name,ElementName=Minimized}" Style="{StaticResource BUTTON_AGREE}" Width="100" Height="30" Background="#FF9900" BorderBrush="#FF9900" Margin="0,0,10,0"/>
<Button Content="退 出" x:Name="Exit" Command="{Binding FormControlCommand}" CommandParameter="{Binding Name,ElementName=Exit}" Style="{StaticResource BUTTON_AGREE}" Width="100" Height="30" Background="#FF0033" BorderBrush="#FF0033" Margin="0,0,10,0"/>

@ -39,5 +39,30 @@ namespace SlnMesnac.WPF
return;
}
/// <summary>
/// 测试1
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void Button_Click_1(object sender, RoutedEventArgs e)
{
MessageBox.Show("开始定位抓取");
}
private void Button_Click_2(object sender, RoutedEventArgs e)
{
MessageBox.Show("结束定位抓取");
}
private void Button_Click_3(object sender, RoutedEventArgs e)
{
MessageBox.Show("调用小车");
}
private void Button_Click_4(object sender, RoutedEventArgs e)
{
MessageBox.Show("入库小车");
}
}
}

@ -29,4 +29,5 @@ namespace SlnMesnac.WPF.Page.IndexPage
}
}
}

@ -116,46 +116,7 @@ namespace SlnMesnac.WPF.ViewModel.IndexPage
////下发数据测试
//AGVRequestAddTaskEntity aGVRequestAddTaskEntity = new AGVRequestAddTaskEntity()
//{
// businessOrderId = "testtask1009",
// priority = 0,
// RobotType = "S800",
// robotId = "53773a420771497b8b699e949e9eaacb",
// group = "",
// taskSource = "agvctest",
// taskType = 0,
// verifyStatus = 0,
// enableSplitCar = 0,
// load = new List<LoadsEntity>()
// {
// new LoadsEntity()
// {
// jobid = "36e065b08a5245df898ba6ff135768a6",
// location = "8491f5771c824bab80a497cc9af63772",
// param = new List<ParamEntity>()
// {
// new ParamEntity()
// {
// paramname = "p3",
// paramvalue = "8491f5771c824bab80a497cc9af63772",
// }
// },
// robotPort = ""
// }
// },
//};
//try
//{
// _airPorthttpClient.AGVAddTaskRequest(aGVRequestAddTaskEntity);
//}
//catch (Exception ex)
//{
// _logger.LogError($"接口发生错误:{ex.Message}");
//}
//Thread.Sleep(5000);

@ -5,16 +5,19 @@ using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using SlnMesnac.Business.@base;
using SlnMesnac.Config;
using SlnMesnac.Model.AirportApiEntity;
using SlnMesnac.Repository.service;
using SlnMesnac.TouchSocket;
using SlnMesnac.WPF.Page.Generate;
using SlnMesnac.WPF.Page.IndexPage;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows;
namespace SlnMesnac.WPF.ViewModel
{
public class MainWindowViewModel: ViewModelBase
public class MainWindowViewModel : ViewModelBase
{
private readonly ILogger<MainWindowViewModel> _logger;
private readonly ILogger<BaseTaskInfoBusiness> _BaseTaskInfoBusinesslogger;
@ -89,7 +92,7 @@ namespace SlnMesnac.WPF.ViewModel
#endregion
public MainWindowViewModel()
{
{
_appConfig = App.ServiceProvider.GetService<AppConfig>();
_logger = App.ServiceProvider.GetService<ILogger<MainWindowViewModel>>();
_Taskservice = App.ServiceProvider.GetService<IAirportTaskService>();
@ -100,7 +103,7 @@ namespace SlnMesnac.WPF.ViewModel
BaseTaskInfoBusiness.GetInstance(_BaseTaskInfoBusinesslogger, _Taskservice, _AGVStateService, _tcpServer, _airPorthttpClient);
ControlOnClickCommand = new RelayCommand<object>(obj => ControlOnClick(obj));
FormControlCommand = new RelayCommand<object>(x => FormControl(x));
_tcpServer.RefreshStateAction+= (_clientIP, _state) =>
_tcpServer.RefreshStateAction += (_clientIP, _state) =>
{
if (_clientIP == _appConfig.AMRIP)
{
@ -116,6 +119,9 @@ namespace SlnMesnac.WPF.ViewModel
/// <param name="obj"></param>
private void FormControl(object obj)
{
NewAddTaskByAGV newAddTaskByAGV = new NewAddTaskByAGV();
try
{
string controlType = obj as string;
@ -147,6 +153,46 @@ namespace SlnMesnac.WPF.ViewModel
case "Minimized":
Application.Current.MainWindow.WindowState = WindowState.Minimized;
break;
case "TestButton1":
//AMR就绪请求视觉初步开始工作
_tcpServer.RequestVisionStartWork(StackState.AGVNeedPositioning, _tcpServer.Vport.ToString());
break;
case "TestButton2":
//码垛结束,请求视觉系统复位
_tcpServer.RequestVisionReplace(_tcpServer.Vport.ToString());
break;
case "TestButton3":
//调用小车到抓取位置
try
{
_airPorthttpClient.AGVAddTaskRequest(newAddTaskByAGV.NewTaskEntity(
_appConfig.AGVConfig.Where(x => x.AGVName == "S800-B").First().AGVGUID,
_appConfig.JobConfig.Where(x => x.JobName == "800小车进入位置任务pause").First().JobGUID,
_appConfig.PositionConfig.Where(x => x.PointName == "800装货点").First().PointGUID,
_appConfig.PositionConfig.Where(x => x.PointName == "800装货点").First().PointParamName
));
}
catch (Exception ex)
{
_logger.LogError($"接口发生错误:{ex.Message}");
}
break;
case "TestButton4":
//调用小车到库位
try
{
_airPorthttpClient.AGVAddTaskRequest(newAddTaskByAGV.NewTaskEntity(
_appConfig.AGVConfig.Where(x => x.AGVName == "S800-B").First().AGVGUID,
_appConfig.JobConfig.Where(x => x.JobName == "800小车入库任务pause").First().JobGUID,
_appConfig.PositionConfig.Where(x => x.PointName == "800装货点").First().PointGUID,
_appConfig.PositionConfig.Where(x => x.PointName == "800装货点").First().PointParamName
));
}
catch (Exception ex)
{
_logger.LogError($"接口发生错误:{ex.Message}");
}
break;
default:
break;
}

@ -78,9 +78,54 @@
"IsFlag": true
}
],
"AMRIP": "127.0.0.1",
"AGVConfig": [
{
"AGVGUID": "f3358c0cee904204a9d53323171f3d1d",
"AGVName": "S800-A"
},
{
"AGVGUID": "53773a420771497b8b699e949e9eaacb",
"AGVName": "S800-B"
},
{
"AGVGUID": "88db096830b74d1e92a5a3ec20e1da19",
"AGVName": "S1000-A"
},
{
"AGVGUID": "85a8e57c9fdc45a89686f62f03f54489",
"AGVName": "S1000-B"
}
],
"PositionConfig": [
{
"PointGUID": "87f1eb13d6fb48c0b18e87917b40f148",
"PointName": "800装货点",
"PointParamName": "p1"
},
{
"PointGUID": "a902cd2f69b942cba287e70c97f27616",
"PointName": "1000装货点",
"PointParamName": "p1"
},
{
"PointGUID": "87f1eb13d6fb48c0b18e87917b40f148",
"PointName": "卸货点",
"PointParamName": "p1"
}
],
"JobConfig": [
{
"JobGUID": "e5aed3a665ae4900bc6c65e8e04a97fa",
"JobName": "800小车进入位置任务pause"
},
{
"JobGUID": "ccf742e56beb4ed18f2de640fdcc0827",
"JobName": "800小车入库任务pause"
}
],
"AMRIP": "127.0.0.1",
"redisConfig": "175.27.215.92:6379,password=redis@2023",
"AGVIpConfig": "http://192.168.10.199:5102",
"TCPVisionConfig": "127.0.0.1:6000"

Loading…
Cancel
Save