![](/img/trans.png)
[英]Creating a program to establish connection to PLC through PVI and another program
[英]Automatically re-create PollValues<T> after a lost PLC connection or PLC program upload
我正在嘗試編寫 C# 應用程序,當應用程序與 PLC 失去連接或將下載新版本的 PLC 程序時,ADS 客戶端將自動重新連接/更新讀取/寫入值和訂閱。
我正在使用 NuGet 的TwinCAT.Ads.Reactive v4.4.0庫。
連接ADS服務器(連接成功)=>
創建反應性循環寫入值ValueSymbolExtensions.WriteValues
代碼:
// WhenValueChanged()
TreeViewSymbols = SymbolLoaderFactory.Create(_client, SymbolLoaderSettings.Default).Symbols; // Load symbol tree from plc
IValueSymbol boolVal = (IValueSymbol)TreeViewSymbols["SomeBoolValue"];
boolVal.WhenValueChanged().Subscribe(Observer.Create<object>(val => ArchiveData((bool)val)));
// WriteValues()
IValueSymbol toggleBit = (IValueSymbol)TreeViewSymbols["toggle_bit"];
toggleBit.WriteValues(
Observable.Interval(TimeSpan.FromSeconds(1.0)).Select(x => x % 2 == 0 ? false : (object)true),
e => Debug.WriteLine($"Error writing toggle bit")
);
IValueSymbol state = (IValueSymbol)TreeViewSymbols[Cfg.ModuleStateTag];
state.PollValues(TimeSpan.FromSeconds(1.0))
.Subscribe(Observer.Create<object>(
val => // val comes as byte[] array
{
var a = new ModuleStateData((byte[])val);
Debug.WriteLine($"Status values Machine Mode:{a.MachineMode}");
},
e => Debug.WriteLine($"Error reading status"),
() => Debug.WriteLine($"OnComplete???? reading status"))
).AddDisposableTo(_disposables);
_client.PollValues<ModuleStateData>(
Cfg.ModuleStateTag,
TimeSpan.FromSeconds(1.0)
).Subscribe(Observer.Create<object>(
val =>
{
Debug.WriteLine($"Status values Machine Mode:{val.MachineMode});
},
e => Debug.WriteLine($"Error reading status - {e.Message}"),
() => Debug.WriteLine($"OnComplete???? reading status"))
).AddDisposableTo(_disposables);
此外,僅當我在廣告客戶端上調用 Connect()/Disconnect() 時才會觸發連接狀態更改事件,而不是在連接問題上。 知道如何發現連接問題嗎?
我已經找到了一半問題的解決方案,其中 observable 即使在連接錯誤(拔出以太網電纜)時也能正常工作,但是在下載新的 PLC 程序(廣告符號版本已更改)后,它不會使用新版本重新創建變量,因此它只會引發錯誤.
解決方案是使用PollValues 的另一個重載,其中我指定了Func<Exception, T> errorHandler
。 此處理程序的工作方式類似於備份值,以防出現錯誤。
_client.PollValues<ModuleStateData>(
Cfg.ModuleStateTag,
TimeSpan.FromSeconds(1.0),
e =>
{
Debug.WriteLine($"Error reading status {Cfg.Name} - {e.Message}");
return new ModuleStateData()
{
// Set data in case of error
};
}
);
我已將此問題報告給 nuget 包的創建者。
感謝您報告此問題,這是一個重要方面。 我對你的情況進行了簡短的調查。 不幸的是,實際上並不支持 observable 的自動復活。 原因是 PollValues 內部使用符號句柄,當現在的 PLC 程序更新時,符號句柄將失效。 所以實際上,您唯一的解決方案是在 TcAdsClient/AdsConnection 上注冊 SymbolVersionChanged 事件(這是在下載/重啟后發送的)並重新創建 Observable。
https://infosys.beckhoff.de/content/1031/tc3_adsnetref/7313543307.html?id=2192955395989567903
如果適合您等待 AdsClient / Ads.Reactive 包的下一個版本 - 應該可以在 PollValues 代碼中內部處理這種情況(以您期望的方式)。 我現在有它在我的待辦事項清單上。
在我得到這個答案之前,我已經編輯了他們的實現並創建了我自己的擴展方法。
public static IObservable<T> PollValues<T>(
this IAdsConnection connection,
string instancePath,
int[] args,
IObservable<Unit> trigger,
Func<Exception, T> errorHandler)
{
DisposableHandleBag bag = new DisposableHandleBag(connection, (IList<string>) new string[1]
{
instancePath
});
Func<Unit, T> selector = (Func<Unit, T>) (o =>
{
try
{
return (T) connection.ReadAny(61445U, bag.GetHandle(instancePath), typeof (T), args);
}
catch (Exception ex)
{
if (errorHandler != null)
return errorHandler(ex);
throw;
}
});
Action finallyAction = (Action) (() =>
{
bag.Dispose();
bag = (DisposableHandleBag) null;
});
return trigger.Select<Unit, T>(selector).Finally<T>(finallyAction);
}
public static IObservable<T> MyPollValues<T>(
this IAdsConnection connection,
string instancePath,
int[] args,
IObservable<Unit> trigger,
Func<Exception, T> errorHandler)
{
Func<Unit, T> selector = (Func<Unit, T>)(o =>
{
try
{
var handle = connection.CreateVariableHandle(instancePath);
var data = (T)connection.ReadAny(handle, typeof(T), args);
connection.DeleteVariableHandle(handle);
return data;
}
catch (Exception ex)
{
if (errorHandler != null)
return errorHandler(ex);
throw;
}
});
return trigger.Select<Unit, T>(selector);
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.