Added class ControllerLogic, Hardcoded Beta for GalaTech "Bohrautomat"
ln.build - build0.waldrennach.l--n.de build job pending Details

master
Harald Wolff 2020-12-28 08:26:13 +01:00
parent acbbcb1aa2
commit 2dbdf5fbb9
15 changed files with 164 additions and 58 deletions

View File

@ -1,12 +1,10 @@
using System;
using System.IO;
using System.Threading;
using System.Timers;
using ln.application;
using ln.ethercat.controller;
using ln.ethercat.controller.drives;
using ln.ethercat.service.api.v1;
using ln.http;
using ln.http.api;
using ln.http.router;
using ln.logging;
using ln.type;
@ -15,7 +13,6 @@ namespace ln.ethercat.service
{
public class EthercatService
{
public ECMaster ECMaster { get; private set; }
[StaticArgument(Option = 'i', LongOption = "interface")]
@ -92,6 +89,7 @@ namespace ln.ethercat.service
try{
EthercatWebSocket.SendProcessData(ECMaster);
ControllerWebSocket.SendUpdates(ECMaster.Controller);
JSONEventWebSocketResponse.SendUpdates();
} catch (Exception ex)
{
Logging.Log(ex);

View File

@ -8,19 +8,15 @@ using ln.json.mapping;
namespace ln.ethercat.service
{
public class MainAxFeederControllerLogic
public class CLGalaTechBohrautomat : ControllerLogic
{
public MyParameters Parameters { get; set; }
ECMaster ECMaster;
SDOValue svRelais;
SDOValue svEnable;
public MainAxFeederControllerLogic(ECMaster ecMaster)
public CLGalaTechBohrautomat()
{
ECMaster = ecMaster;
Parameters = new MyParameters();
if (File.Exists("mafcl.json"))
{
@ -41,22 +37,38 @@ namespace ln.ethercat.service
}
}
public void Initialize()
public override void Initialize(Controller controller)
{
if (!(
ECMaster.GetSDOValue(1, 0x2012, 31, out svRelais) &&
ECMaster.GetSDOValue(1, 0x2012, 32, out svEnable)
controller.ECMaster.GetSDOValue(1, 0x2012, 31, out svRelais) &&
controller.ECMaster.GetSDOValue(1, 0x2012, 32, out svEnable)
))
throw new Exception("could not retrieve needed SDOValues");
}
public void ControllerLogic(Controller contreller)
public override void Cycle(Controller controller)
{
switch (controller.ControllerState)
{
case ControllerStates.FAULT:
svEnable.SetValue((byte)0x00);
break;
case ControllerStates.NOTREADY:
svEnable.SetValue((byte)0x01);
break;
}
if (controller.ControllerState == ControllerStates.OPERATIONAL)
{
svRelais.SetValue((byte)0x01);
} else {
svRelais.SetValue((byte)0x00);
}
}
public class MyParameters {
}
}

View File

@ -34,7 +34,7 @@ namespace ln.ethercat.service
ethercatService.Initialize();
ethercatService.ECMaster.OnStateChange += (ECMaster ECMaster, ECSlaveState newState) => {
if (newState == ECSlaveState.OPERATIONAL)
if (newState == ECSlaveState.SAFE_OP)
{
if (ECMaster.GetSDOValue(1, 0x2012, 32, out SDOValue svEnableDrives))
{
@ -48,21 +48,10 @@ namespace ln.ethercat.service
}
};
ethercatService.ECMaster.Controller.OnStateChanged += (controller, state) => {
Logging.Log(LogLevel.DEBUG, "ControllerState=={0}", state);
if (state == ControllerStates.NOTREADY)
{
if (controller.ECMaster.GetSDOValue(1, 0x2012, 32, out SDOValue svEnableDrives))
{
Logging.Log(LogLevel.DEBUG, "ControllerState=={0} powering up enable signals", state);
svEnableDrives.SetValue((byte)0x01);
}
}
};
ethercatService.ECMaster.Controller.Add(new CLGalaTechBohrautomat());
ethercatService.Start();
if (SerialRemotePort != null)
{
StupidSerialRemote stupidSerialRemote = new StupidSerialRemote(ethercatService.ECMaster.Controller, SerialRemotePort);

View File

@ -1,6 +1,7 @@
using System;
using System.Globalization;
using System.Linq;
using System.Linq.Expressions;
using System.Net.Mail;
using System.Reflection;
using System.Timers;
@ -28,7 +29,15 @@ namespace ln.ethercat.service.api.v1
[GET("/sockets/controller")]
public HttpResponse GetControllerSocket() => new ControllerWebSocket(Controller);
public HttpResponse GetControllerSocket(){
JSONEventWebSocketResponse webSocket = new JSONEventWebSocketResponse(Controller);
for (int drive = 0; drive < Controller.ECMaster.DriveControllers.Length; drive++)
{
DriveController driveController = Controller.ECMaster.DriveControllers[drive];
webSocket.AddTarget(String.Format("drives/{0}", drive), driveController, false);
}
return webSocket;
}
// [GET("/sockets/controller/drives/:drive")]
// public HttpResponse GetDriveControllerSocket(int drive)

View File

@ -1,5 +1,4 @@
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Reflection;
using ln.ethercat.controller;
@ -27,7 +26,6 @@ namespace ln.ethercat.service.api.v1
try
{
JSONArray jsonDriveControllers = new JSONArray();
foreach (DriveController driveController in controller.ECMaster.DriveControllers)

View File

@ -2,10 +2,7 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using ln.http.websocket;
using ln.json;
using ln.json.mapping;

View File

@ -3,15 +3,16 @@
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp3.1</TargetFramework>
<Version>0.1.0</Version>
<Version>0.1.1</Version>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="ln.type" Version="0.1.7-ci" />
<PackageReference Include="ln.logging" Version="1.0.2" />
<PackageReference Include="ln.json" Version="1.0.6" />
<PackageReference Include="ln.http" Version="0.4.0-ci" />
<PackageReference Include="ln.http.api" Version="0.0.6-ci" />
<PackageReference Include="ln.json" Version="1.0.7" />
<PackageReference Include="ln.http" Version="0.4.1" />
<!--PackageReference Include="ln.http.api" Version="0.0.6-ci" /-->
<ProjectReference Include="../../ln.http.api/ln.http.api/ln.http.api.csproj" />
<ProjectReference Include="../ln.ethercat/ln.ethercat.csproj" />
</ItemGroup>

View File

@ -94,11 +94,15 @@ LN
component: {
template: src,
data: function(){
let d = { controller: {}, drive_controller: null };
let d = { controller: false, drive_controller: null };
d.socket = $ECAPP.connectWebSocket("/api/v1/sockets/controller");
d.socket.onmessage = (evt)=>{
let json = JSON.parse(evt.data);
d.controller = json.value;
d.controller = json.value.Controller;
let drives = []
for (let n=0;n<d.controller.DriveCount;n++)
drives.push(json.value["drives/" + n]);
d.drive_controller = drives;
};
return d;
},
@ -106,8 +110,8 @@ LN
drive_set: function(drive, propName, propValue){
let jsonMessage = {
event: "set",
target: `drives/${drive}`,
value: {
drive: drive,
name: propName,
value: propValue
}
@ -117,6 +121,7 @@ LN
ctrl_set: function(propName, propValue){
let jsonMessage = {
event: "set",
target: "Controller",
value: {
name: propName,
value: propValue
@ -128,6 +133,7 @@ LN
arguments = arguments || [];
let jsonMessage = {
event: "action",
target: "Controller",
value: {
method: methodName,
arguments: arguments

View File

@ -19,17 +19,24 @@ header > .wrapper {
main, .flex {
display: flex;
flex-wrap: wrap;
}
main {
flex-wrap: nowrap;
}
main > *, .flex > * {
flex-basis: 100%;
flex-grow: 1;
margin: 0px 8px;
flex-shrink: 1;
}
main > aside, .flex > .aside{
flex-basis: 25%;
flex-grow: 0;
flex-shrink: 0;
min-width: 25%;
}
@ -67,9 +74,25 @@ fieldset {
display: flex;
}
fieldset > * {
flex-grow: 1;
flex-shrink: 1;
flex-basis: 10%;
}
fieldset > label, fieldset > .label {
flex-grow: 1;
flex-shrink: 1;
flex-basis: 5%;
text-align: right;
padding-right: 12px;
padding-left: 12px;
}
/*
fieldset > :first-child {
flex-grow: 1;
flex-basis: 50%;
flex-basis: 25%;
}
fieldset > :nth-child(2) {
flex-grow: 1;
@ -80,9 +103,11 @@ fieldset > :last-child {
flex-basis: 25%;
}
fieldset.equal > * {
flex-basis: 50%;
flex-basis: 25%;
margin: 4px;
flex-shrink: 1;
}
*/
.flex {
display: flex;
@ -117,6 +142,7 @@ fieldset.equal > * {
margin: 2px 8px;
border-radius: 8px;;
background-color: #808080;
text-align: center;
}
.state.large {
width: 240px;

View File

@ -1,10 +1,10 @@
<div>
<h1>Controller</h1>
<div class="panel flex">
<div v-if="controller" class="panel flex">
<column>
<fieldset>
<label>Status</label>
<span class="state" :class="controller.State">{{ controller.State }}</span>
<span class="state" :class="controller.ControllerState">{{ controller.ControllerState }}</span>
</fieldset>
<fieldset class="equal">
<button @click="ctrl_action('DisableDrives');">DISABLE</button>
@ -18,20 +18,20 @@
</column>
<column>
<div class="group"
v-for="drive,key in controller.Drives"
v-for="drive,key in drive_controller"
>
<fieldset>
<label>Drive {{ key }}</label>
<span class="state" :class="drive.DriveState">{{ drive.DriveState }}</span>
<span class="state large" :class="drive.OEMState">{{ drive.OEMState }}</span>
</fieldset>
<fieldset class="equal">
<fieldset class="">
<label>Drive Mode</label>
<span class="value">{{ drive.DriveMode }}</span>
<label>Velocity</label>
<meter :value="Math.abs(drive.ActualSpeed)" min="0.0" max="1.5" low="0.8" high="1.0" optimum="0.7"></meter>
</fieldset>
<fieldset class="equal">
<fieldset class="">
<label>TargetValue</label>
<input type="range" step="0.05" min="-1.0" max="1.0" v-model="drive.TargetValue" @input="drive_set(key, 'TargetValue', drive.TargetValue);">
<label>Torque</label>

View File

@ -3,6 +3,7 @@ using System;
using System.Collections.Generic;
using System.Threading;
using ln.ethercat.controller.drives;
using ln.http.api;
using ln.logging;
namespace ln.ethercat.controller
@ -28,26 +29,39 @@ namespace ln.ethercat.controller
public ECMaster ECMaster { get; }
[ESProperty]
public bool IgnoreRemoteInterface { get; set; }
List<ControlLoop> controlLoops = new List<ControlLoop>();
public ControlLoop[] ControlLoops => controlLoops.ToArray();
[ESProperty]
public ControllerStates ControllerState { get; private set; }
[ESProperty]
public double ControllerLoopInterval { get; set; } = 0.1;
[ESProperty]
public double ControllerLoopFrequency {
get => 1.0 / ControllerLoopInterval;
set => ControllerLoopInterval = 1.0 / value;
}
[ESProperty]
public long CycleCounter { get; private set; }
Thread threadWatchdog;
int wdogCounter;
[ESProperty]
public bool DisableRemoteWatchdog { get; set; }
int remoteWatchdogCounter;
public int WatchdogReset { get; set; } = 5;
[ESProperty]
public int DriveCount => ECMaster.DriveControllers.Length;
HashSet<ControllerLogic> controllerLogics = new HashSet<ControllerLogic>();
public Controller(ECMaster ecMaster)
{
ECMaster = ecMaster;
@ -56,6 +70,9 @@ namespace ln.ethercat.controller
public void Add(ControlLoop controlLoop) => controlLoops.Add(controlLoop);
public void Remove(ControlLoop controlLoop) => controlLoops.Remove(controlLoop);
public void Add(ControllerLogic controllerLogic) => controllerLogics.Add(controllerLogic);
public void Remove(ControllerLogic controllerLogic) => controllerLogics.Remove(controllerLogic);
public void Initialize()
{
CycleCounter = 0;
@ -68,6 +85,9 @@ namespace ln.ethercat.controller
foreach (DriveController driveController in ECMaster.DriveControllers)
driveController.Initialize();
foreach (ControllerLogic controllerLogic in controllerLogics)
controllerLogic.Initialize(this);
}
void UpdateControllerState()
@ -98,6 +118,12 @@ namespace ln.ethercat.controller
if (driveState < nextState)
nextState = driveState;
}
if ((ControllerState == ControllerStates.FAULT) && (nextState == ControllerStates.OPERATIONAL))
{
DisableDrives();
nextState = ControllerStates.FAULT;
}
}
ChangeState(nextState);
}
@ -107,6 +133,9 @@ namespace ln.ethercat.controller
if (newState == ControllerState)
return;
if (ControllerState == ControllerStates.FAULT)
return;
OnStateChanging?.Invoke(this, newState);
switch (newState)
@ -129,11 +158,13 @@ namespace ln.ethercat.controller
OnStateChanged?.Invoke(this, newState);
}
[ESMethod]
public void DisableDrives()
{
ChangeState(ControllerStates.DISABLING);
}
[ESMethod]
public void EnableDrives()
{
if (ControllerState == ControllerStates.READY)
@ -144,8 +175,12 @@ namespace ln.ethercat.controller
}
}
[ESMethod]
public void ClearFaults()
{
if (ControllerState == ControllerStates.FAULT)
ControllerState = ControllerStates.NONE;
foreach (DriveController driveController in ECMaster.DriveControllers)
{
if (driveController.DriveState == DriveStates.ERROR)
@ -206,6 +241,9 @@ namespace ln.ethercat.controller
foreach (ControlLoop controlLoop in controlLoops)
controlLoop.Loop();
foreach (ControllerLogic controllerLogic in controllerLogics)
controllerLogic.Cycle(this);
ControllerLogic?.Invoke(this);
foreach (DriveController driveController in ECMaster.DriveControllers)

View File

@ -0,0 +1,10 @@
using System.Transactions;
namespace ln.ethercat.controller
{
public abstract class ControllerLogic
{
public abstract void Initialize(Controller controller);
public abstract void Cycle(Controller contreller);
}
}

View File

@ -250,14 +250,14 @@ namespace ln.ethercat.controller.drives
public override double ActualLoad => (double)(svActualCurrent?.GetValue<short>() ?? 0) / 1000.0;
public override double TargetPosition {
get => svTargetPosition.GetValue<int>();
get => svTargetPosition?.GetValue<int>() ?? 0;
set => svTargetPosition.SetValue((int)value);
}
public override double TargetSpeed {
get {
if (ModeOfOperation == CIA402ModesOfOperation.CYCLIC_SYNC_VELOCITY)
return (double)svTargetSpeed.GetValue<int>() / (1000.0 * MotorMaxSpeed);
return (double)(svTargetSpeed?.GetValue<int>() ?? 0) / (1000.0 * MotorMaxSpeed);
return (double)(svVLTargetVelocity?.GetValue<short>() ?? 0) / MotorMaxSpeed;
}
set {
@ -267,11 +267,11 @@ namespace ln.ethercat.controller.drives
}
}
public override double TargetTorque {
get => (double)svTargetTorque.GetValue<short>() / 1000.0;
get => (double)(svTargetTorque?.GetValue<short>() ?? 0) / 1000.0;
set => svTargetTorque.SetValue((short)(1000 * value));
}
public override int ErrorCode => svErrorCode.GetValue<int>();
public override int ErrorCode => svErrorCode?.GetValue<ushort>() ?? 0;
public override string ErrorText => ErrorCode.ToString();

View File

@ -1,8 +1,5 @@
using System;
using System.Net.Http.Headers;
using System.Runtime;
using ln.http.api;
namespace ln.ethercat.controller.drives
{
@ -26,8 +23,11 @@ namespace ln.ethercat.controller.drives
public abstract class DriveController
{
protected ECMaster ECMaster { get; }
[ESProperty]
public UInt16 Slave { get; }
[ESProperty]
public bool IgnoredByController { get; set; }
@ -44,33 +44,53 @@ namespace ln.ethercat.controller.drives
/* called by controller after user logic */
public abstract void UpdateDrive();
[ESProperty]
public abstract DriveStates DriveState { get; }
[ESProperty]
public abstract string OEMDriveState { get; }
[ESProperty]
public abstract Int32 ErrorCode { get; }
[ESProperty]
public abstract string ErrorText { get; }
[ESMethod]
public abstract void ClearFault();
[ESProperty]
public abstract DriveMode DriveMode { get; set; }
[ESProperty]
public abstract string OEMDriveMode { get; }
[ESMethod]
public void PowerOn() => Power(true);
[ESMethod]
public void PowerOff() => Power(false);
[ESMethod]
public abstract void Power(bool poweron);
[ESMethod]
public void EnableDrive() => Enable(true);
[ESMethod]
public void DisableDrive() => Enable(false);
[ESMethod]
public abstract void Enable(bool enabled);
[ESProperty]
public abstract double ActualPosition { get; }
[ESProperty]
public abstract double ActualSpeed { get; }
[ESProperty]
public abstract double ActualTorque { get; }
[ESProperty]
public abstract double TargetPosition { get; set; }
[ESProperty]
public abstract double TargetSpeed { get; set; }
[ESProperty]
public abstract double TargetTorque { get; set; }
[ESProperty]
public abstract double ActualLoad { get; }
[ESProperty]
public virtual double TargetValue {
get {
switch (DriveMode)

View File

@ -19,8 +19,10 @@
<PackageReference Include="System.IO.Ports" Version="5.0.0" />
<PackageReference Include="ln.type" Version="0.1.7-ci" />
<PackageReference Include="ln.logging" Version="1.0.2" />
<PackageReference Include="ln.json" Version="1.0.6" />
<PackageReference Include="ln.json" Version="1.0.7" />
<PackageReference Include="ln.collections" Version="0.1.3-ci" />
<!--PackageReference Include="ln.http.api" Version="0.0.6-ci" /-->
<ProjectReference Include="../../ln.http.api/ln.http.api/ln.http.api.csproj" />
</ItemGroup>
</Project>