Files
HitBotCSharpDemo/HitBotCSharpDemo/ShowForm.cs

1436 lines
52 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using ControlBeanExDll;
using MvCamCtrl.NET;
using MvCameraControl;
using OfficeOpenXml;
using System;
using System.Collections.Generic;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.Windows.Forms;
using TcpserverExDll;
namespace HitBotCSharpDemo
{
public partial class ShowForm : Form
{
Thread thread_Jog_Move;//创建按钮长按,连续移动模式的线程。 与点击事件冲突处理
bool moveFlag;//开始结束寸动标志
bool isInit = false;
Button btn;//声明按钮对象。
Label lbl;
int offset = 2;//寸动距离
int offset_jog = 2;//连续移动单次距离
static int io_Count = 6;//IO数量
int[] io_In = new int[io_Count];
int[] io_Out = new int[io_Count];
Label[] lbl_Current_Input;//IO显示控件数组
Label[] lbl_Current_Output;
bool output_State_Flag0 = true;
bool output_State_Flag1 = true;
bool output_State_Flag2 = true;
bool output_State_Flag3 = true;
bool output_State_Flag4 = true;
bool output_State_Flag5 = true;
float[] pos0;//点位1
int posHand0;
float[] pos1;//点位2
int posHand1;
float[] pos2;//点位3
int posHand2;
Thread thread_PosMove;
private float[][] cameraPositions;
private string filePath = "Cam_pos_path.txt";
private TcpClient tcpClient;
private NetworkStream networkStream;
private Thread detectionThread;
private bool isDetectionRunning = false;
private const int SERVER_PORT = 8888; // Python服务器端口
private const string SERVER_IP = "127.0.0.1"; // 本机IP
private float receivedWidth = 0;
private float receivedHeight = 0;
private bool isCycleRunning = false;
private Thread cycleThread;
private List<float[]> detectionData = new List<float[]>(); // 存储每轮检测数据
private int currentCycle = 0;
private List<int> selectedPositions = new List<int>(); // 存储选中的点位
private int dwellTimeMinutes = 1; // 停留时间(分钟)
private string cycleStartTime = ""; // 循环开始时间
private CameraManager cameraManager;
private tempControl tempControl;
private ControlBeanEx robot;
public ShowForm()
{
InitializeComponent();
TcpserverEx.net_port_initial();
robot = TcpserverEx.get_robot(74);//替换为自己的机器的id号
SDKSystem.Initialize(); // 初始化SDK
//InitializeCamera(); // 初始化相机
Control.CheckForIllegalCrossThreadCalls = false;
}
protected override void OnFormClosing(FormClosingEventArgs e)
{
// 停止循环检测
if (isCycleRunning)
{
StopCycle();
// 恢复控件状态
SetControlsEnabled(true);
}
// 停止相机
cameraManager?.StopCamera();
StopDetection();
// 终结SDK
SDKSystem.Finalize();
base.OnFormClosing(e);
}
private void LoadCameraPositions()
{
try
{
if (File.Exists(filePath))
{
string[] lines = File.ReadAllLines(filePath);
cameraPositions = new float[5][]; // 存储5个点位
int positionIndex = 0;
foreach (string line in lines)
{
// 跳过注释行(以#开头)和空行
if (string.IsNullOrWhiteSpace(line) || line.StartsWith("#"))
continue;
if (positionIndex < 5)
{
string[] coords = line.Split(',');
if (coords.Length == 4)
{
cameraPositions[positionIndex] = new float[4];
for (int i = 0; i < 4; i++)
{
if (float.TryParse(coords[i].Trim(), out float value))
{
cameraPositions[positionIndex][i] = value;
}
else
{
MessageBox.Show($"解析第{positionIndex + 1}行第{i + 1}个坐标时出错:{coords[i]}");
return;
}
}
positionIndex++;
}
else
{
MessageBox.Show($"第{positionIndex + 1}行坐标格式错误应该包含4个值(X,Y,Z,R)");
return;
}
}
}
//if (positionIndex == 5)
//{
// MessageBox.Show("成功加载5个相机位置点位");
//}
//else
//{
// MessageBox.Show($"只加载了{positionIndex}个点位需要5个点位");
//}
}
else
{
MessageBox.Show($"未找到文件:{filePath}");
}
}
catch (Exception ex)
{
MessageBox.Show($"加载点位文件时出错:{ex.Message}");
}
}
private void MoveToPosition(int positionIndex)
{
if (!isInit)
{
MessageBox.Show("机械臂未初始化");
return;
}
if (cameraPositions == null || positionIndex >= cameraPositions.Length || cameraPositions[positionIndex] == null)
{
MessageBox.Show($"点位{positionIndex + 1}数据未加载或无效");
return;
}
try
{
// 获取当前位置参数
robot.get_scara_param();
int currentHand = robot.get_lr(); // 使用当前手系
float x = cameraPositions[positionIndex][0];
float y = cameraPositions[positionIndex][1];
float z = cameraPositions[positionIndex][2];
float r = cameraPositions[positionIndex][3];
// 设置运动参数
robot.new_set_acc(30, 30, 30, 30);
// 移动到指定位置
int result = robot.new_movej_xyz_lr(x, y, z, r, 100, 0, currentHand);
if (result != 1)
{
MessageBox.Show($"移动到点位{positionIndex + 1}失败,返回值:{result}");
}
}
catch (Exception ex)
{
MessageBox.Show($"移动到点位{positionIndex + 1}时出错:{ex.Message}");
}
}
private void ShowForm_Load(object sender, EventArgs e)
{
lbl_Current_Input = new Label[] { lbl_InputState_0, lbl_InputState_1, lbl_InputState_2, lbl_InputState_3, lbl_InputState_4, lbl_InputState_5 };//输入信号数组
lbl_Current_Output = new Label[] { lbl_OutputState_0, lbl_OutputState_1, lbl_OutputState_2, lbl_OutputState_3, lbl_OutputState_4, lbl_OutputState_5 };//输出信号数组
LoadCameraPositions();
cameraManager = new CameraManager(cam_feed);
cameraManager.LoadConfiguration();
cameraManager.Initialize();
Label[] temperatureLabels = new Label[] { label4, label11, label16, label21 };
Label[] setting_temperatureLabels = new Label[] { label7, label8, label13, label18 };
tempControl = new tempControl(temperatureLabels, setting_temperatureLabels);
tempControl.LoadAvailablePorts(comboBox1);
textBox6.Click += TextBox_Click;
textBox7.Click += TextBox_Click;
textBox8.Click += TextBox_Click;
textBox9.Click += TextBox_Click;
}
private void TextBox_Click(object sender, EventArgs e)
{
TextBox textBox = sender as TextBox;
if (textBox == null) return;
// 检查串口是否打开
if (tempControl == null || !tempControl.IsSerialPortOpen())
{
MessageBox.Show("串口未打开,无法设置参数");
return;
}
// 根据控件名称确定下位机编号和显示名称
int deviceNumber = -1;
string parameterName = "";
switch (textBox.Name)
{
case "textBox6":
deviceNumber = 0;
parameterName = "下位机1 RAMPSPEED";
break;
case "textBox7":
deviceNumber = 1;
parameterName = "下位机2 RAMPSPEED";
break;
case "textBox8":
deviceNumber = 2;
parameterName = "下位机3 RAMPSPEED";
break;
case "textBox9":
deviceNumber = 3;
parameterName = "下位机4 RAMPSPEED";
break;
}
if (deviceNumber >= 0)
{
// 创建并显示输入窗口
ParameterInputForm inputForm = new ParameterInputForm(parameterName, textBox.Text);
if (inputForm.ShowDialog(this) == DialogResult.OK)
{
// 用户点击了保存按钮
string newValue = inputForm.InputValue;
// 检查输入是否为有效数字
if (double.TryParse(newValue, out double inputValue))
{
// 更新textbox显示
textBox.Text = newValue;
// 构建并发送命令
string command = $"TC1:TCRAMPSPEED={inputValue}@{deviceNumber}\r";
tempControl.SendCommand(command);
}
else
{
MessageBox.Show("请输入有效的数字", "输入错误",
MessageBoxButtons.OK, MessageBoxIcon.Warning);
}
}
inputForm.Dispose();
}
}
private void cob_Robot_ID_Click(object sender, EventArgs e)
{
cob_Robot_ID.Items.Clear();
for (int i = 0; i < 255; i++)
{
robot = TcpserverEx.get_robot(i);//替换为自己的机器的id号
if (robot.is_connected())
{
cob_Robot_ID.Items.Add(i.ToString());
}
}
}
private void btn_Init_Click(object sender, EventArgs e)
{
rit_Coord.Clear();
if (robot == null) return;
robot = TcpserverEx.get_robot(int.Parse(cob_Robot_ID.Text));
robot.check_joint(4, false);
if (robot.is_connected())
{
int ret = robot.initial(1, 240); //修改自己机器的型号参数具体意义参考sdk说明文档
if (ret == 1)
{
robot.unlock_position();
isInit = true;
MessageBox.Show("robot" + "初始化完成");
}
else
{
MessageBox.Show("robot" + "初始化失败,返回值 = " + ret.ToString());
}
}
else
{
MessageBox.Show("robot" + "未连接");
}
}
private void btn_Move_Click(object sender, EventArgs e) //点击按钮,寸动事件。
{
if (!isInit)
{
MessageBox.Show("机械臂未初始化");
return;
}
#region
if (chb_Inching.Checked == true)//寸动
{
robot.get_scara_param();
int hand = robot.get_lr();
float speed = 2;
robot.new_set_acc(30, 30, 30, 30);
#region
if (btn == btn_XP)//X正向移动
{
robot.new_movej_xyz_lr(robot.x + offset, robot.y, robot.z, robot.rotation, speed, 0, hand);//以 movej直线模式 的运动方式,并以指定手系达目标点
}
else if (btn == btn_XN)//X负向移动
{
robot.new_movej_xyz_lr(robot.x - offset, robot.y, robot.z, robot.rotation, speed, 0, hand);
}
if (btn == btn_YP)//Y正向移动
{
robot.new_movej_xyz_lr(robot.x, robot.y + offset, robot.z, robot.rotation, speed, 0, hand);//以 movej直线模式 的运动方式,并以指定手系达目标点
}
else if (btn == btn_YN)//Y负向移动
{
robot.new_movej_xyz_lr(robot.x, robot.y - offset, robot.z, robot.rotation, speed, 0, hand);
}
if (btn == btn_ZP)//Z正向移动
{
robot.new_movej_xyz_lr(robot.x, robot.y, robot.z + offset, robot.rotation, speed, 0, hand);//以 movej直线模式 的运动方式,并以指定手系达目标点
}
else if (btn == btn_ZN)//Z负向移动
{
robot.new_movej_xyz_lr(robot.x, robot.y, robot.z - offset, robot.rotation, speed, 0, hand);
}
if (btn == btn_RP)//R正向旋转
{
robot.new_movej_xyz_lr(robot.x, robot.y, robot.z, robot.rotation + offset, speed, 0, hand);//以 movej直线模式 的运动方式,并以指定手系达目标点
}
else if (btn == btn_RN)//R负向旋转
{
robot.new_movej_xyz_lr(robot.x, robot.y, robot.z, robot.rotation - offset, speed, 0, hand);
}
#endregion
}
else
{
}
#endregion
}
public void jog_Move()//连续移动方法
{
moveFlag = true;
while (moveFlag && chb_Inching.Checked == false && btn != null)
{
//robot.new_set_acc(100, 100, 100, 100);
if (btn == btn_XP)//X正向移动
{
robot.jog_move2(offset_jog, 0, 0, 0, 1);
//robot.jog_move2(robot.x - 1, robot.y, robot.z, robot.rotation,1);
//type: 1是以xyz坐标系为准移动固定距离。 2是以关节轴为基准移动固定距离
}
else if (btn == btn_XN)//X负向移动
{
robot.jog_move2(-offset_jog, 0, 0, 0, 1);
}
if (btn == btn_YP)//Y正向移动
{
robot.jog_move2(0, offset_jog, 0, 0, 1);
}
else if (btn == btn_YN)//Y负向移动
{
robot.jog_move2(0, -offset_jog, 0, 0, 1);
}
if (btn == btn_ZP)//Z正向移动
{
robot.jog_move2(0, 0, offset_jog, 0, 1);
}
else if (btn == btn_ZN)//Z负向移动
{
robot.jog_move2(0, 0, -offset_jog, 0, 1);
}
if (btn == btn_RP)//R正向旋转
{
robot.jog_move2(0, 0, 0, offset_jog, 1);
}
else if (btn == btn_RN)//R负向旋转
{
robot.jog_move2(0, 0, 0, offset_jog, 1);
}
Thread.Sleep(200);
}
robot.wait_stop();
}
private void btn_gainJointState_Click(object sender, EventArgs e)//获取关节状态
{
if (!isInit)
{
MessageBox.Show("机械臂未初始化");
return;
}
int jointNumber = int.Parse(cob_Joint_Number.SelectedItem.ToString());
int ret = robot.get_joint_state(jointNumber);
switch (ret)
{
case 1:
rit_showJointState.Clear();
rit_showJointState.SelectedText = "关节" + jointNumber + "正常";
break;
default:
rit_showJointState.Clear();
rit_showJointState.SelectedText = "关节" + jointNumber + "异常!异常代码:" + ret + ".详情请查看API文档"; //可具体
break;
}
}
private void btn_Jog_MouseDown(object sender, MouseEventArgs e)
{
btn = (Button)sender;
if (btn == null)
{
return;
}
thread_Jog_Move = new Thread(jog_Move);
thread_Jog_Move.IsBackground = true;
thread_Jog_Move.Start();
}
private void tim_IO_Refresh_Tick(object sender, EventArgs e)//刷新IO和坐标定时器
{
robot.get_scara_param();
if (isInit)
{
rit_Coord.Text = "Coord: X:" + robot.x + "mm " + "Y:" + robot.y + "mm " + "Z:" + robot.z + "mm " + "R:" + robot.rotation + "°" + "Hand:" + (robot.get_lr() == 1 ? "R" : "L") + " ";
}
for (int i = 0; i < io_Count; i++)
{
io_In[i] = robot.get_digital_in(i);
io_Out[i] = robot.get_digital_out(i);
}
for (int i = 0; i < io_Count; i++)//输入
{
int ret_Input = io_In[i];
Label lbl_Current_IO = lbl_Current_Input[i];
switch (ret_Input)//• -1io_number 参数错误 • 0io 输入点没有被触发 • 1io 输入点被触发 • 3未初始化
{
case -1:
if (lbl_Current_Input[i].BackColor != Color.Gray)
lbl_Current_Input[i].BackColor = Color.Gray;
break;
case 0:
if (lbl_Current_Input[i].BackColor != Color.Green)
lbl_Current_Input[i].BackColor = Color.Green;
break;
case 1:
if (lbl_Current_Input[i].BackColor != Color.Red)
lbl_Current_Input[i].BackColor = Color.Red;
break;
case 3:
if (lbl_Current_Input[i].BackColor != Color.Gray)
lbl_Current_Input[i].BackColor = Color.Gray;
break;
}
}
for (int i = 0; i < io_Count; i++)//输出
{
int ret_Output = io_Out[i];
Label lbl_Current_IO = lbl_Current_Output[i];
switch (ret_Output)//• -1io_number 参数错误 • 0io 输入点没有被触发 • 1io 输入点被触发 • 3未初始化
{
case -1:
if (lbl_Current_Output[i].BackColor != Color.Gray)
lbl_Current_Output[i].BackColor = Color.Gray;
break;
case 0:
if (lbl_Current_Output[i].BackColor != Color.Green)
lbl_Current_Output[i].BackColor = Color.Green;
break;
case 1:
if (lbl_Current_Output[i].BackColor != Color.Red)
lbl_Current_Output[i].BackColor = Color.Red;
break;
case 3:
if (lbl_Current_Output[i].BackColor != Color.Gray)
lbl_Current_Output[i].BackColor = Color.Gray;
break;
}
}
}
private void lbl_Output_Click(object sender, EventArgs e)//设置输出事件
{
#region
int output_Num = 0;
lbl = (Label)sender;
if (lbl == lbl_OutputState_0)
{
output_Num = 0;
robot.set_digital_out(output_Num, output_State_Flag0);
output_State_Flag0 = !output_State_Flag0;
}
else if (lbl == lbl_OutputState_1)
{
output_Num = 1;
robot.set_digital_out(output_Num, output_State_Flag1);
output_State_Flag1 = !output_State_Flag1;
}
else if (lbl == lbl_OutputState_2)
{
output_Num = 2;
robot.set_digital_out(output_Num, output_State_Flag2);
output_State_Flag2 = !output_State_Flag2;
}
else if (lbl == lbl_OutputState_3)
{
output_Num = 3;
robot.set_digital_out(output_Num, output_State_Flag3);
output_State_Flag3 = !output_State_Flag3;
}
else if (lbl == lbl_OutputState_4)
{
output_Num = 4;
robot.set_digital_out(output_Num, output_State_Flag4);
output_State_Flag4 = !output_State_Flag4;
}
else if (lbl == lbl_OutputState_5)
{
output_Num = 5;
robot.set_digital_out(output_Num, output_State_Flag5);
output_State_Flag5 = !output_State_Flag5;
}
#endregion
}
private void btn_MouseUp(object sender, MouseEventArgs e)//停止连续移动
{
if (robot != null&&!chb_Inching.Checked)
{
robot.new_stop_move();
}
btn = null;
moveFlag = false;
}
private void btn_Position0_Click(object sender, EventArgs e)
{
if (!isInit)
{
MessageBox.Show("机械臂未初始化");
return;
}
rit_Position0.Clear();
rit_Position0.Text = "Coord: X:" + robot.x + "mm " + "Y:" + robot.y + "mm " + "Z:" + robot.z + "mm " + "R:" + robot.rotation + "°" + "Hand:" + (robot.get_lr() == 1 ? "R" : "L") + " ";
pos0 = new float[] { robot.x, robot.y, robot.z, robot.rotation };
posHand0 = robot.get_lr()/* == 1 ? "R" : "L"*/;
}
private void btn_Position1_Click(object sender, EventArgs e)
{
if (!isInit)
{
MessageBox.Show("机械臂未初始化");
return;
}
rit_Position1.Clear();
rit_Position1.Text = "Coord: X:" + robot.x + "mm " + "Y:" + robot.y + "mm " + "Z:" + robot.z + "mm " + "R:" + robot.rotation + "°" + "Hand:" + (robot.get_lr() == 1 ? "R" : "L") + " ";
pos1 = new float[] { robot.x, robot.y, robot.z, robot.rotation };
posHand1 = robot.get_lr()/* == 1 ? "R" : "L"*/;
}
private void btn_Position2_Click(object sender, EventArgs e)
{
if (!isInit)
{
MessageBox.Show("机械臂未初始化");
return;
}
rit_Position2.Clear();
rit_Position2.Text = "Coord: X:" + robot.x + "mm " + "Y:" + robot.y + "mm " + "Z:" + robot.z + "mm " + "R:" + robot.rotation + "°" + "Hand:" + (robot.get_lr() == 1 ? "R" : "L") + " ";
pos2 = new float[] { robot.x, robot.y, robot.z, robot.rotation };
posHand2 = robot.get_lr() /*== 1 ? "R" : "L"*/;
}
private void btn_Start_Click(object sender, EventArgs e)
{
btn_Pause.Enabled = true;
btn_Resume.Enabled = true;
if (pos0==null|| pos1 == null|| pos2 == null)
{
MessageBox.Show("请先设置3个点位");
return;
}
thread_PosMove = new Thread(PosMove);
thread_PosMove.IsBackground = false;
thread_PosMove.Start();
}
private static object locker_PosMove = new object();
public void PosMove()
{
lock (locker_PosMove)
{
while (true)
{
robot.resume_move();
robot.get_scara_param();
robot.new_movej_xyz_lr(pos0[0], pos0[1], pos0[2], pos0[3], 50, 0, posHand0);
robot.wait_stop();
robot.new_movej_xyz_lr(pos1[0], pos1[1], pos1[2], pos1[3], 50, 0, posHand1);
robot.wait_stop();
robot.new_movej_xyz_lr(pos2[0], pos2[1], pos2[2], pos2[3], 50, 0, posHand2);
robot.wait_stop();
}
}
}
private void btn_Pause_Click(object sender, EventArgs e)
{
btn_Stop.Enabled = false;
robot.pause_move();
}
private void btn_Resume_Click(object sender, EventArgs e)
{
btn_Stop.Enabled = true;
robot.resume_move();
}
private void btn_Stop_Click(object sender, EventArgs e)
{
btn_Pause.Enabled = false;
btn_Resume.Enabled = false;
robot.new_stop_move();
thread_PosMove.Abort();
}
private void btn_Joint_Click(object sender, EventArgs e)
{
if (!isInit)
{
MessageBox.Show("机械臂未初始化");
return;
}
#region
btn = (Button)sender;
if (btn == null)
{
return;
}
if (btn == btn_joint1)
{
robot.joint_home(1);//使轴回到零位
}
else if (btn == btn_joint2)
{
robot.joint_home(2);
}
else if (btn == btn_joint3)
{
robot.joint_home(3);
}
else if (btn == btn_joint4)
{
robot.joint_home(4);
}
#endregion
}
private void rit_Coord_TextChanged(object sender, EventArgs e)
{
}
private void cob_Robot_ID_SelectedIndexChanged(object sender, EventArgs e)
{
}
private void tap_Move_Click(object sender, EventArgs e)
{
}
private void button1_Click(object sender, EventArgs e)
{
MoveToPosition(0);
}
private void button3_Click(object sender, EventArgs e)
{
MoveToPosition(2);
}
private void button2_Click(object sender, EventArgs e)
{
MoveToPosition(1);
}
private void button4_Click(object sender, EventArgs e)
{
MoveToPosition(3);
}
private void init_pos_btn_Click(object sender, EventArgs e)
{
MoveToPosition(4);
}
private void button2_Click_1(object sender, EventArgs e)
{
}
private void button1_Click_1(object sender, EventArgs e)
{
cameraManager.TakePhoto();
}
private void cam_feed_Click(object sender, EventArgs e)
{
cameraManager.ShowParameterDialog();
}
private void button1_Click_2(object sender, EventArgs e)
{
if (!isDetectionRunning)
{
// 连接到Python服务器
if (ConnectToServer())
{
isDetectionRunning = true;
detectionThread = new Thread(DetectionProcess);
detectionThread.IsBackground = true;
detectionThread.Start();
((Button)sender).Text = "停止检测";
MessageBox.Show("目标检测已开始");
}
else
{
MessageBox.Show("连接服务器失败");
}
}
else
{
// 停止检测
StopDetection();
((Button)sender).Text = "开始检测";
MessageBox.Show("目标检测已停止");
}
}
private void pictureBox1_Click(object sender, EventArgs e)
{
if (pictureBox1.Image != null)
{
// 创建一个新窗口显示大图
Form imageForm = new Form();
imageForm.Text = "检测结果";
imageForm.StartPosition = FormStartPosition.CenterParent;
imageForm.Size = new Size(800, 600);
PictureBox largePictureBox = new PictureBox();
largePictureBox.Dock = DockStyle.Fill;
largePictureBox.SizeMode = PictureBoxSizeMode.Zoom;
largePictureBox.Image = new Bitmap(pictureBox1.Image);
imageForm.Controls.Add(largePictureBox);
imageForm.ShowDialog(this);
largePictureBox.Image.Dispose();
}
}
private bool ConnectToServer()
{
try
{
tcpClient = new TcpClient();
tcpClient.Connect(SERVER_IP, SERVER_PORT);
networkStream = tcpClient.GetStream();
return true;
}
catch (Exception ex)
{
MessageBox.Show("连接服务器失败: " + ex.Message);
return false;
}
}
// 检测处理线程
private void DetectionProcess()
{
while (isDetectionRunning)
{
try
{
// 保存当前图像
string imagePath = cameraManager.SaveCurrentImageForDetection();
if (!string.IsNullOrEmpty(imagePath))
{
// 发送图像到Python服务器
SendImageToServer(imagePath);
// 接收处理后的图像
string receivedImagePath = ReceiveImageFromServer();
if (!string.IsNullOrEmpty(receivedImagePath))
{
// 在UI线程中显示图像
this.Invoke(new Action(() => DisplayDetectionResult(receivedImagePath)));
}
}
// 等待1分钟
Thread.Sleep(60000);
//File.Delete(imagePath);
}
catch (Exception ex)
{
this.Invoke(new Action(() => MessageBox.Show("检测过程出错: " + ex.Message)));
break;
}
}
}
// 发送图像到服务器
private void SendImageToServer(string imagePath)
{
try
{
byte[] imageData = File.ReadAllBytes(imagePath);
byte[] imageSize = new byte[4];
imageSize[0] = (byte)((imageData.Length >> 24) & 0xFF);
imageSize[1] = (byte)((imageData.Length >> 16) & 0xFF);
imageSize[2] = (byte)((imageData.Length >> 8) & 0xFF);
imageSize[3] = (byte)(imageData.Length & 0xFF);
// 先发送图像大小
networkStream.Write(imageSize, 0, 4);
// 再发送图像数据
networkStream.Write(imageData, 0, imageData.Length);
networkStream.Flush();
//MessageBox.Show($"发送图像成功,大小: {imageData.Length} 字节");
}
catch (Exception ex)
{
throw new Exception("发送图像失败: " + ex.Message);
}
}
// 从服务器接收处理后的图像
private string ReceiveImageFromServer()
{
try
{
// 接收图像大小
byte[] sizeBuffer = new byte[4];
int bytesRead = ReceiveExactly(sizeBuffer, 4);
if (bytesRead != 4) throw new Exception("接收图像大小失败");
int imageSize = (sizeBuffer[0] << 24) | (sizeBuffer[1] << 16) |
(sizeBuffer[2] << 8) | sizeBuffer[3];
//MessageBox.Show($"准备接收处理结果图像,大小: {imageSize} 字节");
// 接收width
byte[] widthBuffer = new byte[4];
bytesRead = ReceiveExactly(widthBuffer, 4);
if (bytesRead != 4) throw new Exception("接收width失败");
// 将字节数组转换为浮点数(大端序)
if (BitConverter.IsLittleEndian)
Array.Reverse(widthBuffer);
receivedWidth = BitConverter.ToSingle(widthBuffer, 0);
// 接收height
byte[] heightBuffer = new byte[4];
bytesRead = ReceiveExactly(heightBuffer, 4);
if (bytesRead != 4) throw new Exception("接收height失败");
// 将字节数组转换为浮点数(大端序)
if (BitConverter.IsLittleEndian)
Array.Reverse(heightBuffer);
receivedHeight = BitConverter.ToSingle(heightBuffer, 0);
//MessageBox.Show($"width:{receivedWidth}, height:{receivedHeight}");
// 接收图像数据
byte[] imageBuffer = new byte[imageSize];
bytesRead = ReceiveExactly(imageBuffer, imageSize);
if (bytesRead != imageSize) throw new Exception("接收图像数据不完整");
// 保存接收到的图像
string receivedImagePath = Path.Combine(Application.StartupPath,
"received_detection_" + DateTime.Now.ToString("yyyyMMddHHmmss") + ".jpg");
File.WriteAllBytes(receivedImagePath, imageBuffer);
return receivedImagePath;
}
catch (Exception ex)
{
throw new Exception("接收图像失败: " + ex.Message);
}
}
// 辅助方法:确保接收指定字节数的数据
private int ReceiveExactly(byte[] buffer, int size)
{
int totalBytesRead = 0;
while (totalBytesRead < size)
{
int bytesRead = networkStream.Read(buffer, totalBytesRead, size - totalBytesRead);
if (bytesRead == 0)
throw new Exception("连接断开");
totalBytesRead += bytesRead;
}
return totalBytesRead;
}
// 在pictureBox1中显示检测结果
private void DisplayDetectionResult(string imagePath)
{
try
{
if (File.Exists(imagePath))
{
// 如果pictureBox1之前有图像先释放资源
if (pictureBox1.Image != null)
{
pictureBox1.Image.Dispose();
}
// 加载并显示新图像
using (var fs = new FileStream(imagePath, FileMode.Open, FileAccess.Read))
{
pictureBox1.Image = Image.FromStream(fs);
}
pictureBox1.SizeMode = PictureBoxSizeMode.Zoom;
}
}
catch (Exception ex)
{
MessageBox.Show("显示检测结果失败: " + ex.Message);
}
}
// 停止检测
private void StopDetection()
{
isDetectionRunning = false;
if (detectionThread != null && detectionThread.IsAlive)
{
detectionThread.Join(2000); // 等待2秒
}
// 关闭网络连接
try
{
networkStream?.Close();
tcpClient?.Close();
}
catch { }
networkStream = null;
tcpClient = null;
}
private void tap_Axis_Click(object sender, EventArgs e)
{
}
private void tap_Cam_Click(object sender, EventArgs e)
{
}
private void button2_Click_2(object sender, EventArgs e)
{
if (!isCycleRunning)
{
// 检查是否选择了点位
UpdateSelectedPositions();
if (selectedPositions.Count == 0)
{
MessageBox.Show("请至少选择一个点位进行检测");
return;
}
// 开始循环
if (!isInit)
{
MessageBox.Show("机械臂未初始化");
return;
}
if (cameraPositions == null || cameraPositions.Length < 5)
{
MessageBox.Show("点位数据未正确加载");
return;
}
// 连接到检测服务器
if (!ConnectToServer())
{
MessageBox.Show("连接检测服务器失败");
return;
}
// 记录循环开始时间
cycleStartTime = DateTime.Now.ToString("yyyyMMdd_HHmmss");
SetControlsEnabled(false);
isCycleRunning = true;
currentCycle = 0;
detectionData.Clear();
cycleThread = new Thread(CycleProcess);
cycleThread.IsBackground = true;
cycleThread.Start();
((Button)sender).Text = "停止循环";
MessageBox.Show($"循环检测已开始,选中点位:{string.Join(",", selectedPositions.Select(p => (p + 1).ToString()))},停留时间:{dwellTimeMinutes}分钟");
}
else
{
// 停止循环
StopCycle();
SetControlsEnabled(true);
((Button)sender).Text = "开始循环";
MessageBox.Show("循环检测已停止");
}
}
private void SetControlsEnabled(bool enabled)
{
// 在UI线程中执行控件状态修改
if (this.InvokeRequired)
{
this.Invoke(new Action<bool>(SetControlsEnabled), enabled);
return;
}
// 禁用/启用复选框
checkBox1.Enabled = enabled;
checkBox2.Enabled = enabled;
checkBox3.Enabled = enabled;
checkBox4.Enabled = enabled;
// 禁用/启用停留时间文本框
textBox1.Enabled = enabled;
}
// 修改后的循环处理方法
private void CycleProcess()
{
try
{
while (isCycleRunning)
{
// 创建一个字典来存储本轮循环的检测结果
Dictionary<int, float[]> cycleResults = new Dictionary<int, float[]>();
// 按照选中的点位顺序移动
foreach (int positionIndex in selectedPositions)
{
if (!isCycleRunning) break;
// 移动到指定点位
this.Invoke(new Action(() => {
MoveToPosition(positionIndex);
}));
// 等待移动完成并稳定3秒
WaitForRobotStopAndDelay(3000);
if (!isCycleRunning)
{
WaitForRobotStop();
break;
}
// 拍照并进行检测
string detectionResult = CaptureAndDetect(positionIndex);
if (!string.IsNullOrEmpty(detectionResult))
{
// 在UI线程中显示检测结果
this.Invoke(new Action(() => DisplayDetectionResult(detectionResult)));
// 存储检测到的width和height数据
cycleResults[positionIndex] = new float[] { receivedWidth, receivedHeight };
}
else
{
// 如果检测失败存储0值
cycleResults[positionIndex] = new float[] { 0f, 0f };
}
// 在当前点位停留剩余时间(总时间 - 稳定时间3秒
if (isCycleRunning)
{
int remainingTimeMs = (dwellTimeMinutes * 60 - 3) * 1000;
if (remainingTimeMs > 0)
{
// 分解为多个小的睡眠每100ms检查一次停止标志
int sleptTime = 0;
while (sleptTime < remainingTimeMs && isCycleRunning)
{
int sleepDuration = Math.Min(100, remainingTimeMs - sleptTime);
Thread.Sleep(sleepDuration);
sleptTime += sleepDuration;
}
}
}
}
// 保存本轮循环的数据
if (isCycleRunning && cycleResults.Count > 0)
{
currentCycle++;
// 更新Excel文件
this.Invoke(new Action(() => UpdateExcelFileWithSelectedPositions(cycleResults)));
}
}
}
catch (Exception ex)
{
this.Invoke(new Action(() => MessageBox.Show("循环过程出错: " + ex.Message)));
}
finally
{
// 移动到归位点位第5个点位
if (isInit)
{
WaitForRobotStop();
this.Invoke(new Action(() => {
MoveToPosition(4); // 第5个点位索引4
}));
// 确保在循环结束时恢复控件状态
this.Invoke(new Action(() => {
if (isCycleRunning == false) // 只有在正常结束时才恢复
{
SetControlsEnabled(true);
}
}));
}
}
}
// Excel文件更新方法
private void UpdateExcelFileWithSelectedPositions(Dictionary<int, float[]> cycleResults)
{
try
{
ExcelPackage.LicenseContext = LicenseContext.NonCommercial;
// 根据开始时间和选中点位创建文件名
string selectedPosStr = string.Join("_", selectedPositions.Select(p => (p + 1).ToString()));
string fileName = $"DetectionResults_Pos{selectedPosStr}_{cycleStartTime}.xlsx";
string filePath = Path.Combine(Application.StartupPath, fileName);
FileInfo file = new FileInfo(filePath);
using (ExcelPackage package = new ExcelPackage(file))
{
ExcelWorksheet worksheet;
if (package.Workbook.Worksheets.Count == 0)
{
// 创建新的工作表
worksheet = package.Workbook.Worksheets.Add("检测结果");
// 设置表头
worksheet.Cells[1, 1].Value = "循环次数";
worksheet.Cells[1, 2].Value = "检测时间";
int headerCol = 3;
foreach (int pos in selectedPositions)
{
worksheet.Cells[1, headerCol].Value = $"pos{pos + 1}_width";
worksheet.Cells[1, headerCol + 1].Value = $"pos{pos + 1}_height";
headerCol += 2;
}
}
else
{
worksheet = package.Workbook.Worksheets[0];
}
// 添加数据行
int row = worksheet.Dimension?.Rows + 1 ?? 2;
worksheet.Cells[row, 1].Value = currentCycle;
worksheet.Cells[row, 2].Value = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
int dataCol = 3;
foreach (int pos in selectedPositions)
{
if (cycleResults.ContainsKey(pos))
{
worksheet.Cells[row, dataCol].Value = cycleResults[pos][0]; // width
worksheet.Cells[row, dataCol + 1].Value = cycleResults[pos][1]; // height
}
else
{
worksheet.Cells[row, dataCol].Value = 0; // width
worksheet.Cells[row, dataCol + 1].Value = 0; // height
}
dataCol += 2;
}
package.Save();
}
}
catch (Exception ex)
{
MessageBox.Show("更新Excel文件失败: " + ex.Message);
}
}
private void WaitForRobotStop()
{
if (!isInit) return;
while (true)
{
robot.get_scara_param();
if (!robot.move_flag) // 机械臂处于静止状态
{
break;
}
Thread.Sleep(100); // 每100ms检查一次
}
}
private void WaitForRobotStopAndDelay(int additionalDelayMs)
{
// 先等待机械臂停止运动
WaitForRobotStop();
// 然后额外等待指定时间
if (isCycleRunning)
{
Thread.Sleep(additionalDelayMs);
}
}
private string CaptureAndDetect(int positionIndex)
{
try
{
// 重置检测结果
receivedWidth = 0;
receivedHeight = 0;
// 保存当前图像到对应文件夹
string imagePath = SaveImageToPositionFolder(positionIndex);
if (string.IsNullOrEmpty(imagePath))
{
return null;
}
// 发送图像到服务器进行检测
SendImageToServer(imagePath);
// 接收处理后的图像
string receivedImagePath = ReceiveImageFromServer();
// 将检测结果图像保存到对应文件夹
if (!string.IsNullOrEmpty(receivedImagePath))
{
string targetFolder = Path.Combine(Application.StartupPath, $"Position{positionIndex + 1}_Results_{cycleStartTime}");
if (!Directory.Exists(targetFolder))
{
Directory.CreateDirectory(targetFolder);
}
string finalPath = Path.Combine(targetFolder,
$"Detection_Pos{positionIndex + 1}_Cycle{currentCycle}_{DateTime.Now:yyyyMMddHHmmss}.jpg");
File.Copy(receivedImagePath, finalPath, true);
return finalPath;
}
return receivedImagePath;
}
catch (Exception ex)
{
this.Invoke(new Action(() => MessageBox.Show($"点位{positionIndex + 1}检测失败: " + ex.Message)));
return null;
}
}
private string SaveImageToPositionFolder(int positionIndex)
{
return cameraManager.SaveImageToPositionFolder(positionIndex, currentCycle, cycleStartTime);
}
private void StopCycle()
{
isCycleRunning = false;
if (cycleThread != null && cycleThread.IsAlive)
{
cycleThread.Join(5000); // 等待5秒
}
// 关闭网络连接
StopDetection();
}
private void checkBox1_CheckedChanged_1(object sender, EventArgs e)
{
UpdateSelectedPositions();
}
private void checkBox2_CheckedChanged(object sender, EventArgs e)
{
UpdateSelectedPositions();
}
private void checkBox3_CheckedChanged(object sender, EventArgs e)
{
UpdateSelectedPositions();
}
private void checkBox4_CheckedChanged(object sender, EventArgs e)
{
UpdateSelectedPositions();
}
private void textBox1_TextChanged(object sender, EventArgs e)
{
// 更新停留时间
if (int.TryParse(textBox1.Text, out int minutes) && minutes > 0)
{
dwellTimeMinutes = minutes;
}
else if (!string.IsNullOrEmpty(textBox1.Text))
{
MessageBox.Show("请输入有效的停留时间(分钟数)");
textBox1.Text = dwellTimeMinutes.ToString();
}
}
private void UpdateSelectedPositions()
{
selectedPositions.Clear();
if (checkBox1.Checked) selectedPositions.Add(0); // 点位1
if (checkBox2.Checked) selectedPositions.Add(1); // 点位2
if (checkBox3.Checked) selectedPositions.Add(2); // 点位3
if (checkBox4.Checked) selectedPositions.Add(3); // 点位4
}
private void button3_Click_1(object sender, EventArgs e)
{
tempControl.ToggleSerialPort(button3, comboBox1);
}
private void tabPage1_Click(object sender, EventArgs e)
{
}
private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
{
tempControl.OnComboBoxSelectedIndexChanged(comboBox1, button3);
}
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
tempControl.OnFormClosing();
}
private void groupBox1_Enter(object sender, EventArgs e)
{
}
private void label6_Click(object sender, EventArgs e)
{
}
private void textBox2_TextChanged(object sender, EventArgs e)
{
}
private void groupBox1_Enter_1(object sender, EventArgs e)
{
}
private void label4_Click(object sender, EventArgs e)
{
}
private void button4_Click_1(object sender, EventArgs e)
{
}
private void button7_Click(object sender, EventArgs e)
{
}
private void button9_Click(object sender, EventArgs e)
{
}
private void button11_Click(object sender, EventArgs e)
{
}
private void label26_Click(object sender, EventArgs e)
{
}
}
}