C#産業オートメーション開発完全ガイド:エンタープライズアプリケーションの構築

無料無料技术资料

这篇内容可直接阅读,适合用于基础学习和検索引流。

C#産業オートメーション開発完全ガイド:エンタープライズアプリケーションの構築

C#/. NET産業オートメーション開発完全ガイド:エンタープライズクラスの産業用アプリケーションの構築

産業オートメーションにおけるC#/. NETの利点

C#/. NETプラットフォームは、強力な型システム、豊富なクラスライブラリ、優れたパフォーマンス、マイクロソフトの包括的なサポートにより、エンタープライズクラスの産業オートメーションの世界で重要な地位を占めています。従来のWindowsデスクトップアプリケーションから最新のクラウドネイティブマイクロサービスまで、C#/. NETは完全なソリューションスタックを提供し、特に高信頼性、高いパフォーマンスを、長期メンテナンスを必要とする産業用アプリケーションに最適です。 この記事では、NModbusライブラリの使用、WPF/Win Formsインターフェイスの開発、エンタープライズアーキテクチャの設計、プロフェッショナルグレードの産業オートメーションシステムの構築方法を示す実践的なケーススタディに焦点を当て、産業オートメーションにおけるC#/. NETの使用について深く掘り下げます。

C#/. NET産業開発環境の設定

1.1開発環境の要件

<!-- . NET SDKのバージョン要件->
<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroupの略。>
    <TargetFramework Net 8.0/TargetFramework>
    <OutputType Exe/OutputType>
    <Nullable/Nullable>
  </PropertyGroup>
<プロジェクト/Project>

1.2プロジェクト構造と依存構成

<!-- IndustrialAutomation.csproj-->
<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroupの略。>
    <WinExe/OutputTypeの設定>
    <TargetFramework net 8.0-Windows/TargetFramework>
    <UseWPF true/UseWPF>
    <Nullable/Nullable>
  </PropertyGroup>

  <ItemGroup>
    <!-- Modbus通信 ->
    <PackageReference Include="NModbus" Version="3.0.73" />
    <PackageReference Include="NModbus.Serial" Version="3.0.73" />

    <!--シリアル通信-->
    <PackageReference Include="System.IO.Ports" Version="8.0.0" />

    <!--ログ--->
    <PackageReference Include="Serilog"バージョン="3.1.1" />
    <PackageReference Include="Serilog. Sinks.File" Version="5.0.0" />
    <PackageReference Include="Serilog.Sinks.Console" Version="5.0.0" />

    <!--依存性注入 ->
    <PackageReference Include="Microsoft. Extension.DependencyInjection" Version="8.0.0" />
    <PackageReference Include="Microsoft.Extensions.Hosting" Version="8.0.0" />

    <!--構成管理 ->
    <PackageReference Include="Microsoft. Extension.Configuration" Version="8.0.0" />
    <PackageIn =". Extons.ation.Json" Version="8.0.0" />

    <!--データ検証->
    <PackageReference Include="FluentValidation" Version="11.8.0" />

    <!--ユニットテスト-->
    <PackageReference Include="xunit" Version="2.6.3" />
    <PackageReference Include="xunit.runner.visualstudio" Version="2.5.5" />
    <PackageReference Include="Moq" Version="4.20.69" />
  </ItemGroup>

</Project>

1.3プロジェクトのディレクトリ構造

産業オートメーション/
略称はSRC。
│ │ │   カテゴリー:Industrial Automation.Core/          コアビジネスロジック
│ │ │   │ │ │   あなたは-モデル。                         #データモデル
│ │ │   │ │ │   あなた-サービス/                       #ビジネスサービス
│ │ │   │ │ │   略称は“インターフェイス”。                     #インターフェースの定義
│ │ │   │ │ │   3-例外とは                     #例外の定義
│ │ │   │ │ │
│ │ │   Industrial Automation.Modbusの略。        # Modbus通信モジュール
│ │ │   │ │ │   クライアント-クライアント。                        # Modbusクライアント
│ │ │   │ │ │   あなたはサーバーです。                        # Modbusサーバ
│ │ │   │ │ │   そして、Converters/                     #データコンバータ
│ │ │   │ │ │
│ │ │   カテゴリー:Industrial Automation.UI            #ユーザーインターフェース
│ │ │   │ │ │   あなたの意見-ビュー                          # WPFビュー
│ │ │   │ │ │   タイトル:ViewModels                     # MVVMビューモデル
│ │ │   │ │ │   あなたはConvertersです。                     #値変換器
│ │ │   │ │ │   10.“Be haviors”                      #振る舞いは
│ │ │   │ │ │
│ │ │   6--Industrial Automation.Host/          #アプリケーションホスト
│ │ │
あなた-テスト/テスト
│ │ │   カテゴリー:Industrial Automation.Core.Tests
│ │ │   カテゴリー:Industrial Automation.Modbus.Tests
│ │ │   産業オートメーション-統合-テスト/
│ │ │
>> config/とは
│ │ │   >> appsettings.json                    #設定の適用
│ │ │   appsettings.development.json        #開発環境の設定
│ │ │   >> devices.json                        #装備の設定
│ │ │
それは...ドキュメント。                                   #プロジェクトファイル

2. NModbusライブラリの深い使用

2.1 Modbus TCPクライアント

NModbusの使用
NModbus.Deviceを使用する
System.Net.Socketsの使用

名前空間産業オートメーション.Modbus.Clients
{
    //summary>
    // Modbus TCPクライアント
    ////summary>
    public class ModbusTcpClient IModbusClient、IDisposable
    {
        private readonly ILogger ModbusTcpclient_logger;
        private readonly Tcpclient_tcpClient;
        ate modbusmaster;
        private bool_disposed;

        //summary>
        ///デバイス接続ステータス
        ////summary>
        public bool IsConnected =_tcpClient. Connected()偽である。

        //summary>
        ///デバイスのIPアドレス
        ////summary>
        public string IpAddress { get; }

        //summary>
        //デバイスのポート
        ////summary>
        public int Port { get; }

        //summary>
        Modbus TCPクライアントの初期化
        ////summary>
        public ModbusTcpClient
            string ipAddress、
            int port = 502
            ILogger ModbusTcpClient logger = null
        {
            IpAddress = ipAddress throw new ArgumentNullException nameof ipAddress;
            ポート=ポート;
            _logger = logger NullLogger ModbusTcpClient.Instance;
            _tcpClient = new TcpClient();
        }

        /// <summary>
        /// 连接到デバイス
        /// </summary>
        public async Task<bool> ConnectAsync(CancellationToken cancellationToken = default)
        {
            try
            {
                _logger.LogInformation("正在连接到デバイス {IpAddress}:{Port}", IpAddress, Port);

                await _tcpClient.ConnectAsync(IpAddress, Port, cancellationToken);

                var factory = new ModbusFactory();
                _modbusMaster = factory.CreateMaster(_tcpClient);

                // 設定タイムアウト時間
                _modbusMaster.Transport.ReadTimeout = 3000;
                _modbusMaster.Transport.WriteTimeout = 3000;

                _logger.LogInformation("成功连接到デバイス {IpAddress}:{Port}", IpAddress, Port);
                return true;
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "连機器の接続 {IpAddress}:{Port} 失敗", IpAddress, Port);
                return false;
            }
        }

        /// <summary>
        /// リードホールドレジスタ
        /// </summary>
        public async Task<ushort[]> ReadHoldingRegistersAsync(
            byte slaveAddress,
            ushort startAddress,
            ushort numberOfPoints,
            CancellationToken cancellationToken = default)
        {
            ValidateConnection();

            try
            {
                _logger.LogDebug(
                    "リードホールドレジスタ - スレーブ: {SlaveAddress}, アドレス: {StartAddress}, 数量: {NumberOfPoints}",
                    slaveAddress, startAddress, numberOfPoints);

                var result = await Task.Run(() =>
                    _modbusMaster!.ReadHoldingRegisters(slaveAddress, startAddress, numberOfPoints),
                    cancellationToken);

                _logger.LogDebug(
                    "リードホールドレジスタ成功 - スレーブ: {SlaveAddress}, アドレス: {StartAddress}, データ: {Data}",
                    slaveAddress, startAddress, result);

                return result;
            }
            catch (Exception ex)
            {
                _logger.LogError(ex,
                    "リードホールドレジスタ失敗 - スレーブ: {SlaveAddress}, アドレス: {StartAddress}, 数量: {NumberOfPoints}",
                    slaveAddress, startAddress, numberOfPoints);
                throw new ModbusCommunicationException(
                    $"リードホールドレジスタ失敗: {ex.Message}", ex);
            }
        }

        /// <summary>
        /// 写入单レジスタを保持する。
        /// </summary>
        public async Task WriteSingleRegisterAsync(
            byte slaveAddress,
            ushort registerAddress,
            ushort value,
            CancellationToken cancellationToken = default)
        {
            ValidateConnection();

            try
            {
                _logger.LogDebug(
                    "写入单1つのレジスタ - スレーブ: {SlaveAddress}, アドレス: {RegisterAddress}, 值: {Value}",
                    slaveAddress, registerAddress, value);

                await Task.Run(() =>
                    _modbusMaster!.WriteSingleRegister(slaveAddress, registerAddress, value),
                    cancellationToken);

                _logger.LogDebug(
                    "写入单1つのレジスタ成功 - スレーブ: {SlaveAddress}, アドレス: {RegisterAddress}",
                    slaveAddress, registerAddress);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex,
                    "写入单1つのレジスタ失敗 - スレーブ: {SlaveAddress}, アドレス: {RegisterAddress}, 值: {Value}",
                    slaveAddress, registerAddress, value);
                throw new ModbusCommunicationException(
                    $"写入单1つのレジスタ失敗: {ex.Message}", ex);
            }
        }

        /// <summary>
        /// 写入多レジスタを保持する。
        /// </summary>
        public async Task WriteMultipleRegistersAsync(
            byte slaveAddress,
            ushort startAddress,
            ushort[] data,
            CancellationToken cancellationToken = default)
        {
            ValidateConnection();

            try
            {
                _logger.LogDebug(
                    "写入多1つのレジスタ - スレーブ: {SlaveAddress}, アドレス: {StartAddress}, データ長さ: {Length}",
                    slaveAddress, startAddress, data.Length);

                await Task.Run(() =>
                    _modbusMaster!.WriteMultipleRegisters(slaveAddress, startAddress, data),
                    cancellationToken);

                _logger.LogDebug(
                    "写入多1つのレジスタ成功 - スレーブ: {SlaveAddress}, アドレス: {StartAddress}",
                    slaveAddress, startAddress);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex,
                    "写入多1つのレジスタ失敗 - スレーブ: {SlaveAddress}, アドレス: {StartAddress}, データ長さ: {Length}",
                    slaveAddress, startAddress, data.Length);
                throw new ModbusCommunicationException(
                    $"写入多1つのレジスタ失敗: {ex.Message}", ex);
            }
        }

        /// <summary>
        /// コイル状態の読み取り
        /// </summary>
        public async Task<bool[]> ReadCoilsAsync(
            byte slaveAddress,
            ushort startAddress,
            ushort numberOfPoints,
            CancellationToken cancellationToken = default)
        {
            ValidateConnection();

            try
            {
                _logger.LogDebug(
                    "リードコイル - スレーブ: {SlaveAddress}, アドレス: {StartAddress}, 数量: {NumberOfPoints}",
                    slaveAddress, startAddress, numberOfPoints);

                var result = await Task.Run(() =>
                    _modbusMaster!.ReadCoils(slaveAddress, startAddress, numberOfPoints),
                    cancellationToken);

                _logger.LogDebug(
                    "リードコイル成功 - スレーブ: {SlaveAddress}, アドレス: {StartAddress}, データ: {Data}",
                    slaveAddress, startAddress, result);

                return result;
            }
            catch (Exception ex)
            {
                _logger.LogError(ex,
                    "リードコイル失敗 - スレーブ: {SlaveAddress}, アドレス: {StartAddress}, 数量: {NumberOfPoints}",
                    slaveAddress, startAddress, numberOfPoints);
                throw new ModbusCommunicationException(
                    $"リードコイル失敗: {ex.Message}", ex);
            }
        }

        /// <summary>
        /// バッチ読み取り最適化
        /// </summary>
        public async Task<Dictionary<ushort, ushort[]>> BatchReadRegistersAsync(
            byte slaveAddress,
            IEnumerable<RegisterReadRequest> requests,
            CancellationToken cancellationToken = default)
        {
            ValidateConnection();

            var results = new Dictionary<ushort, ushort[]>();

            foreach (var request in requests)
            {
                try
                {
                    var data = await ReadHoldingRegistersAsync(
                        slaveAddress,
                        request.StartAddress,
                        request.NumberOfPoints,
                        cancellationToken);

                    results[request.StartAddress] = data;
                }
                catch (Exception ex)
                {
                    _logger.LogWarning(ex,
                        "批量読み取り失敗 - アドレス: {StartAddress}, 数量: {NumberOfPoints}",
                        request.StartAddress, request.NumberOfPoints);
                    results[request.StartAddress] = Array.Empty<ushort>();
                }
            }

            return results;
        }

        /// <summary>
        /// 切断する
        /// </summary>
        public void Disconnect()
        {
            try
            {
                _modbusMaster?.Dispose();
                _modbusMaster = null;

                if (_tcpClient.Connected)
                {
                    _tcpClient.Close();
                }

                _logger.LogInformation("已断开与デバイス {IpAddress}:{Port} 的连接", IpAddress, Port);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "切断する时发生エラー");
            }
        }

        /// <summary>
        /// 验证连接ステータス
        /// </summary>
        private void ValidateConnection()
        {
            if (!IsConnected || _modbusMaster == null)
            {
                throw new InvalidOperationException("デバイス未连接");
            }
        }

        /// <summary>
        /// 释放リソース
        /// </summary>
        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize this;
        }

        protected virtual void Dispose bool disposing
        {
            if!_ disposed
            {
                if disposing
                {
                    Disconnect Disconnect nParticle nParticle;
                    _tcpClient.Dispose;
                }

                disposed = true;
            }
        }
    }

    //summary>
    ///レジスタ読み取り要求
    ////summary>
    public record RegisterReadRequest
        ushort StartAddress、
        ushort NumberOfPoints;
}

2.2 Modbus RTUクライアント

```csharp using NModbus; using NModbus.Serial; using System.IO.Ports; namespace IndustrialAutomation.Modbus.Clients { ///// Modbus RTUクライアント ///public class ModbusRtuClient : IModbusClient, IDisposable { private readonly ILogger_logger; private readonly SerialPort _serialPort; private IModbusMaster? _modbusMaster; private bool _disposed;
//summary>
    ///シリアル接続ステータス
    ////summary>
    public bool IsConnected =_serialPort. IsOpen偽である。

    //summary>
    ///シリアル名
    ////summary>
    public string PortName { get; }

    //summary>
    ///ボーレート
    ////summary>
    public int baud rate {}

    //summary>
    Modbus RTUクライアントの初期化
    ////summary>
    public ModbusRClient
        string portName、
        baudRate = 96 00です。
        ILogger ModbusRtuClient logger = null
    {
        portName = portName throw new ArgumentNullException nameof portName;
        BaudRate = baudRate;
        _logger = logger NullLogger ModbusRtuClient.Instance;

        _serialPort = new SerialPort portName
        {
            BaudRate = baudRate
            DataBits = 8、
            Parity = Parity.
            StopBits = StopBits.One
            ReadTimeout = 1000
            WriteTimeout = 1000
        };
    }

    //summary>
    ///シリアルデバイスに接続
    ////summary>
    public async bool Async ellationcancellation =
    {
        try tryより
        {
            _logger.LogInformation "シリアルポート{PortName}ボーレート{BaudRate}" PortName BaudRate;

            await Task.Run =>
            {
                if!_ serialPort.IsOpen
                {
                    _serialPort.Open Open nParticle nParticle;
                }
            } cancellationToken;

            var factory = new ModbusFactory;
            var adapter = new SerialPortAdapter_serialPort;
            _modbusMaster = factory. RMaster adapter;

            //Modbusパラメータの設定
            _modbusMaster.Transport.ReadTimeout = 1000;
            _modbusMaster.Transport.WriteTimeout = 1000;
            _modbusMaster.Transport.Retries = 3;
            _modbusMaster.Transport.WaitToRetryMilliseconds = 100;

            _logger.LogInformation "シリアルポート{PortName}が正常にオープンされました" PortName;
            真の帰還;
        }
        catch Exception ex
        {
            _logger.LogError ex "シリアルポート{PortName}のオープンに失敗しました" PortName;
            偽を返す。
        }
    }

    //summary>
    ///シリアルデバイスのスキャン
    ////summary>
    public async List byte DevicesAsync
        byte startAddress = 1
        byte endAddress = 247、
        ellation
    {
        var found = new List byte;

        _logger.LogInformation "スキャンデバイスアドレス范囲{StartAddress}-{EndAddress}" Address endAddress;

        for byte slAddress = Address; slAddress = endAddress; slAddress ++
        {
            if cancellationToken.IsCancellationRequested
            {
                休憩を取る。
            }

            try tryより
            {
                //デバイスIDの読み取りを試みる
                var result = await Task.Run(() =>
                    _modbusMaster!.ReadDeviceIdentification(slaveAddress, 0x01),
                    cancellationToken);

                if (result != null)
                {
                    foundDevices.Add(slaveAddress);
                    _logger.LogInformation("
この資料を実際のプロジェクトに活用しませんか?

ツールセンターで電文解析、CRCチェック、デバイスデバッグを行うか、要件を送信して選定と接続のアドバイスを受けましょう。

エンジニア会員

この記事を実行可能なデバッグ資料に

登録すると、高度な電文解析、資料パックのダウンロード、コード例、エンジニアリングケース、優先技術サポートが利用可能に。実際のプロジェクト納品に最適です。

高度なツール無制限
資料パックとコードパック
完全なエンジニアリングケースライブラリ
優先技術サポート窓口

发表回复

あなたのメールアドレスアドレス不会被公开。 必須項目已用 * 标注