做个电机的上位机以及电机的说明文档

This commit is contained in:
13763374093 2025-09-08 18:00:31 +08:00
parent 0bc17570d3
commit 309876ff0c
25 changed files with 2042 additions and 4 deletions

1
.gitignore vendored
View File

@ -80,3 +80,4 @@ ModelManifest.xml
v15/
/MotorControl/.vs/MotorControl/FileContentIndex

View File

@ -0,0 +1,25 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.7.34024.191
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MotorControl", "MotorControl\MotorControl.csproj", "{C4E350C1-8E30-41C5-82E9-BD0FA79A29D6}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{C4E350C1-8E30-41C5-82E9-BD0FA79A29D6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{C4E350C1-8E30-41C5-82E9-BD0FA79A29D6}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C4E350C1-8E30-41C5-82E9-BD0FA79A29D6}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C4E350C1-8E30-41C5-82E9-BD0FA79A29D6}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {F72AB833-9587-4BF1-957C-ACC0FDB89F25}
EndGlobalSection
EndGlobal

View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.7.2" />
</startup>
</configuration>

View File

@ -0,0 +1,669 @@
namespace MotorControl
{
partial class Form1
{
/// <summary>
/// 必需的设计器变量。
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// 清理所有正在使用的资源。
/// </summary>
/// <param name="disposing">如果应释放托管资源,为 true否则为 false。</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows
/// <summary>
/// 设计器支持所需的方法 - 不要修改
/// 使用代码编辑器修改此方法的内容。
/// </summary>
private void InitializeComponent()
{
this.bt_Link = new System.Windows.Forms.Button();
this.cb_ComList = new System.Windows.Forms.ComboBox();
this.label1 = new System.Windows.Forms.Label();
this.label1111 = new System.Windows.Forms.Label();
this.lb_ID = new System.Windows.Forms.Label();
this.bt_ReadInfo = new System.Windows.Forms.Button();
this.lb_Pos = new System.Windows.Forms.Label();
this.label3 = new System.Windows.Forms.Label();
this.label2 = new System.Windows.Forms.Label();
this.lb_Velocity = new System.Windows.Forms.Label();
this.label5 = new System.Windows.Forms.Label();
this.lb_Current = new System.Windows.Forms.Label();
this.label7 = new System.Windows.Forms.Label();
this.bt_PosOnce = new System.Windows.Forms.Button();
this.bt_SpeedOnce = new System.Windows.Forms.Button();
this.bt_InOnce = new System.Windows.Forms.Button();
this.lb_LimitCurrent = new System.Windows.Forms.Label();
this.label9 = new System.Windows.Forms.Label();
this.label10 = new System.Windows.Forms.Label();
this.bt_SetLimitCurrent = new System.Windows.Forms.Button();
this.label13 = new System.Windows.Forms.Label();
this.bt_SetPosCom = new System.Windows.Forms.Button();
this.label14 = new System.Windows.Forms.Label();
this.bt_Call = new System.Windows.Forms.Button();
this.label15 = new System.Windows.Forms.Label();
this.bt_SetVelocityCom = new System.Windows.Forms.Button();
this.label16 = new System.Windows.Forms.Label();
this.label17 = new System.Windows.Forms.Label();
this.bt_SetCurrentCom = new System.Windows.Forms.Button();
this.label18 = new System.Windows.Forms.Label();
this.bt_OpenDocunment = new System.Windows.Forms.Button();
this.numID = new System.Windows.Forms.NumericUpDown();
this.numLimitCurrent = new System.Windows.Forms.NumericUpDown();
this.num_Velocity = new System.Windows.Forms.NumericUpDown();
this.num_Current = new System.Windows.Forms.NumericUpDown();
this.bt_Enable = new System.Windows.Forms.Button();
this.bt_StopNow = new System.Windows.Forms.Button();
this.num_Position = new System.Windows.Forms.NumericUpDown();
this.list_Postions = new System.Windows.Forms.ListBox();
this.label4 = new System.Windows.Forms.Label();
this.bt_RecordPos = new System.Windows.Forms.Button();
this.bt_LoopPos = new System.Windows.Forms.Button();
((System.ComponentModel.ISupportInitialize)(this.numID)).BeginInit();
((System.ComponentModel.ISupportInitialize)(this.numLimitCurrent)).BeginInit();
((System.ComponentModel.ISupportInitialize)(this.num_Velocity)).BeginInit();
((System.ComponentModel.ISupportInitialize)(this.num_Current)).BeginInit();
((System.ComponentModel.ISupportInitialize)(this.num_Position)).BeginInit();
this.SuspendLayout();
//
// bt_Link
//
this.bt_Link.Location = new System.Drawing.Point(150, 19);
this.bt_Link.Margin = new System.Windows.Forms.Padding(2);
this.bt_Link.Name = "bt_Link";
this.bt_Link.Size = new System.Drawing.Size(81, 24);
this.bt_Link.TabIndex = 0;
this.bt_Link.Text = "连接";
this.bt_Link.UseVisualStyleBackColor = true;
this.bt_Link.Click += new System.EventHandler(this.bt_Link_Click);
//
// cb_ComList
//
this.cb_ComList.FormattingEnabled = true;
this.cb_ComList.Location = new System.Drawing.Point(55, 22);
this.cb_ComList.Margin = new System.Windows.Forms.Padding(2);
this.cb_ComList.Name = "cb_ComList";
this.cb_ComList.Size = new System.Drawing.Size(92, 20);
this.cb_ComList.TabIndex = 1;
this.cb_ComList.DropDown += new System.EventHandler(this.cb_Com_DropDown);
//
// label1
//
this.label1.AutoSize = true;
this.label1.Location = new System.Drawing.Point(21, 25);
this.label1.Margin = new System.Windows.Forms.Padding(2, 0, 2, 0);
this.label1.Name = "label1";
this.label1.Size = new System.Drawing.Size(29, 12);
this.label1.TabIndex = 2;
this.label1.Text = "COM:";
//
// label1111
//
this.label1111.AutoSize = true;
this.label1111.Location = new System.Drawing.Point(21, 88);
this.label1111.Margin = new System.Windows.Forms.Padding(2, 0, 2, 0);
this.label1111.Name = "label1111";
this.label1111.Size = new System.Drawing.Size(53, 12);
this.label1111.TabIndex = 3;
this.label1111.Text = "电机ID";
//
// lb_ID
//
this.lb_ID.AutoSize = true;
this.lb_ID.Location = new System.Drawing.Point(142, 88);
this.lb_ID.Margin = new System.Windows.Forms.Padding(2, 0, 2, 0);
this.lb_ID.MinimumSize = new System.Drawing.Size(112, 0);
this.lb_ID.Name = "lb_ID";
this.lb_ID.Size = new System.Drawing.Size(112, 12);
this.lb_ID.TabIndex = 4;
this.lb_ID.Text = "(空)";
this.lb_ID.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
//
// bt_ReadInfo
//
this.bt_ReadInfo.Location = new System.Drawing.Point(23, 56);
this.bt_ReadInfo.Margin = new System.Windows.Forms.Padding(2);
this.bt_ReadInfo.Name = "bt_ReadInfo";
this.bt_ReadInfo.Size = new System.Drawing.Size(83, 24);
this.bt_ReadInfo.TabIndex = 5;
this.bt_ReadInfo.Text = "读取信息";
this.bt_ReadInfo.UseVisualStyleBackColor = true;
this.bt_ReadInfo.Click += new System.EventHandler(this.bt_ReadInfo_Click);
//
// lb_Pos
//
this.lb_Pos.AutoSize = true;
this.lb_Pos.Location = new System.Drawing.Point(142, 110);
this.lb_Pos.Margin = new System.Windows.Forms.Padding(2, 0, 2, 0);
this.lb_Pos.MinimumSize = new System.Drawing.Size(112, 0);
this.lb_Pos.Name = "lb_Pos";
this.lb_Pos.Size = new System.Drawing.Size(112, 12);
this.lb_Pos.TabIndex = 7;
this.lb_Pos.Text = "(空)";
this.lb_Pos.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
//
// label3
//
this.label3.AutoSize = true;
this.label3.Location = new System.Drawing.Point(21, 110);
this.label3.Margin = new System.Windows.Forms.Padding(2, 0, 2, 0);
this.label3.Name = "label3";
this.label3.Size = new System.Drawing.Size(107, 12);
this.label3.TabIndex = 6;
this.label3.Text = "电机位置rad";
//
// label2
//
this.label2.AutoSize = true;
this.label2.Location = new System.Drawing.Point(446, 15);
this.label2.Margin = new System.Windows.Forms.Padding(2, 0, 2, 0);
this.label2.Name = "label2";
this.label2.Size = new System.Drawing.Size(53, 12);
this.label2.TabIndex = 9;
this.label2.Text = "电机ID";
//
// lb_Velocity
//
this.lb_Velocity.AutoSize = true;
this.lb_Velocity.Location = new System.Drawing.Point(142, 132);
this.lb_Velocity.Margin = new System.Windows.Forms.Padding(2, 0, 2, 0);
this.lb_Velocity.MinimumSize = new System.Drawing.Size(112, 0);
this.lb_Velocity.Name = "lb_Velocity";
this.lb_Velocity.Size = new System.Drawing.Size(112, 12);
this.lb_Velocity.TabIndex = 11;
this.lb_Velocity.Text = "(空)";
this.lb_Velocity.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
//
// label5
//
this.label5.AutoSize = true;
this.label5.Location = new System.Drawing.Point(21, 132);
this.label5.Margin = new System.Windows.Forms.Padding(2, 0, 2, 0);
this.label5.Name = "label5";
this.label5.Size = new System.Drawing.Size(107, 12);
this.label5.TabIndex = 10;
this.label5.Text = "电机速度(rad/s)";
//
// lb_Current
//
this.lb_Current.AutoSize = true;
this.lb_Current.Location = new System.Drawing.Point(142, 156);
this.lb_Current.Margin = new System.Windows.Forms.Padding(2, 0, 2, 0);
this.lb_Current.MinimumSize = new System.Drawing.Size(112, 0);
this.lb_Current.Name = "lb_Current";
this.lb_Current.Size = new System.Drawing.Size(112, 12);
this.lb_Current.TabIndex = 13;
this.lb_Current.Text = "(空)";
this.lb_Current.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
//
// label7
//
this.label7.AutoSize = true;
this.label7.Location = new System.Drawing.Point(21, 156);
this.label7.Margin = new System.Windows.Forms.Padding(2, 0, 2, 0);
this.label7.Name = "label7";
this.label7.Size = new System.Drawing.Size(89, 12);
this.label7.TabIndex = 12;
this.label7.Text = "电机电流(mA)";
//
// bt_PosOnce
//
this.bt_PosOnce.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
this.bt_PosOnce.Location = new System.Drawing.Point(446, 94);
this.bt_PosOnce.Margin = new System.Windows.Forms.Padding(2);
this.bt_PosOnce.Name = "bt_PosOnce";
this.bt_PosOnce.Size = new System.Drawing.Size(134, 24);
this.bt_PosOnce.TabIndex = 14;
this.bt_PosOnce.Text = "转到第一圈";
this.bt_PosOnce.UseVisualStyleBackColor = true;
this.bt_PosOnce.Click += new System.EventHandler(this.bt_PosOnce_Click);
//
// bt_SpeedOnce
//
this.bt_SpeedOnce.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
this.bt_SpeedOnce.Location = new System.Drawing.Point(446, 122);
this.bt_SpeedOnce.Margin = new System.Windows.Forms.Padding(2);
this.bt_SpeedOnce.Name = "bt_SpeedOnce";
this.bt_SpeedOnce.Size = new System.Drawing.Size(134, 24);
this.bt_SpeedOnce.TabIndex = 15;
this.bt_SpeedOnce.Text = "以1rad/s的速度旋转";
this.bt_SpeedOnce.UseVisualStyleBackColor = true;
this.bt_SpeedOnce.Click += new System.EventHandler(this.bt_SpeedOnce_Click);
//
// bt_InOnce
//
this.bt_InOnce.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
this.bt_InOnce.Location = new System.Drawing.Point(446, 150);
this.bt_InOnce.Margin = new System.Windows.Forms.Padding(2);
this.bt_InOnce.Name = "bt_InOnce";
this.bt_InOnce.Size = new System.Drawing.Size(134, 24);
this.bt_InOnce.TabIndex = 16;
this.bt_InOnce.Text = "以1A的电流旋转";
this.bt_InOnce.UseVisualStyleBackColor = true;
this.bt_InOnce.Click += new System.EventHandler(this.bt_InOnce_Click);
//
// lb_LimitCurrent
//
this.lb_LimitCurrent.AutoSize = true;
this.lb_LimitCurrent.Location = new System.Drawing.Point(142, 178);
this.lb_LimitCurrent.Margin = new System.Windows.Forms.Padding(2, 0, 2, 0);
this.lb_LimitCurrent.MinimumSize = new System.Drawing.Size(112, 0);
this.lb_LimitCurrent.Name = "lb_LimitCurrent";
this.lb_LimitCurrent.Size = new System.Drawing.Size(112, 12);
this.lb_LimitCurrent.TabIndex = 18;
this.lb_LimitCurrent.Text = "(空)";
this.lb_LimitCurrent.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
//
// label9
//
this.label9.AutoSize = true;
this.label9.Location = new System.Drawing.Point(21, 178);
this.label9.Margin = new System.Windows.Forms.Padding(2, 0, 2, 0);
this.label9.Name = "label9";
this.label9.Size = new System.Drawing.Size(113, 12);
this.label9.TabIndex = 17;
this.label9.Text = "电机堵转电流(mA)";
//
// label10
//
this.label10.AutoSize = true;
this.label10.Location = new System.Drawing.Point(9, 226);
this.label10.Margin = new System.Windows.Forms.Padding(2, 0, 2, 0);
this.label10.Name = "label10";
this.label10.Size = new System.Drawing.Size(113, 12);
this.label10.TabIndex = 19;
this.label10.Text = "设置堵转电流(mA)";
//
// bt_SetLimitCurrent
//
this.bt_SetLimitCurrent.Location = new System.Drawing.Point(191, 221);
this.bt_SetLimitCurrent.Margin = new System.Windows.Forms.Padding(2);
this.bt_SetLimitCurrent.Name = "bt_SetLimitCurrent";
this.bt_SetLimitCurrent.Size = new System.Drawing.Size(75, 24);
this.bt_SetLimitCurrent.TabIndex = 21;
this.bt_SetLimitCurrent.Text = "设置";
this.bt_SetLimitCurrent.UseVisualStyleBackColor = true;
this.bt_SetLimitCurrent.Click += new System.EventHandler(this.bt_SetLimitCurrent_Click);
//
// label13
//
this.label13.AutoSize = true;
this.label13.Location = new System.Drawing.Point(456, 244);
this.label13.Margin = new System.Windows.Forms.Padding(2, 0, 2, 0);
this.label13.Name = "label13";
this.label13.Size = new System.Drawing.Size(17, 12);
this.label13.TabIndex = 29;
this.label13.Text = "圈";
//
// bt_SetPosCom
//
this.bt_SetPosCom.Location = new System.Drawing.Point(477, 239);
this.bt_SetPosCom.Margin = new System.Windows.Forms.Padding(2);
this.bt_SetPosCom.Name = "bt_SetPosCom";
this.bt_SetPosCom.Size = new System.Drawing.Size(102, 24);
this.bt_SetPosCom.TabIndex = 28;
this.bt_SetPosCom.Text = "发送命令";
this.bt_SetPosCom.UseVisualStyleBackColor = true;
this.bt_SetPosCom.Click += new System.EventHandler(this.bt_SetPosCom_Click);
//
// label14
//
this.label14.AutoSize = true;
this.label14.Location = new System.Drawing.Point(350, 243);
this.label14.Margin = new System.Windows.Forms.Padding(2, 0, 2, 0);
this.label14.Name = "label14";
this.label14.RightToLeft = System.Windows.Forms.RightToLeft.Yes;
this.label14.Size = new System.Drawing.Size(41, 12);
this.label14.TabIndex = 26;
this.label14.Text = "转到第";
//
// bt_Call
//
this.bt_Call.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
this.bt_Call.Location = new System.Drawing.Point(446, 66);
this.bt_Call.Margin = new System.Windows.Forms.Padding(2);
this.bt_Call.Name = "bt_Call";
this.bt_Call.Size = new System.Drawing.Size(134, 24);
this.bt_Call.TabIndex = 30;
this.bt_Call.Text = "电机校准";
this.bt_Call.UseVisualStyleBackColor = true;
this.bt_Call.Click += new System.EventHandler(this.bt_Call_Click);
//
// label15
//
this.label15.AutoSize = true;
this.label15.Location = new System.Drawing.Point(392, 269);
this.label15.Margin = new System.Windows.Forms.Padding(2, 0, 2, 0);
this.label15.Name = "label15";
this.label15.Size = new System.Drawing.Size(83, 12);
this.label15.TabIndex = 34;
this.label15.Text = "rad/s速度运行";
//
// bt_SetVelocityCom
//
this.bt_SetVelocityCom.Location = new System.Drawing.Point(477, 264);
this.bt_SetVelocityCom.Margin = new System.Windows.Forms.Padding(2);
this.bt_SetVelocityCom.Name = "bt_SetVelocityCom";
this.bt_SetVelocityCom.Size = new System.Drawing.Size(102, 24);
this.bt_SetVelocityCom.TabIndex = 33;
this.bt_SetVelocityCom.Text = "发送命令";
this.bt_SetVelocityCom.UseVisualStyleBackColor = true;
this.bt_SetVelocityCom.Click += new System.EventHandler(this.bt_SetVelocityCom_Click);
//
// label16
//
this.label16.AutoSize = true;
this.label16.Location = new System.Drawing.Point(315, 269);
this.label16.Margin = new System.Windows.Forms.Padding(2, 0, 2, 0);
this.label16.Name = "label16";
this.label16.Size = new System.Drawing.Size(17, 12);
this.label16.TabIndex = 31;
this.label16.Text = "以";
//
// label17
//
this.label17.AutoSize = true;
this.label17.Location = new System.Drawing.Point(410, 294);
this.label17.Margin = new System.Windows.Forms.Padding(2, 0, 2, 0);
this.label17.Name = "label17";
this.label17.Size = new System.Drawing.Size(65, 12);
this.label17.TabIndex = 38;
this.label17.Text = "mA电流运行";
//
// bt_SetCurrentCom
//
this.bt_SetCurrentCom.Location = new System.Drawing.Point(477, 289);
this.bt_SetCurrentCom.Margin = new System.Windows.Forms.Padding(2);
this.bt_SetCurrentCom.Name = "bt_SetCurrentCom";
this.bt_SetCurrentCom.Size = new System.Drawing.Size(102, 24);
this.bt_SetCurrentCom.TabIndex = 37;
this.bt_SetCurrentCom.Text = "发送命令";
this.bt_SetCurrentCom.UseVisualStyleBackColor = true;
this.bt_SetCurrentCom.Click += new System.EventHandler(this.bt_SetCurrentCom_Click);
//
// label18
//
this.label18.AutoSize = true;
this.label18.Location = new System.Drawing.Point(333, 294);
this.label18.Margin = new System.Windows.Forms.Padding(2, 0, 2, 0);
this.label18.Name = "label18";
this.label18.Size = new System.Drawing.Size(17, 12);
this.label18.TabIndex = 35;
this.label18.Text = "以";
//
// bt_OpenDocunment
//
this.bt_OpenDocunment.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
this.bt_OpenDocunment.Location = new System.Drawing.Point(446, 323);
this.bt_OpenDocunment.Margin = new System.Windows.Forms.Padding(2);
this.bt_OpenDocunment.Name = "bt_OpenDocunment";
this.bt_OpenDocunment.Size = new System.Drawing.Size(134, 24);
this.bt_OpenDocunment.TabIndex = 39;
this.bt_OpenDocunment.Text = "打开电机说明文档";
this.bt_OpenDocunment.UseVisualStyleBackColor = true;
this.bt_OpenDocunment.Click += new System.EventHandler(this.bt_OpenDocunment_Click);
//
// numID
//
this.numID.Location = new System.Drawing.Point(511, 12);
this.numID.Margin = new System.Windows.Forms.Padding(2);
this.numID.Name = "numID";
this.numID.Size = new System.Drawing.Size(68, 21);
this.numID.TabIndex = 40;
//
// numLimitCurrent
//
this.numLimitCurrent.Location = new System.Drawing.Point(118, 222);
this.numLimitCurrent.Margin = new System.Windows.Forms.Padding(2);
this.numLimitCurrent.Maximum = new decimal(new int[] {
2000,
0,
0,
0});
this.numLimitCurrent.Name = "numLimitCurrent";
this.numLimitCurrent.Size = new System.Drawing.Size(69, 21);
this.numLimitCurrent.TabIndex = 41;
//
// num_Velocity
//
this.num_Velocity.DecimalPlaces = 2;
this.num_Velocity.Increment = new decimal(new int[] {
1,
0,
0,
131072});
this.num_Velocity.Location = new System.Drawing.Point(335, 264);
this.num_Velocity.Margin = new System.Windows.Forms.Padding(2);
this.num_Velocity.Maximum = new decimal(new int[] {
99999,
0,
0,
0});
this.num_Velocity.Minimum = new decimal(new int[] {
99999,
0,
0,
-2147483648});
this.num_Velocity.Name = "num_Velocity";
this.num_Velocity.Size = new System.Drawing.Size(56, 21);
this.num_Velocity.TabIndex = 44;
//
// num_Current
//
this.num_Current.Location = new System.Drawing.Point(350, 289);
this.num_Current.Margin = new System.Windows.Forms.Padding(2);
this.num_Current.Name = "num_Current";
this.num_Current.Size = new System.Drawing.Size(56, 21);
this.num_Current.TabIndex = 45;
//
// bt_Enable
//
this.bt_Enable.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
this.bt_Enable.Location = new System.Drawing.Point(446, 37);
this.bt_Enable.Margin = new System.Windows.Forms.Padding(2);
this.bt_Enable.Name = "bt_Enable";
this.bt_Enable.Size = new System.Drawing.Size(133, 24);
this.bt_Enable.TabIndex = 46;
this.bt_Enable.Text = "使能电机";
this.bt_Enable.UseVisualStyleBackColor = true;
this.bt_Enable.Click += new System.EventHandler(this.bt_Enable_Click);
//
// bt_StopNow
//
this.bt_StopNow.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
this.bt_StopNow.Location = new System.Drawing.Point(446, 178);
this.bt_StopNow.Margin = new System.Windows.Forms.Padding(2);
this.bt_StopNow.Name = "bt_StopNow";
this.bt_StopNow.Size = new System.Drawing.Size(134, 24);
this.bt_StopNow.TabIndex = 48;
this.bt_StopNow.Text = "立即停止";
this.bt_StopNow.UseVisualStyleBackColor = true;
this.bt_StopNow.Click += new System.EventHandler(this.bt_StopNow_Click);
//
// num_Position
//
this.num_Position.DecimalPlaces = 2;
this.num_Position.Increment = new decimal(new int[] {
1,
0,
0,
131072});
this.num_Position.Location = new System.Drawing.Point(393, 239);
this.num_Position.Margin = new System.Windows.Forms.Padding(2);
this.num_Position.Maximum = new decimal(new int[] {
99999,
0,
0,
0});
this.num_Position.Minimum = new decimal(new int[] {
99999,
0,
0,
-2147483648});
this.num_Position.Name = "num_Position";
this.num_Position.Size = new System.Drawing.Size(56, 21);
this.num_Position.TabIndex = 49;
//
// list_Postions
//
this.list_Postions.FormattingEnabled = true;
this.list_Postions.ItemHeight = 12;
this.list_Postions.Location = new System.Drawing.Point(273, 31);
this.list_Postions.Margin = new System.Windows.Forms.Padding(2);
this.list_Postions.Name = "list_Postions";
this.list_Postions.Size = new System.Drawing.Size(133, 112);
this.list_Postions.TabIndex = 50;
//
// label4
//
this.label4.AutoSize = true;
this.label4.Location = new System.Drawing.Point(273, 14);
this.label4.Margin = new System.Windows.Forms.Padding(2, 0, 2, 0);
this.label4.Name = "label4";
this.label4.Size = new System.Drawing.Size(59, 12);
this.label4.TabIndex = 51;
this.label4.Text = "位置列表:";
//
// bt_RecordPos
//
this.bt_RecordPos.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
this.bt_RecordPos.Location = new System.Drawing.Point(273, 150);
this.bt_RecordPos.Margin = new System.Windows.Forms.Padding(2);
this.bt_RecordPos.Name = "bt_RecordPos";
this.bt_RecordPos.Size = new System.Drawing.Size(133, 24);
this.bt_RecordPos.TabIndex = 52;
this.bt_RecordPos.Text = "记录当前位置";
this.bt_RecordPos.UseVisualStyleBackColor = true;
this.bt_RecordPos.Click += new System.EventHandler(this.bt_RecordPos_Click);
//
// bt_LoopPos
//
this.bt_LoopPos.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
this.bt_LoopPos.Location = new System.Drawing.Point(273, 178);
this.bt_LoopPos.Margin = new System.Windows.Forms.Padding(2);
this.bt_LoopPos.Name = "bt_LoopPos";
this.bt_LoopPos.Size = new System.Drawing.Size(133, 24);
this.bt_LoopPos.TabIndex = 53;
this.bt_LoopPos.Text = "循环运动";
this.bt_LoopPos.UseVisualStyleBackColor = true;
this.bt_LoopPos.Click += new System.EventHandler(this.bt_LoopPos_Click);
//
// Form1
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(600, 360);
this.Controls.Add(this.bt_LoopPos);
this.Controls.Add(this.bt_RecordPos);
this.Controls.Add(this.label4);
this.Controls.Add(this.list_Postions);
this.Controls.Add(this.num_Position);
this.Controls.Add(this.bt_StopNow);
this.Controls.Add(this.bt_Enable);
this.Controls.Add(this.num_Current);
this.Controls.Add(this.num_Velocity);
this.Controls.Add(this.numLimitCurrent);
this.Controls.Add(this.numID);
this.Controls.Add(this.bt_OpenDocunment);
this.Controls.Add(this.label17);
this.Controls.Add(this.bt_SetCurrentCom);
this.Controls.Add(this.label18);
this.Controls.Add(this.label15);
this.Controls.Add(this.bt_SetVelocityCom);
this.Controls.Add(this.label16);
this.Controls.Add(this.bt_Call);
this.Controls.Add(this.label13);
this.Controls.Add(this.bt_SetPosCom);
this.Controls.Add(this.label14);
this.Controls.Add(this.bt_SetLimitCurrent);
this.Controls.Add(this.label10);
this.Controls.Add(this.lb_LimitCurrent);
this.Controls.Add(this.label9);
this.Controls.Add(this.bt_InOnce);
this.Controls.Add(this.bt_SpeedOnce);
this.Controls.Add(this.bt_PosOnce);
this.Controls.Add(this.lb_Current);
this.Controls.Add(this.label7);
this.Controls.Add(this.lb_Velocity);
this.Controls.Add(this.label5);
this.Controls.Add(this.label2);
this.Controls.Add(this.lb_Pos);
this.Controls.Add(this.label3);
this.Controls.Add(this.bt_ReadInfo);
this.Controls.Add(this.lb_ID);
this.Controls.Add(this.label1111);
this.Controls.Add(this.label1);
this.Controls.Add(this.cb_ComList);
this.Controls.Add(this.bt_Link);
this.Margin = new System.Windows.Forms.Padding(2);
this.Name = "Form1";
this.Text = "Jyker电机上位机";
this.Load += new System.EventHandler(this.Form1_Load);
((System.ComponentModel.ISupportInitialize)(this.numID)).EndInit();
((System.ComponentModel.ISupportInitialize)(this.numLimitCurrent)).EndInit();
((System.ComponentModel.ISupportInitialize)(this.num_Velocity)).EndInit();
((System.ComponentModel.ISupportInitialize)(this.num_Current)).EndInit();
((System.ComponentModel.ISupportInitialize)(this.num_Position)).EndInit();
this.ResumeLayout(false);
this.PerformLayout();
}
#endregion
private System.Windows.Forms.Button bt_Link;
private System.Windows.Forms.ComboBox cb_ComList;
private System.Windows.Forms.Label label1;
private System.Windows.Forms.Label label1111;
private System.Windows.Forms.Label lb_ID;
private System.Windows.Forms.Button bt_ReadInfo;
private System.Windows.Forms.Label lb_Pos;
private System.Windows.Forms.Label label3;
private System.Windows.Forms.Label label2;
private System.Windows.Forms.Label lb_Velocity;
private System.Windows.Forms.Label label5;
private System.Windows.Forms.Label lb_Current;
private System.Windows.Forms.Label label7;
private System.Windows.Forms.Button bt_PosOnce;
private System.Windows.Forms.Button bt_SpeedOnce;
private System.Windows.Forms.Button bt_InOnce;
private System.Windows.Forms.Label lb_LimitCurrent;
private System.Windows.Forms.Label label9;
private System.Windows.Forms.Label label10;
private System.Windows.Forms.Button bt_SetLimitCurrent;
private System.Windows.Forms.Label label13;
private System.Windows.Forms.Button bt_SetPosCom;
private System.Windows.Forms.Label label14;
private System.Windows.Forms.Button bt_Call;
private System.Windows.Forms.Label label15;
private System.Windows.Forms.Button bt_SetVelocityCom;
private System.Windows.Forms.Label label16;
private System.Windows.Forms.Label label17;
private System.Windows.Forms.Button bt_SetCurrentCom;
private System.Windows.Forms.Label label18;
private System.Windows.Forms.Button bt_OpenDocunment;
private System.Windows.Forms.NumericUpDown numID;
private System.Windows.Forms.NumericUpDown numLimitCurrent;
private System.Windows.Forms.NumericUpDown num_Velocity;
private System.Windows.Forms.NumericUpDown num_Current;
private System.Windows.Forms.Button bt_Enable;
private System.Windows.Forms.Button bt_StopNow;
private System.Windows.Forms.NumericUpDown num_Position;
private System.Windows.Forms.ListBox list_Postions;
private System.Windows.Forms.Label label4;
private System.Windows.Forms.Button bt_RecordPos;
private System.Windows.Forms.Button bt_LoopPos;
}
}

View File

@ -0,0 +1,344 @@
using Masuit.Tools;
using Microsoft.Win32;
using MotorControl.Logger;
using MotorControl.Serials;
using MotorControl.Serials.Slcan;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace MotorControl
{
public partial class Form1 : Form
{
Serial Serial;
//坐标列表
List<float> positions = new List<float>();
//记录获取位置信息的时间
DateTime PosTime = DateTime.Now;
//记录获取速递信息的时间
DateTime VelocityTime = DateTime.Now;
//当前位置
float PosNow = 0;
//当前速度
float VelocityNow = 0;
//停止运动标志
bool IsStop = false;
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
Serial = new Serial();
Serial.GetResInfo += Serial_GetResInfo;
}
//加载串口
private void cb_Com_DropDown(object sender, EventArgs e)
{
var list = new List<string>();
const string keyPath = @"HARDWARE\DEVICEMAP\SERIALCOMM";
using (RegistryKey key = Registry.LocalMachine.OpenSubKey(keyPath))
{
if (key != null)
{
cb_ComList.Items.Clear();
foreach (string valueName in key.GetValueNames())
{
if (!valueName.Contains("USB")) continue;
string portName = key.GetValue(valueName) as string;
var caption = $"{portName}_{valueName}";
Match match = Regex.Match(caption, @"COM\d+");
if (match.Success)
{
string comPortName = match.Value; // 提取匹配到的 COM 名称
cb_ComList.Items.Add(comPortName);
list.Add(comPortName);
}
}
}
}
}
//打开连接
private void bt_Link_Click(object sender, EventArgs e)
{
if (bt_Link.Text == "断开连接")
{
cb_ComList.Enabled = true;
bt_Link.Text = "连接";
SetButtomState(false);
}
else
{
var name = cb_ComList.SelectedItem + "";
var res = Serial.Open(name);
if (res)
{
cb_ComList.Enabled = false;
bt_Link.Text = "断开连接";
SetButtomState(true);
}
}
}
private void SetButtomState(bool state)
{
}
//读取信息
private void bt_ReadInfo_Click(object sender, EventArgs e)
{
var Id = (int)numID.Value;
var frame = SlcanParser.ParseSlcanFrameStr(Id, 0x21);
Serial?.PushDataToQueue(frame);
Thread.Sleep(5);
frame = SlcanParser.ParseSlcanFrameStr(Id, 0x22);
Serial?.PushDataToQueue(frame);
Thread.Sleep(5);
frame = SlcanParser.ParseSlcanFrameStr(Id, 0x23);
Serial?.PushDataToQueue(frame);
Thread.Sleep(5);
frame = SlcanParser.ParseSlcanFrameStr(Id, 0x26);
Serial?.PushDataToQueue(frame);
}
//读取数据回调
private void Serial_GetResInfo(int Id, float value, InfoType type)
{
this.Invoke(new Action(() => {
switch (type)
{
case InfoType.Current:
lb_Current.Text = value + "";
break;
case InfoType.Velocity:
lb_Velocity.Text = value + "";
VelocityTime = DateTime.Now;
VelocityNow = value;
break;
case InfoType.Position:
lb_Pos.Text = value + "";
PosTime = DateTime.Now;
PosNow = value;
JLog.Info("这时候获取的");
break;
case InfoType.CurrentLimint:
lb_LimitCurrent.Text = value + "";
break;
default:
break;
}
lb_ID.Text = Id + "";
}));
}
//使能(失能)电机
private void bt_Enable_Click(object sender, EventArgs e)
{
var Id = (int)numID.Value;
var frame = SlcanParser.ParseSlcanFrameStr(Id, 0x01);
Serial?.PushDataToQueue(frame);
if (bt_Enable.Text.Equals("使能电机"))
{
bt_Enable.Text = "失能电机";
}
else
{
bt_Enable.Text = "使能电机";
}
}
//校准电机
private void bt_Call_Click(object sender, EventArgs e)
{
var Id = (int)numID.Value;
var frame = SlcanParser.ParseSlcanFrameStr(Id, 0x02);
Serial?.PushDataToQueue(frame);
}
//转一圈
private void bt_PosOnce_Click(object sender, EventArgs e)
{
var Id = (int)numID.Value;
var frame = SlcanParser.ParseSlcanFrameStr(Id, 0x05, 1);
Serial?.PushDataToQueue(frame);
}
//以一圈每秒的速度旋转
private void bt_SpeedOnce_Click(object sender, EventArgs e)
{
var Id = (int)numID.Value;
var frame = SlcanParser.ParseSlcanFrameStr(Id, 0x04, 1);
Serial?.PushDataToQueue(frame);
}
//以1A的电流旋转
private void bt_InOnce_Click(object sender, EventArgs e)
{
var Id = (int)numID.Value;
var frame = SlcanParser.ParseSlcanFrameStr(Id, 0x03, 1);
Serial?.PushDataToQueue(frame);
}
//马上停止
private void bt_StopNow_Click(object sender, EventArgs e)
{
var Id = (int)numID.Value;
var frame = SlcanParser.ParseSlcanFrameStr(Id, 0x04, 0);
Serial?.PushDataToQueue(frame);
IsStop = true;
}
//转到xx圈绝度位移
private void bt_SetPosCom_Click(object sender, EventArgs e)
{
var Id = (int)numID.Value;
var value = (float)num_Position.Value;
var frame = SlcanParser.ParseSlcanFrameStr(Id, 0x05, value);
Serial?.PushDataToQueue(frame);
}
//设置以xx速度运行
private void bt_SetVelocityCom_Click(object sender, EventArgs e)
{
var Id = (int)numID.Value;
var value = (float)num_Velocity.Value;
var frame = SlcanParser.ParseSlcanFrameStr(Id, 0x04, value);
Serial?.PushDataToQueue(frame);
}
//以xx的电流运行电机
private void bt_SetCurrentCom_Click(object sender, EventArgs e)
{
var Id = (int)numID.Value;
var value = (float)num_Current.Value;
var frame = SlcanParser.ParseSlcanFrameStr(Id, 0x03, value);
Serial?.PushDataToQueue(frame);
}
//设置限制电流
private void bt_SetLimitCurrent_Click(object sender, EventArgs e)
{
var Id = (int)numID.Value;
var value = ((float)(numLimitCurrent.Value)) * 0.001f;
var frame = SlcanParser.ParseSlcanFrameStr(Id, 0x12, value, resACK: true);
Serial?.PushDataToQueue(frame);
}
//记录当前位置
private void bt_RecordPos_Click(object sender, EventArgs e)
{
Task.Run(() => {
var Id = (int)numID.Value;
var frame = SlcanParser.ParseSlcanFrameStr(Id, 0x23);
Serial?.PushDataToQueue(frame);
int count = 0;
while (true && count < 10)
{
JLog.Info(PosTime.ToString());
count++;
if (PosTime.AddSeconds(1) > DateTime.Now)
{
this.Invoke(new Action(() => {
//一秒之内获取的,还比较新鲜,就用这个
list_Postions.Items.Add(PosNow);
}));
return;
}
Thread.Sleep(10);
}
this.Invoke(new Action(() => {
MessageBox.Show("获取当前位置失败");
}));
});
}
//循环运动
private void bt_LoopPos_Click(object sender, EventArgs e)
{
IsStop = false;
Task.Run(() =>
{
while (!IsStop)
{
var items = list_Postions.Items;
if (items.Count == 0)
{
IsStop = true;
JLog.Info("没有循环数据");
}
for (int i = 0; i < items.Count; i++)
{
// 发送移动命令
var val = Convert.ToString(items[i]);
if (!float.TryParse(val, out float res))
{
continue;
}
var Id = (int)numID.Value;
var frame = SlcanParser.ParseSlcanFrameStr(Id, 0x05, res);
Serial?.PushDataToQueue(frame);
this.Invoke(new Action(() =>
{
//设置select;
list_Postions.SelectedItem = items[i];
}));
Thread.Sleep(100);
// 等待电机到位
while (Math.Abs(PosNow - res) > 0.01&& !IsStop)
{
Id = (int)numID.Value;
frame = SlcanParser.ParseSlcanFrameStr(Id, 0x23);
Serial?.PushDataToQueue(frame);
Thread.Sleep(10);
}
}
}
});
}
//打开说明文档
private void bt_OpenDocunment_Click(object sender, EventArgs e)
{
string pdfPath = @"电机说明文档.pdf";
if (!System.IO.File.Exists(pdfPath))
{
MessageBox.Show("文件不存在!");
return;
}
try
{
Process.Start(new ProcessStartInfo()
{
FileName = pdfPath,
UseShellExecute = true // 必须为 true 才能使用系统默认程序
});
}
catch (Exception ex)
{
JLog.Error(ex);
}
}
}
}

View File

@ -0,0 +1,120 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>

View File

@ -0,0 +1,44 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace MotorControl.Logger
{
internal class JLog
{
internal static event Action<string> MessageEvent;
internal static event Action<string> MessageEventLive;
/// <summary>
/// 打印错误信息
/// </summary>
/// <param name="msg"></param>
internal static void Error(Exception msg)
{
Masuit.Tools.Logging.LogManager.Error(msg);
//MessageEvent?.Invoke(msg.Message);
}
/// <summary>
/// 打印普通信息
/// </summary>
/// <param name="msg"></param>
internal static void Info(string msg)
{
Masuit.Tools.Logging.LogManager.Info(msg);
MessageEvent?.Invoke(msg);
}
/// <summary>
/// 打印普通信息
/// </summary>
/// <param name="msg"></param>
internal static void InfoLive(string msg)
{
Masuit.Tools.Logging.LogManager.Info(msg);
MessageEventLive?.Invoke(msg);
}
}
}

View File

@ -0,0 +1,146 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{C4E350C1-8E30-41C5-82E9-BD0FA79A29D6}</ProjectGuid>
<OutputType>WinExe</OutputType>
<RootNamespace>MotorControl</RootNamespace>
<AssemblyName>MotorControl</AssemblyName>
<TargetFrameworkVersion>v4.7.2</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
<Deterministic>true</Deterministic>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="Castle.Core, Version=4.0.0.0, Culture=neutral, PublicKeyToken=407dd0808d44fbdc, processorArchitecture=MSIL">
<HintPath>..\packages\Castle.Core.4.4.1\lib\net45\Castle.Core.dll</HintPath>
</Reference>
<Reference Include="DnsClient, Version=1.7.0.0, Culture=neutral, PublicKeyToken=4574bb5573c51424, processorArchitecture=MSIL">
<HintPath>..\packages\DnsClient.1.7.0\lib\net471\DnsClient.dll</HintPath>
</Reference>
<Reference Include="Masuit.Tools.Net45, Version=2.5.9.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\Masuit.Tools.Net45.2025.5.0\lib\net45\Masuit.Tools.Net45.dll</HintPath>
</Reference>
<Reference Include="Microsoft.Web.Infrastructure, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.Web.Infrastructure.1.0.0.0\lib\net40\Microsoft.Web.Infrastructure.dll</HintPath>
</Reference>
<Reference Include="Microsoft.Win32.Registry, Version=5.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.Win32.Registry.5.0.0\lib\net461\Microsoft.Win32.Registry.dll</HintPath>
</Reference>
<Reference Include="Newtonsoft.Json, Version=13.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
<HintPath>..\packages\Newtonsoft.Json.13.0.3\lib\net45\Newtonsoft.Json.dll</HintPath>
</Reference>
<Reference Include="RJCP.SerialPortStream, Version=2.4.2.0, Culture=neutral, PublicKeyToken=5f5e7b70c6a74deb, processorArchitecture=MSIL">
<HintPath>..\packages\SerialPortStream.2.4.2\lib\net45\RJCP.SerialPortStream.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Buffers, Version=4.0.3.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
<HintPath>..\packages\System.Buffers.4.5.1\lib\net461\System.Buffers.dll</HintPath>
</Reference>
<Reference Include="System.ComponentModel.DataAnnotations" />
<Reference Include="System.Configuration" />
<Reference Include="System.Core" />
<Reference Include="System.Management" />
<Reference Include="System.Security.AccessControl, Version=5.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\System.Security.AccessControl.5.0.0\lib\net461\System.Security.AccessControl.dll</HintPath>
</Reference>
<Reference Include="System.Security.Principal.Windows, Version=5.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\System.Security.Principal.Windows.5.0.0\lib\net461\System.Security.Principal.Windows.dll</HintPath>
</Reference>
<Reference Include="System.ValueTuple, Version=4.0.3.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
<HintPath>..\packages\System.ValueTuple.4.5.0\lib\net47\System.ValueTuple.dll</HintPath>
</Reference>
<Reference Include="System.Web" />
<Reference Include="System.Web.Helpers, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.AspNet.WebPages.3.3.0\lib\net45\System.Web.Helpers.dll</HintPath>
</Reference>
<Reference Include="System.Web.Mvc, Version=5.3.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.AspNet.Mvc.5.3.0\lib\net45\System.Web.Mvc.dll</HintPath>
</Reference>
<Reference Include="System.Web.Razor, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.AspNet.Razor.3.3.0\lib\net45\System.Web.Razor.dll</HintPath>
</Reference>
<Reference Include="System.Web.WebPages, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.AspNet.WebPages.3.3.0\lib\net45\System.Web.WebPages.dll</HintPath>
</Reference>
<Reference Include="System.Web.WebPages.Deployment, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.AspNet.WebPages.3.3.0\lib\net45\System.Web.WebPages.Deployment.dll</HintPath>
</Reference>
<Reference Include="System.Web.WebPages.Razor, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.AspNet.WebPages.3.3.0\lib\net45\System.Web.WebPages.Razor.dll</HintPath>
</Reference>
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Deployment" />
<Reference Include="System.Drawing" />
<Reference Include="System.Net.Http" />
<Reference Include="System.Windows.Forms" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="Form1.cs">
<SubType>Form</SubType>
</Compile>
<Compile Include="Form1.Designer.cs">
<DependentUpon>Form1.cs</DependentUpon>
</Compile>
<Compile Include="Logger\JLog.cs" />
<Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Serials\Serial.cs" />
<Compile Include="Serials\Slcan\CanFrame.cs" />
<Compile Include="Serials\Slcan\SlcanParser.cs" />
<EmbeddedResource Include="Form1.resx">
<DependentUpon>Form1.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="Properties\Resources.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
<SubType>Designer</SubType>
</EmbeddedResource>
<Compile Include="Properties\Resources.Designer.cs">
<AutoGen>True</AutoGen>
<DependentUpon>Resources.resx</DependentUpon>
</Compile>
<None Include="packages.config" />
<None Include="Properties\Settings.settings">
<Generator>SettingsSingleFileGenerator</Generator>
<LastGenOutput>Settings.Designer.cs</LastGenOutput>
</None>
<Compile Include="Properties\Settings.Designer.cs">
<AutoGen>True</AutoGen>
<DependentUpon>Settings.settings</DependentUpon>
<DesignTimeSharedInput>True</DesignTimeSharedInput>
</Compile>
<None Include="电机说明文档.pdf">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>
<ItemGroup>
<None Include="App.config" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>

View File

@ -0,0 +1,23 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace MotorControl
{
internal static class Program
{
/// <summary>
/// 应用程序的主入口点。
/// </summary>
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
}
}
}

View File

@ -0,0 +1,36 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// 有关程序集的一般信息由以下
// 控制。更改这些特性值可修改
// 与程序集关联的信息。
[assembly: AssemblyTitle("MotorControl")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("微软中国")]
[assembly: AssemblyProduct("MotorControl")]
[assembly: AssemblyCopyright("Copyright © 微软中国 2025")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// 将 ComVisible 设置为 false 会使此程序集中的类型
//对 COM 组件不可见。如果需要从 COM 访问此程序集中的类型
//请将此类型的 ComVisible 特性设置为 true。
[assembly: ComVisible(false)]
// 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID
[assembly: Guid("c4e350c1-8e30-41c5-82e9-bd0fa79a29d6")]
// 程序集的版本信息由下列四个值组成:
//
// 主版本
// 次版本
// 生成号
// 修订号
//
//可以指定所有这些值,也可以使用“生成号”和“修订号”的默认值
//通过使用 "*",如下所示:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

View File

@ -0,0 +1,71 @@
//------------------------------------------------------------------------------
// <auto-generated>
// 此代码由工具生成。
// 运行时版本: 4.0.30319.42000
//
// 对此文件的更改可能导致不正确的行为,如果
// 重新生成代码,则所做更改将丢失。
// </auto-generated>
//------------------------------------------------------------------------------
namespace MotorControl.Properties
{
/// <summary>
/// 强类型资源类,用于查找本地化字符串等。
/// </summary>
// 此类是由 StronglyTypedResourceBuilder
// 类通过类似于 ResGen 或 Visual Studio 的工具自动生成的。
// 若要添加或移除成员,请编辑 .ResX 文件,然后重新运行 ResGen
// (以 /str 作为命令选项),或重新生成 VS 项目。
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
internal class Resources
{
private static global::System.Resources.ResourceManager resourceMan;
private static global::System.Globalization.CultureInfo resourceCulture;
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
internal Resources()
{
}
/// <summary>
/// 返回此类使用的缓存 ResourceManager 实例。
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Resources.ResourceManager ResourceManager
{
get
{
if ((resourceMan == null))
{
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("MotorControl.Properties.Resources", typeof(Resources).Assembly);
resourceMan = temp;
}
return resourceMan;
}
}
/// <summary>
/// 重写当前线程的 CurrentUICulture 属性,对
/// 使用此强类型资源类的所有资源查找执行重写。
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Globalization.CultureInfo Culture
{
get
{
return resourceCulture;
}
set
{
resourceCulture = value;
}
}
}
}

View File

@ -0,0 +1,117 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>

View File

@ -0,0 +1,30 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.42000
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace MotorControl.Properties
{
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "11.0.0.0")]
internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase
{
private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
public static Settings Default
{
get
{
return defaultInstance;
}
}
}
}

View File

@ -0,0 +1,7 @@
<?xml version='1.0' encoding='utf-8'?>
<SettingsFile xmlns="http://schemas.microsoft.com/VisualStudio/2004/01/settings" CurrentProfile="(Default)">
<Profiles>
<Profile Name="(Default)" />
</Profiles>
<Settings />
</SettingsFile>

View File

@ -0,0 +1,152 @@
using MotorControl.Logger;
using MotorControl.Serials.Slcan;
using RJCP.IO.Ports;
using System;
using System.Collections.Generic;
using System.IO.Ports;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace MotorControl.Serials
{
internal enum InfoType
{
Current,
Velocity,
Position,
CurrentLimint
}
internal class Serial
{
private Queue<string> DataToSend;
public event Action<int, float, InfoType> GetResInfo;
public void PushDataToQueue(string data)
{
if (!OpenResult)
{
JLog.Info("请先打开连接");
return;
}
DataToSend.Enqueue(data);
//JLog.Info($"加入队列:{data}");
}
private bool OpenResult;
//串口工具
private static SerialPortStream stream;
public bool Open(string name)
{
try
{
if (stream != null && stream.IsOpen)
{
stream.Dispose();
}
stream = new SerialPortStream(name, 115200, 8, RJCP.IO.Ports.Parity.None, RJCP.IO.Ports.StopBits.One);
stream.ReadTimeout = 1000;
stream.DataReceived += Stream_DataReceived;
stream.Open();
OpenResult = true;
DataToSend = new Queue<string>();
LoopSend();
//设置波特率
PushDataToQueue("S8\r");
//开始
PushDataToQueue("O\r");
}
catch (Exception)
{
OpenResult = false;
}
return OpenResult;
}
//循环发送数据
private void LoopSend()
{
Task.Run(async () =>
{
while (OpenResult)
{
try
{
if(DataToSend.Count==0)
{
Thread.Sleep(5);
continue;
}
string send = DataToSend.Dequeue();
if (!string.IsNullOrEmpty(send))
{
stream.Write(send);
//JLog.Info(send);
}
}
catch (Exception e)
{
JLog.Error(e);
}
}
});
}
//数据接收
private void Stream_DataReceived(object sender, RJCP.IO.Ports.SerialDataReceivedEventArgs e)
{
var sp = sender as SerialPortStream;
var recieveText = sp.ReadExisting();
var frames = recieveText.Split('\r');
foreach (var frame in frames)
{
if (string.IsNullOrEmpty(frame)) continue;
var aFrame = SlcanParser.ParseSlcanFrame(frame);
if (aFrame != null)
{
switch (aFrame.Cmd)
{
case 0x21:
//电流信息
var current = BitConverter.ToSingle(aFrame.Data.Take(4).ToArray(),0);
GetResInfo?.Invoke(aFrame.Id, current, InfoType.Current);
JLog.Info($"电流 {current}");
break;
case 0x22:
// 速度信息
var velocity = BitConverter.ToSingle(aFrame.Data.Take(4).ToArray(), 0);
GetResInfo?.Invoke(aFrame.Id, velocity, InfoType.Velocity);
break;
case 0x23:
//角度信息
var angle = BitConverter.ToSingle(aFrame.Data.Take(4).ToArray(), 0);
GetResInfo?.Invoke(aFrame.Id, angle, InfoType.Position);
break;
case 0x26:
//堵转电流
var currentLimit = BitConverter.ToSingle(aFrame.Data.Take(4).ToArray(), 0);
GetResInfo?.Invoke(aFrame.Id, currentLimit, InfoType.CurrentLimint);
break;
}
}
}
}
public bool SerialDispose()
{
//关闭CAN 传输
stream.Write("C/r");
//关闭串口
stream.Close();
return true;
}
}
}

View File

@ -0,0 +1,31 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace MotorControl.Serials.Slcan
{
public class CanFrame
{
public int Id { get; set; } = 0;
public int Cmd { get; set; }
public byte[] Data { get; set; } = new byte[0];
public bool IsExtended { get; set; }
public bool IsRtr { get; set; }
public byte Dlc { get; set; } = 0;
public override string ToString()
{
return $"ID: 0x{Id:X8}, DLC: {Dlc}, Data: {BitConverter.ToString(Data)}";
}
public string ToStr()
{
var IdCmd = (Id << 7 | Cmd).ToString("X3");
var DlcStr = Dlc.ToString("X1");
var DataStr = string.Concat(Data.Select(t => t.ToString("X2")));
return $"t{IdCmd}{DlcStr}{DataStr}\r";
}
}
}

View File

@ -0,0 +1,115 @@
using MotorControl.Logger;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace MotorControl.Serials.Slcan
{
public static class SlcanParser
{
public static CanFrame ParseSlcanFrame(string frame)
{
try
{
char cmd = frame[0];
var canFrame = new CanFrame();
switch (cmd)
{
case 't': // 标准帧
canFrame.IsExtended = false;
canFrame.IsRtr = false;
break;
case 'T': // 扩展帧
canFrame.IsExtended = true;
canFrame.IsRtr = false;
break;
case 'r': // 远程标准帧
canFrame.IsExtended = false;
canFrame.IsRtr = true;
break;
case 'R': // 远程扩展帧
canFrame.IsExtended = true;
canFrame.IsRtr = true;
break;
default:
throw new ArgumentException("Unsupported frame type.");
}
// 解析 ID 和 DLC
var IdCmd = frame.Substring(1, 3);
canFrame.Id = Convert.ToInt32(IdCmd, 16) >> 7;
canFrame.Cmd = Convert.ToInt32(IdCmd, 16) & 0x7F;
canFrame.Dlc = byte.Parse(frame.Substring(4, 1));
if (canFrame.Dlc > 0)
{
canFrame.Data = new byte[canFrame.Dlc];
for (int i = 0; i < canFrame.Dlc; i++)
{
var oneByte = byte.Parse(frame.Substring(5 + i * 2, 2), System.Globalization.NumberStyles.HexNumber);
canFrame.Data[i] = oneByte;
}
}
else
{
canFrame.Data = Array.Empty<byte>();
}
return canFrame;
}
catch (Exception e)
{
JLog.Error(e);
return null;
}
}
public static CanFrame ParseSlcanFrame(int Id, int Cmd, float value, bool resACK = false)
{
return ParseSlcanFrame(Id, Cmd, value, 0, resACK);
}
public static CanFrame ParseSlcanFrame(int Id, int Cmd, float value1, float value2, bool resACK = false)
{
CanFrame canFrame = new CanFrame();
canFrame.Id = Id;
canFrame.Cmd = Cmd;
canFrame.Dlc = 8;
canFrame.Data = new byte[8];
byte[] bytes1 = BitConverter.GetBytes(value1);
for (int i = 0; i < bytes1.Length; i++)
{
canFrame.Data[i] = bytes1[i];
}
byte[] bytes2 = BitConverter.GetBytes(value2);
for (int i = 0; i < bytes2.Length; i++)
{
canFrame.Data[i + 4] = bytes2[i];
}
if(resACK)
{
canFrame.Data[4] = 1;
}
return canFrame;
}
public static string ParseSlcanFrameStr(int Id, int Cmd)
{
return ParseSlcanFrame(Id, Cmd, 0, 0).ToStr();
}
public static string ParseSlcanFrameStr(int Id, int Cmd, float value, bool resACK = false)
{
return ParseSlcanFrame(Id, Cmd, value, resACK).ToStr();
}
public static string ParseSlcanFrameStr(int Id, int Cmd, float value1, float value2)
{
return ParseSlcanFrame(Id, Cmd, value1, value2).ToStr();
}
}
}

View File

@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Castle.Core" version="4.4.1" targetFramework="net472" />
<package id="DnsClient" version="1.7.0" targetFramework="net472" />
<package id="Masuit.Tools.Net45" version="2025.5.0" targetFramework="net472" />
<package id="Microsoft.AspNet.Mvc" version="5.3.0" targetFramework="net472" />
<package id="Microsoft.AspNet.Razor" version="3.3.0" targetFramework="net472" />
<package id="Microsoft.AspNet.WebPages" version="3.3.0" targetFramework="net472" />
<package id="Microsoft.CSharp" version="4.7.0" targetFramework="net472" />
<package id="Microsoft.Web.Infrastructure" version="1.0.0.0" targetFramework="net472" />
<package id="Microsoft.Win32.Registry" version="5.0.0" targetFramework="net472" />
<package id="Newtonsoft.Json" version="13.0.3" targetFramework="net472" />
<package id="SerialPortStream" version="2.4.2" targetFramework="net472" />
<package id="System.Buffers" version="4.5.1" targetFramework="net472" />
<package id="System.Security.AccessControl" version="5.0.0" targetFramework="net472" />
<package id="System.Security.Principal.Windows" version="5.0.0" targetFramework="net472" />
<package id="System.ValueTuple" version="4.5.0" targetFramework="net472" />
</packages>

Binary file not shown.

Binary file not shown.

67
MotorControl/README.md Normal file
View File

@ -0,0 +1,67 @@
电机控制上位机系统
基于 CAN 通信协议的智能电机控制上位机软件
本项目是一个用于控制支持 CAN 通信的智能电机驱动器的上位机软件,支持电机状态读取、基本控制、参数设置和循环运动功能。
📋 功能特性
✅ 通过串口SLCAN协议与电机通信
✅ 支持多电机 ID 识别与控制
✅ 实时读取电流、速度、位置、限流值
✅ 电机使能/失能、校准、快速测试
✅ 目标位置、速度、电流设置
✅ 位置循环运动(支持记录与自动循环)
✅ 图形化界面,操作简单直观
🛠️ 硬件连接
使用 USB 线将电机驱动器连接至电脑。
驱动器支持 CAN 或串口通信,确保接线正确。
每台电机通过 拨码开关 设置唯一 ID0-7
拨码开关 2、3、4 分别代表权重 1、2、4
例如开关2打开3、4关闭 → ID = 1
💻 软件使用说明
1. 连接设备
打开上位机软件。
从 “COM端口” 下拉框中选择正确的串口号(如 COM3
点击 “连接” 按钮建立连接。
✅ 连接成功后,按钮变为“断开连接”,串口选择框将被锁定。
2. 读取电机状态
在 “电机ID” 输入框中输入目标电机 ID。
点击 “读取信息” 按钮。
软件将显示:
电流 (A)
速度 (rev/s)
位置 (rev)
限流值 (A)
3. 基本控制
操作 说明
使能电机 通电,准备运行(点击后变为“失能电机”)
校准电机 执行编码器校准程序
转一圈 控制电机旋转一整圈
一圈每秒 控制电机以 1 rev/s 的速度运行
1A电流 控制电机以 1A 电流运行
马上停止 立即停止电机运动
4. 参数设置
在对应输入框中输入目标值,点击右侧 “设置” 按钮:
设置位置:运动到指定圈数
设置速度以指定速度运行rev/s
设置电流以指定电流运行A
设置限流设置电流保护上限A
5. 位置循环运动
记录位置点:
手动移动电机到目标位置。
点击 “记录当前位置”,位置将添加到列表。
重复操作,记录多个点。
启动循环:
点击 “循环运动”,电机将按顺序循环运动到每个记录点。
停止循环:
点击 “马上停止” 可随时中断。
📄 通信协议CAN
命令码 功能 数据格式
0x01 使能/禁能 uint32_t
0x02 校准 -
0x03 设置电流 float (A)
0x04 设置速度 float (rev/s)
0x05 设置位置 float (rev) + ACK
0x21~0x26 查询状态 返回 float + 状态
详细协议请参考 CAN通信协议文档

View File

@ -388,7 +388,7 @@ void CAN_Send(CAN_TxHeaderTypeDef* pHeader, uint8_t* data)
uint8_t id = (RxHeader.StdId >> 7); // 4Bits ID & 7Bits Msg
uint8_t cmd = RxHeader.StdId & 0x7F; // 4Bits ID & 7Bits Msg
printf("HAL_CAN_RxFifo0MsgPendingCallback id:%d ,cmd:%d RxData[0]:%d\n",id,cmd,RxData[0]);
//printf("HAL_CAN_RxFifo0MsgPendingCallback id:%d ,cmd:%d RxData[0]:%d\n",id,cmd,RxData[0]);
if (id == 0 || id == boardConfig.canNodeId)
{
OnCanCmd(cmd, RxData, RxHeader.DLC);

View File

@ -39,14 +39,14 @@ void Main()
// .canNodeId = defaultNodeID,
.encoderHomeOffset = 0,
.defaultMode = Motor::MODE_COMMAND_POSITION,
.currentLimit = 1 * 1000, // A
.currentLimit = 2 * 1000, // A
.velocityLimit = 30 * motor.MOTOR_ONE_CIRCLE_SUBDIVIDE_STEPS, // r/s
.velocityAcc = 100 * motor.MOTOR_ONE_CIRCLE_SUBDIVIDE_STEPS, // r/s^2
.calibrationCurrent=2000,
.dce_kp = 200,
.dce_kv = 80,
.dce_ki = 300,
.dce_kd = 250,
.dce_kd = 300,
.motor_temperature = 0.0,
.enableMotorOnBoot=false,
.enableStallProtect=false,

View File

@ -261,6 +261,23 @@ void OnCanCmd(uint8_t _cmd, uint8_t* _data, uint32_t _len)
}
break;
case 0x26: // Get Limit-Current
{
float currentLimitFloat = (float)boardConfig.currentLimit;
// 将浮点数转换为字节序列
unsigned char* b = (unsigned char*)&currentLimitFloat;
for (int i = 0; i < 4; i++)
_data[i] = *(b + i);
_data[4] = 0;
_data[5] = 0;
_data[6] = 0;
_data[7] = 0;
txHeader.StdId = (boardConfig.canNodeId << 7) | 0x26;
CAN_Send(&txHeader, _data);
}
break;
case 0x7d: // enable motor temperature watch
boardConfig.enableTempWatch = true;
break;

View File

@ -4,6 +4,5 @@
source [find interface/stlink.cfg]
transport select hla_swd
source [find target/stm32f1x.cfg]
# download speed = 10MHz
adapter speed 10000