連接鈕

作為連接 (Connect)斷開連接 (Disconnect) 紐用,點選此鈕後 KINGSTAR 子系統將會連接至硬體,若硬體已連接,點擊鈕以斷連。

此鈕名稱為 btnConnect,擁有連接至位置 btnConnectClicked 之信號 clicked,點擊此鈕後使用 setEnabled 以停用之,如此當連接正在建立時即無法點擊該鈕,而 Timeout 為一決定 EtherCAT 連接是否耗費過長時間建立之變數。

以下代碼在 QtGui.cpp 中:

void QtGui::btnConnectClicked()
   int Timeout = 0;
   ui->btnConnect->setEnabled(false);

在連接至硬體前,使用 getecState 函式以檢查 EtherCAT 之連接狀態,getecState 回傳 maSts.State 之值,由此可知 EtherCAT 連結是否已建立,若已建立,則代表此鈕功能為 Disconnect 鈕;否則為 Connect 鈕。

不管鈕的功能為 ConnectDisconnect 皆會呼叫兩個函式:processEventscommandConnectprocessEvents 為當 EtherCAT 連結建立或故障時維持使用者介面 (UI) 運作的 QApplication 成員函式;commandConnect 為連接至位置 actionConnect 的信號,commandConnect 信號一旦發射,將立即觸發 actionConnect

以下代碼在 QtGui.cpp 中:

while (ks->getecState() != ecatOP && Timeout < 2000)
{
   QApplication::processEvents();
   emit commandConnect();

actionConnect 寫在 ksworker.cpp 中,使用 switch 陳述式來測試 wkState,其為 workerState 列舉之變數,內含三種狀態:disconnectedconnectingconnected

連接 (Connect)

作為 Connect 鈕的狀態為 disconnected,其中我們將 wkState 設為 connecting,並在開關陳列式中執行 connecting 功能塊。

連接前

點選 Connect 將執行 disconnected 功能塊內的代碼,下列函式將初始化和建立 EtherCAT 連結,並開啟 KINGSTAR 子系統:

以下代碼在 ksworker.cpp 中:

ksWorker::ksWorker(QObject *parent)
: QObject(parent), dataTimer(new QTimer(this)), data({false, 0.0, 0.0}),
   maSts({ ecatOffline, ecatOffline, 0, 0, 0, { ecatOffline }, { ecatOffline }, { axisOffline } }), 
   wkState(disconnected), currentIndex(-1), commandVelocity(360)
{

   nRet = Create(0, 0);

   if (nRet != errNoError) {
      return;
   }
   ......
}

void ksWorker::actionConnect()
{
   switch (wkState)
   {
      case disconnected:
      wkState = connecting;

      nRet = SetAxisAccessMode(KsAccessMode::accessPos);
      nRet = SetCycleTime(cycle1000);
      nRet = SetConfiguredAxesCount(1);
      nRet = ConfigureDc(TRUE, TRUE, TRUE, 0);

      WaitForCommand(0.2, FALSE, Start());

      GetStatus(&maSts, nullptr);

      break;

      case connecting:
      GetStatus(&maSts, nullptr);
      if (maSts.State == EthercatState::ecatOP)
      {
         wkState = connected;

         SlaveStatus *ss = new SlaveStatus;

         McProfileSettings Motion = { 
            3,
            360,
            5000,
            50000,
            50000,
            5000000,
            0
         };

         for (int i = 0; i < maSts.AxesCount; i++)
         {
            int Resolution = 10000;
            DWORD InputVariables = 0;
            DWORD OutputVariables = 0;

            GetAxisByIndex(i, ss, &Resolution, &InputVariables, &OutputVariables);
            SetAxisMotionProfile(i, profileUnitPerSecond, Motion);
            SetAxisCountsPerUnit(i, Resolution, 360, FALSE);
            EnableAxisUnitConversion(i, TRUE);
            SetAxisPositionOffset(i, 0, FALSE, McExecutionMode::mcImmediately);
            powerStatus.push_back(FALSE);
           emit sendName(i, ss->Name);
         }
         delete ss;

         dataTimer->start(100);
      }
      break;
      ...........
   }
   ...........
}

連接中

connecting 功能塊中使用以下函式來初始化運動設定:

計時器

connecting 結尾使用 dataTimer 作為計時器,而 start 設定 dataTimer 之時間區間至 100 毫秒,每 100 豪秒 dataTimer 會發射 QTimer::timeout 信號,其連接 lambda 函式作為第三參數。

當觸發 timeout 時,lambda 函式將檢查 EtherCAT 連結狀態是否為操作中 (Op) 且 currentIndex 大於零,若是,將獲得所選軸的電力狀態並分配至 data.powerStatus,其中 currentIndex 為軸的索引,而 data 為用來獲取軸狀態的 axisData 結構之變數。接著使用 GetAxisPositionGetAxisVelocity 來獲取軸的實際位置和實際速度,最後發射連接至位置 updateAxisDatasendData 信號,其將立即執行,而 updateAxisData 將依照狀態更新 GUI 元素。

以下代碼在 ksworker.cpp 中:

QObject::connect(dataTimer, &QTimer::timeout, [this]()
{
   if (maSts.State == ecatOP && currentIndex >= 0)
   { 
      double pos = 0.0;
      double vel = 0.0;

      data.powerStatus = powerStatus[currentIndex];
      nRet = GetAxisPosition(currentIndex, McSource::mcActualValue, &pos);
      if (nRet == KsError::errNoError)
         data.actualPos = pos;
      else
         data.actualPos = (double)nRet;

      nRet = GetAxisVelocity(currentIndex, McSource::mcActualValue, &(vel));
      if (nRet == KsError::errNoError)
         data.actualVel = vel;
      else
         data.actualVel = (double)nRet;
   }

   emit sendData(data);
});

以下代碼在 QtGui.cpp 中:

void QtGui::updateAxisData(axisData data)
{
   if (!ui->btnEnable->isEnabled())
   {
      if (ui->btnEnable->text() == "Enable" && data.powerStatus)
      {
         ui->btnEnable->setText("Disable");
         ui->btnEnable->setEnabled(true);
         ui->btnJogForward->setEnabled(true);
         ui->btnJogBackward->setEnabled(true);
      }
      else if (ui->btnEnable->text() == "Disable" && !data.powerStatus)
      {
         ui->btnEnable->setText("Enable");
         ui->btnEnable->setEnabled(true);
         ui->btnJogForward->setEnabled(false);
         ui->btnJogBackward->setEnabled(false);
      }
   }
   else
   {
      if (data.powerStatus)
      {
         ...........
      }
      else
      {
         ...........
      }
   }

   ui->leActPosition->setText(QString::number(data.actualPos, 'f', 3));
   ui->leActVelocity->setText(QString::number(data.actualVel, 'f', 3));
}

連結建立後,更改以下 GUI 元素之設定:

以下代碼在 QtGui.cpp 中:

ui->listDevices->setCurrentRow(0);
ui->leCommVelocity->setEnabled(true); 	//Enable the Command Velocity box.
ui->leCommVelocity->setText("360");	//Set the value to 360 in the Command Velocity box.
ui->btnEnable->setEnabled(true);	//Enable the Enable button.
ui->btnReset->setEnabled(true);		//Enable the Reset button.
ui->btnJogForward->setEnabled(true);	//Enable the Jog Forward button.
ui->btnJogBackward->setEnabled(true);	//Enable the Jog Backward button.

ui->btnConnect->setText("Disconnect");	//Change the text of the Connect button to "Disconnect."

statusLabel->setText("EC state: OP");	//Change the text of the Status label to "EC state: OP."
statusProgress->setMaximum(100);	//Change the maximum step of the progress bar to 100.
statusProgress->setValue(100);		//Set the current value of the progress bar to 100.

斷開連結 (Disconnect)

作為 Disconnect 鈕的狀態為 connected,我們將停止計時器,並使用 PowerAxis 來停用所有軸,再用 Stop 來停止 EtherCAT 網路及 KINGSTAR 子系統WaitForCommand 用來給 PowerAxis 一些時間而 Stop 用來完成其工作,我們給 PowerAxis 5 秒而給 Stop 2 秒,wkState 設為 disconnected 以將鈕設為 Connect,而 currentIndex 設為 -1,代表沒有任何軸,maSts 將恢復為預設值。

以下代碼在 ksworker.cpp 中:

case connected:
   dataTimer->stop();

   for (int i = 0; i < maSts.AxesCount; i++)
   {
      KsCommandStatus Command = { 0 };
      Command = WaitForCommand(5, FALSE, PowerAxis(i, FALSE, FALSE, FALSE));
   }

   WaitForCommand(2, FALSE, Stop());
   wkState = disconnected;
   currentIndex = -1;
   maSts = { ecatOffline, ecatOffline, 0, 0, 0, { ecatOffline }, { ecatOffline }, { axisOffline } };
   break;

default:
   break;
}