这里我们只讲FTP文件上传和异步通讯的使用,其他的都是C#的操作。PMAC所有的功能都可以通过终端就行操作,就像上一节演示的小案例,和IDE的终端是一样的,可以对PMAC进行任何的操作,变量的增删改查,参数的查看和修改,添加运动程序、plc程序到缓存,执行程序等。
主窗口的代码就是昨天演示里的,只是在登陆后显示了一下连接状态。
deviceProperties currentDevProp = new deviceProperties();//通讯属性类
ISyncGpasciiCommunicationInterface communication = null;//异步通讯接口
String commands = String.Empty;//指令发送内容
String response = String.Empty;//指令接受内容
private string connectedToFormat = "连接成功!";
private string notConnected = "连接失败";
private void LoginStatus()
{
if (this.communication == null)
{
this.toolStripStatusLabel3.Text = this.invalidLicense;//授权无效
return;
}
var devicePage = new DevicePropertyPage(this.currentDevProp, this.communication.GpAsciiConnected);
devicePage.OnConnect += this.devicePage_OnConnect;//连接失败
devicePage.OnDisConnect += this.devicePage_OnDisConnect;//连接成功
devicePage.ShowDialog();
}
#endregion
#region 连接失败
private bool devicePage_OnDisConnect()
{
if (this.communication == null)
{
this.toolStripStatusLabel3.Text = this.invalidLicense;
return false;
}
var bSuccess = false;
if (this.communication.GpAsciiConnected)
{
bSuccess = this.communication.DisconnectGpascii();
this.toolStripStatusLabel3.Text = this.notConnected;
}
return bSuccess;
}
#endregion
#region 连接成功
private bool devicePage_OnConnect(deviceProperties properties)
{
if (this.communication == null)
{
this.toolStripStatusLabel3.Text = this.invalidLicense;
return false;
}
this.communication = Connect.CreateSyncGpascii(properties.Protocol, this.communication);
var bSuccess = this.communication.ConnectGpAscii(properties.IPAddress, properties.PortNumber, properties.User, properties.Password);
if (bSuccess)
{
this.currentDevProp.IPAddress = properties.IPAddress;
this.currentDevProp.Password = properties.Password;
this.currentDevProp.PortNumber = properties.PortNumber;
this.currentDevProp.User = properties.User;
this.toolStripStatusLabel3.Text = this.connectedToFormat + properties.IPAddress;
}
return bSuccess;
}
#endregion
前面介绍了如何使用异步通讯及终端的使用,下一步是利用终端实现一些功能。
/// /运动控制界面属性//
private ControlForm myChildFrmControl = null; //定义子窗口对象
private void 运动控制ToolStripMenuItem_Click(object sender, EventArgs e)
{
if (myChildFrmControl != null)
{
if (myChildFrmControl.IsDisposed)
myChildFrmControl = new ControlForm(communication);//如果已经销毁,则重新创建子窗口对象
myChildFrmControl.Show();
myChildFrmControl.Focus();
}
else
{
myChildFrmControl = new ControlForm(communication);
myChildFrmControl.Show();
myChildFrmControl.Focus();
}
}
我们要把异步通讯的接口从主窗口传到子窗口下去/
新建一个通讯接口,用来接收主窗口传过来的
ISyncGpasciiCommunicationInterface Communication = null;//新建一个通讯接口,用来接收主窗口传过来的
public ControlForm(ISyncGpasciiCommunicationInterface communication)
{
InitializeComponent();
Communication = communication;
String response = String.Empty;
}
编写一个对终端操作的通用方法
//对终端操作的通用方法/
private bool ReadWritePmacVariables(string command)
{
var commads = new List<string>();
List<string> response;
commads.Add(command.ToString());
var communicationStatus = this.Communication.GetResponse(commads, out response, 3);
if (communicationStatus == Status.Ok)
{
responses = string.Join("", response.ToArray());
command = null;
return Decide = true;
}
else
{
return Decide = false;
}
}
案例中出现的PMAC类的方法在手册上都有介绍,这里不详细讲解。
使用终端操作PMAC
#region 电机上电
private void button5_Click(object sender, EventArgs e)
{
ReadWritePmacVariables("#1..4j/");
if (Decide == true)
{
toolStripStatusLabel1.Text = "电机已上电!";
}
else
{
toolStripStatusLabel1.Text = "上电失败!";
}
}
#endregion
private void button6_Click(object sender, EventArgs e)
{
ReadWritePmacVariables("#1..4k");
if (Decide == true)
{
toolStripStatusLabel1.Text = "电机已下电!";
}
else
{
toolStripStatusLabel1.Text = "下电失败!";
}
}
#endregion
点动正反向
#region Jog正方向移动
private void button1_MouseDown(object sender, MouseEventArgs e)
{
if (comboBox1.Text == "X" || comboBox1.Text == "Y" || comboBox1.Text == "Z" || comboBox1.Text == "A")
{
if (comboBox1.Text == "X")//x正方向
{
ReadWritePmacVariables("Motor[1].AmpEna");
System.Threading.Thread.Sleep(100);
int CheckPowerOn1 = int.Parse(responses);
if (CheckPowerOn1 == 1)
{
ReadWritePmacVariables("#1jog+");
if (Decide == true)
{
toolStripStatusLabel1.Text = "X轴正方向";
}
else
{
toolStripStatusLabel1.Text = "移动失败!";
}
}
else
{
toolStripStatusLabel1.Text = "请上电";
}
}
if (comboBox1.Text == "Y")//y正方向
{
ReadWritePmacVariables("Motor[2].AmpEna");
System.Threading.Thread.Sleep(100);
int CheckPowerOn2 = int.Parse(responses);
if (CheckPowerOn2 == 1)
{
ReadWritePmacVariables("#2jog+");
if (Decide == true)
{
toolStripStatusLabel1.Text = "Y轴正方向";
}
else
{
toolStripStatusLabel1.Text = "移动失败!";
}
}
else
{
toolStripStatusLabel1.Text = "请上电";
}
}
if (comboBox1.Text == "Z")//z正方向
{
ReadWritePmacVariables("Motor[3].AmpEna");
System.Threading.Thread.Sleep(100);
int CheckPowerOn3 = int.Parse(responses);
if (CheckPowerOn3 == 1)
{
ReadWritePmacVariables("#3jog+");
if (Decide == true)
{
toolStripStatusLabel1.Text = "Z轴正方向";
}
else
{
toolStripStatusLabel1.Text = "移动失败!";
}
}
else
{
toolStripStatusLabel1.Text = "请上电";
}
}
if (comboBox1.Text == "A")//a正方向
{
ReadWritePmacVariables("Motor[4].AmpEna");
System.Threading.Thread.Sleep(100);
int CheckPowerOn4 = int.Parse(responses);
if (CheckPowerOn4 == 1)
{
ReadWritePmacVariables("#4jog+");
if (Decide == true)
{
toolStripStatusLabel1.Text = "A轴正方向";
}
else
{
toolStripStatusLabel1.Text = "移动失败!";
}
}
else
{
toolStripStatusLabel1.Text = "请上电";
}
}
}
else
{
toolStripStatusLabel1.Text = "移动前请先选择电机";
}
}
#endregion
点动停止
#region Jog正方向移动停止
private void button1_MouseUp(object sender, MouseEventArgs e)
{
if (comboBox1.Text == "X" || comboBox1.Text == "Y" || comboBox1.Text == "Z" || comboBox1.Text == "A")
{
ReadWritePmacVariables("Motor[1].AmpEna");
System.Threading.Thread.Sleep(10);
int CheckPowerOn1 = int.Parse(responses);
ReadWritePmacVariables("Motor[2].AmpEna");
System.Threading.Thread.Sleep(10);
int CheckPowerOn2 = int.Parse(responses);
ReadWritePmacVariables("Motor[3].AmpEna");
System.Threading.Thread.Sleep(10);
int CheckPowerOn3 = int.Parse(responses);
ReadWritePmacVariables("Motor[4].AmpEna");
System.Threading.Thread.Sleep(10);
int CheckPowerOn4 = int.Parse(responses);
if (CheckPowerOn1 == 1 || CheckPowerOn2 == 1 || CheckPowerOn3 == 1 || CheckPowerOn4 == 1)
{
ReadWritePmacVariables("#1..4jog/");
if (Decide == true)
{
toolStripStatusLabel1.Text = "电机停止移动";
}
else
{
toolStripStatusLabel1.Text = "停止失败!";
}
}
}
}
#endregion
位置状态显示,一次性全查出来,拆分显示就可以了。
#region 位置状态显示
private void timer1_Tick(object sender, EventArgs e)
{
ReadWritePmacVariables("Motor[1].JogSpeed,4");
string JogSpeed0 = responses;
string[] JogSpeed = JogSpeed0.Split(',');
textBox5.Text = JogSpeed[0];
textBox6.Text = JogSpeed[1];
textBox7.Text = JogSpeed[2];
textBox8.Text = JogSpeed[3];
ReadWritePmacVariables("Motor[1].ActPos,4");
string ActPos0 = responses;
string[] ActPos = ActPos0.Split(',');
textBox1.Text = ActPos[0];
textBox2.Text = ActPos[1];
textBox3.Text = ActPos[2];
textBox4.Text = ActPos[3];
}
#endregion
通过异步通讯使用终端,利用终端可以对PMAC进行控制。
this.FtpCommunication = Connect.CreateFTPClient(CommunicationGlobals.FTPConnectionTypes.FTP, null);
try
{
if (PublicParameter.Globals.IsValidLicense)
{
this.FtpCommunication = Connect.CreateFTPClient(CommunicationGlobals.FTPConnectionTypes.FTP, null);
PublicParameter.Globals.IsValidLicense = true;
}
}
catch (Exception ex)
{
PublicParameter.Globals.IsValidLicense = false;
this.AppendTextToOutPut(ex.Message);
}
打开要上传的文件
private string uploadFileName = string.Empty;
private void button3_Click(object sender, EventArgs e)
{
var openFileDialog = new OpenFileDialog();
try
{
openFileDialog.Filter = $"{this.allFilesText} (*.pmc)|*.pmc";
openFileDialog.FilterIndex = 0;
openFileDialog.RestoreDirectory = true;
openFileDialog.InitialDirectory = "@c:\\temp";
if (openFileDialog.ShowDialog() == DialogResult.OK)
{
this.uploadFileNameWithFolder = openFileDialog.FileName;
this.uploadFileName = Path.GetFileName(this.uploadFileNameWithFolder);
this.UploadFileTextBox.Text = openFileDialog.FileName;
}
}
catch (Exception)
{
// ignored
}
}
上传到PMAC中
private void button5_Click(object sender, EventArgs e)
{
if (this.Communication == null)
{
this.AppendTextToOutPut(this.invalidLicenseText);
return;
}
if (string.IsNullOrEmpty(this.ServerTextBox.Text))
{
this.AppendTextToOutPut(this.pleaseSelectFtpServerFirstText);
return;
}
if (string.IsNullOrEmpty(this.uploadFileName))
{
this.AppendTextToOutPut(this.pleaseSelectFileToUploadFirstText);
return;
}
this.AppendTextToOutPut(string.Format(this.tryingToConnectToFtpServerFormat, this.ServerTextBox.Text));
var ftp = Connect.CreateFTPClient(CommunicationGlobals.FTPConnectionTypes.FTP, null);
ftp.ConnectFTP(this.ServerTextBox.Text, "root", "deltatau");
if (!ftp.FTPConnected)
{
this.AppendTextToOutPut(string.Format(this.couldNotConnectToFtpServerFormat, this.ServerTextBox.Text));
}
else
{
this.AppendTextToOutPut(string.Format(this.deletingFileFormat, this.uploadFileName, FtpFilename, this.ServerTextBox.Text));
ftp.RemoveFile(FtpFilename + this.uploadFileName);
var destnationfile = FtpFilename + "/" + uploadFileName;
if (ftp.GetFileSize(destnationfile) > 0)
{
this.AppendTextToOutPut(string.Format(this.couldNotDeleteTheFileFormat, this.uploadFileName, FtpFilename));
}
else
{
var ret = ftp.DownloadFile(this.uploadFileNameWithFolder, destnationfile);
if (ret)
{
this.AppendTextToOutPut(ftp.GetFileSize(FtpFilename + this.uploadFileName) > 0
? string.Format(this.fileUploadeSuccessfullyFormat, this.uploadFileName, FtpFilename)
: this.fileCouldNotBeUploadedText);
}
else
{
this.AppendTextToOutPut(this.fileCouldNotBeUploadedText);
}
}
}
ftp.DisconnectFTP();
}
PMAC下载到上位机
private void button4_Click(object sender, EventArgs e)
{
if (this.Communication == null)
{
this.AppendTextToOutPut(this.invalidLicenseText);
return;
}
if (string.IsNullOrEmpty(this.ServerTextBox.Text))
{
this.AppendTextToOutPut(this.pleaseSelectFtpServerFirstText);
return;
}
this.downloadFileName = this.DownloadFileTextBox.Text;
if (string.IsNullOrEmpty(this.downloadFileName))
{
this.AppendTextToOutPut(this.pleaseSelectFileToDownloadFirstText);
return;
}
this.AppendTextToOutPut(string.Format(this.tryingToConnectToFtpServerFormat, this.ServerTextBox.Text));
var ftp = Connect.CreateFTPClient(CommunicationGlobals.FTPConnectionTypes.FTP, null);
ftp.ConnectFTP(this.ServerTextBox.Text, "root", "deltatau");
if (!ftp.FTPConnected)
{
this.AppendTextToOutPut(string.Format(this.couldNotConnectToFtpServerFormat, this.ServerTextBox.Text));
}
else
{
var sourcefilename = FtpFilename + '/' + downloadFileName;
if (ftp.GetFileSize(sourcefilename) <= 0)
{
this.AppendTextToOutPut(string.Format(this.fileDoesNotExistFormat, this.downloadFileName, FtpFilename, this.ServerTextBox.Text));
}
else
{
var destinationfilename = this.downLoadFilePath + @"\" + downloadFileName;
var ret = ftp.UploadFile(sourcefilename, destinationfilename);
this.AppendTextToOutPut(ret
? string.Format(this.fileDownloadedSuccessfullyFormat, this.downloadFileName, this.downLoadFilePath)
: this.fileCouldNotBeDownloadedText);
}
}
ftp.DisconnectFTP();
}
这个程序是很早之前写的一个测试程序,写的比较急,很多地方没写注释,但是一行行看还是可以看懂的,没有什么复杂的地方,和普通的API调用时一样的。
这应该是PMAC应用的最后一节,以后有再补充吧,写这个系列第一是为了总结自己在应用中所学到的东西,以免以后忘记了有迹可循,第二是想向大家分享自PMAC的使用。PMAC是我接触过最好的运动控制器,但是偏冷门,资源很少,网上很难查到资料,也有一些博主写过关于PMAC应用的分享,但都不是很详细,我使用的是PowerPMAC(CK3M),我有看到罗伯特祥写过这款控制器,但是没有完全写完,挺遗憾的,我刚上手的时候也是在铺天盖地的在网上找资料,国内的话资源很匮乏,我建议大家去外面找,以前官网的论坛很好,大部分的问题可以在里面找到答案,上个月我去看的时候论坛好像关掉了,不知道现在有没有开。
加油!坚持下去一直写!接下来写一个对机器人学导论总结的系列。
这个问题的回答里有开发套件的License,License,注册后的使用方法使用方法。