ブログ

割とコンピュータよりの情報をお届けします。

2019年4月

open62541の開発ブランチには互換性がない変更が加わった

以前にopen62541のビルドの記事(1, 2)を書いていたが,その時と異なりGitHubのリポジトリの先頭にはいよいよ次のリリースへ向けて(?)大きな変更が入ってしまった.

GitHubのリポジトリをクローンして使っていると昨年9月のころできていたことができなくなっている.
Server用とClient用の区切りを設けようとしているのか詳しくはわからないが,大きく仕様が変わっており,マニュアルも整っていないようなので,特にWindows用の対応は難しい.試行錯誤でうまく動かすような時間が必要である.

GitHubのリポジトリをクローンして使う場合には,最終リリース版である0.3を使用されることをお勧めする.
ちなみにhttps://open62541.org/では0.3.0の配布になっているのでそちらの方が適当であろう.
昨年9月までは新しい仕様を取り込もうとGitHubからクローンした方がバグフィックスが入っていて便利ということも間違いとは言い難かったが,0.3.0のリリース直前だったからで0.3.0のリリース後は次のリリースへ向けて積極的に変更が入っている.

ファイルの構造が変わって,open62541.hなどの一つのファイルをインクルードすれば足りたファイルがなくなってしまっている.そして,開発版のドキュメントではそれに対応していそうに見えたが,少なくともVisual Studioではライブラリのビルドは成功するのだが,それを使う段階でチュートリアルの方法では失敗する
時間がたてば,もう少し整理されてくるはず.オープンソースでまともに動くOPC-UAの実装の一つなので期待している.

≫ 続きを読む

2019/04/24 コンピュータ   TakeMe

HttpClientは標準でProxy経由の通信になる

.NET FrameworkでHttpClientを使う機会があった.何も気にせずに使い始めると通信にProxyの設定が適用される.

(2023.06.11 追記 下の例のアプリではHttpClientを1回しか使わないから問題ないが、短時間に複数回使用していく用途ではusingで囲うとリソースが枯渇するリスクが上がる。特に最新の.NET Coreや.NET 5.0以降の使用例ではDisposeせずに残している。記事内でKeepAliveなどを気にせずと書いているが、usingブロックから出るときにインスタンスが破棄されるため、KeepAliveなどが持続しないので注意。)

.NET Framework 4.5からの機能だとおもうが,HttpClientというものが使えるようになった.TcpClientでは気にする必要があるKeepAlive/Httpsなどの実装を気にせずに使用できるようだ.参考となるページはHttpClientクラスでWebページを取得するには?[C#、VB]であろうか.
(ただこの記事が書かれた時と状況が異なる点がSystem.Net.ServicePointManager.SecurityProtocol |= System.Net.SecurityProtocolType.Tls12;の部分である.現在では脆弱性の懸念から,SSL 3やTLS1.1などが無効化され始めており,最初からTLS1.2でつなげに行かなければ失敗するサーバーが多くなっている点である.)
さて,外のサーバーに接続する場合には
HttpClientHandler handler = new HttpClientHandler();
handler.UseProxy = false;
もいらない(はずである).
しかし,ローカルにプロキシサーバーを設けている場合にはローカルアドレスに対してプロキシを使用しない設定にしても,http://192.168.1.1/などにリクエストを送ろうとすると,Windows の仕様(ほぼバグ)によりプロキシを経由しようとする.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Net.Http;

namespace ConsoleApp1
{
    class Program
    {
        static void Main(string[] args)
        {
            // 取得したいWebページのURI
            Uri webUri = new Uri("https://www.valuestar.work/");

            // Call the method "GetWebPageAsync"
            Task<string> webTask = GetWebPageAsync(webUri);
            webTask.Wait(); // Mainメソッド内でawaitのかわりの待機
            string result = webTask.Result;  // content of the result 

            Console.WriteLine(result);
#if DEBUG
            Console.ReadKey();
#endif
        }

        static async Task<string> GetWebPageAsync(Uri uri)
        {
            // Forced to use TLS1.2
            System.Net.ServicePointManager.SecurityProtocol |= System.Net.SecurityProtocolType.Tls12;

            // Setting: "Do not use proxy"
            HttpClientHandler handler = new HttpClientHandler();
            handler.UseProxy = false;

            using (HttpClient client = new HttpClient(handler))
            {

                // setting timeout (optional)
                client.Timeout = TimeSpan.FromSeconds(10.0);

                try
                {
                    // Main part of this function
                    return await client.GetStringAsync(uri);
                }
                catch (HttpRequestException e)
                {
                    // Related to HTTP
                    Console.WriteLine("\nHTTP Exception");
                    Exception ex = e;
                    while (ex != null)
                    {
                        Console.WriteLine(ex.Message);
                        ex = ex.InnerException;
                    }
                }
                catch (TaskCanceledException e)
                {
                    // Timeout
                    Console.WriteLine("\nTimeout");
                    Console.WriteLine(e.Message);
                }
                catch (Exception e)
                {
                    // Others
                    Console.WriteLine(e.Message);
                }
                return null;
            }
        }
    }
}

困った問題である.http://127.0.0.1/などはループバックなのにプロキシを経由されるというほぼバグ仕様によりデバッグ中に相当苦労させられた.

≫ 続きを読む

2019/04/24 コンピュータ   TakeMe

Windows FormsのDockプロパティFillはダブルバッファリングと相性が悪い

今回は,Windows Formsのアプリケーションを作成していた.
DataBindingを設定して,更新してみていたが どうもちらつく.原因はDockプロパティだった.
「Windows FormsのDockプロパティFillはダブルバッファリングと相性が悪い」ではなく「Windows FormsのDockプロパティFillはダブルバッファリングと相性が悪いかったかも」が正しいのかもしれない.実行環境を新しくしていくと問題が消えていく...

そもそも,本題の更新時のちらつきについて話を進める前に,
WPFのデータバインディングの場合には,バックグラウンドスレッドで更新しても普通に更新がかかるのだが,Windows Formsの場合にはUIスレッドで意図的にプロパティ変更イベントを出さないといけないようだ.
さて本題だが,Windows FormsのLabelは標準でダブルバッファリングが有効になったコントロールである.
しかし,DockプロパティをFillにしているとちらつく(ことがある).
ただし,Windows 10では問題ないように見える.例えば以下のようなコードはWindows 10で問題ない(っぽい)

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Windows.Forms;

namespace WindowsFormsApp1
{
    public partial class Form1 : Form
    {
        private Timer timer = new Timer();
        private Label label = new Label();
        private Label label2 = new Label();
        private TableLayoutPanel tableLayoutPanel = new TableLayoutPanel();
        private Int64 count = 0;

        private ViewModel vm = new ViewModel();

        public Form1()
        {
            InitializeComponent();

            this.Controls.Add(tableLayoutPanel);
            tableLayoutPanel.Dock = DockStyle.Fill;
            tableLayoutPanel.ColumnCount = 2;
            tableLayoutPanel.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 50F));
            tableLayoutPanel.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 50F));
            tableLayoutPanel.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 50F));
            tableLayoutPanel.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 50F));
            tableLayoutPanel.RowCount = 2;
            tableLayoutPanel.Controls.Add(label);
            tableLayoutPanel.SetColumn(label, 0);
            tableLayoutPanel.SetRow(label, 0);

            tableLayoutPanel.Controls.Add(label2);
            tableLayoutPanel.SetColumn(label2, 1);
            tableLayoutPanel.SetRow(label2, 1);

            this.label.DataBindings.Add(new Binding("Text", this.vm, "Text1", false));
            this.label2.DataBindings.Add(new Binding("Text", this.vm, "Text2", false));

            label.Font = new Font("MS Gothic", 40);
            label.Height = 50;
            label.Text = count.ToString();
            label.TextAlign = ContentAlignment.MiddleCenter;
            label.Dock = DockStyle.Fill;

            label2.Font = new Font("MS Gothic", 40);
            label2.Height = 50;
            label2.Text = count.ToString();
            label2.TextAlign = ContentAlignment.MiddleCenter;
            label2.Dock = DockStyle.Fill;

            timer.Interval = 100;
            timer.Tick += timer_Tick;
            timer.Start();
        }

        private void timer_Tick(object sender, EventArgs e)
        {
            count++;
            this.vm.Text1 = count.ToString();
            this.vm.Text2 = (-count).ToString();
        }
    }
}
using System;
using System.ComponentModel;

namespace WindowsFormsApp1
{
    public class ViewModel : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;
        private void RaisePropertyChanged(string propertyName)
        {
            if (PropertyChanged != null)
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }

        private string _text1 = "test";
        public string Text1
        {
            set
            {
                _text1 = value;
                RaisePropertyChanged("Text1");
            }
            get
            {
                return _text1;
            }
        }

        private string _text2 = "test";
        public string Text2
        {
            set
            {
                _text2 = value;
                RaisePropertyChanged("Text2");
            }
            get
            {
                return _text2;
            }
        }
    }
}

環境によってちらつきが発生する難しいバグ発生となった.
このバグが発生する場合には「コントロールのダブルバッファリングを有効にして、ちらつきを防止する」を実施しても関係ないようだ.
難しい.

≫ 続きを読む

2019/04/14 コンピュータ   TakeMe
タグ:Windows Forms

熱電対の温度と電圧の変換式を作る2

前回の記事では温度から熱起電力を求める式と熱起電力から温度を求める関数を用意していたが,逆が遅い.

とりあえず多項式近似なら,
前回

import numpy as np
import scipy as scipy
from scipy.optimize import fmin
import matplotlib
import matplotlib.pyplot as plt
import time

def GetK_Type_T2E(t):
    return -17.600413686 + 38.921204975 * t + 0.018558770032 * t ** 2 \
        + -0.000099457592874 * t ** 3  + 0.00000031840945719 * t ** 4 \
        + -5.6072844889E-10 * t ** 5 + 5.6075059059E-13 * t ** 6 \
        + -3.2020720003E-16 * t ** 7 + 9.7151147152E-20 * t ** 8 \
        + -1.2104721275E-23 * t ** 9 \
        + 118.5976 * np.exp(-0.0001183432 * (t - 126.9686) ** 2);

def f(t, *args):
    return np.abs(GetK_Type_T2E(t) - args[0])

def GetK_Type_E2T(e):
    t = e / 38.921204975;
    res  = scipy.optimize.minimize_scalar(f, bracket=None, bounds=(t - 0.7, t + 0.7), args=(e), method='brent', tol=1e-10);
    #res  = scipy.optimize.minimize_scalar(f, bracket=None, bounds=(t - 0.7, t + 0.7), args=(e), method='golden', options={'xtol': 1e-15});
    print(res)
    return res.x;

if __name__ == '__main__':
    start = time.time()
    t = 20
    e = GetK_Type_T2E(t);
    print(t)
    e0 = GetK_Type_T2E(20)
    print(e0)
    t0 = GetK_Type_E2T(e0)
    print(t0)
    elapsed_time = time.time() - start
    print ("elapsed: {0}".format(elapsed_time) + " s")

今回

import numpy as np
import scipy as scipy
from scipy.optimize import fmin
import matplotlib
import matplotlib.pyplot as plt
import time

def GetK_Type_T2E(t):
    return -17.600413686 + 38.921204975 * t + 0.018558770032 * t ** 2 \
        + -0.000099457592874 * t ** 3  + 0.00000031840945719 * t ** 4 \
        + -5.6072844889E-10 * t ** 5 + 5.6075059059E-13 * t ** 6 \
        + -3.2020720003E-16 * t ** 7 + 9.7151147152E-20 * t ** 8 \
        + -1.2104721275E-23 * t ** 9 \
        + 118.5976 * np.exp(-0.0001183432 * (t - 126.9686) ** 2);

def GetK_Type_E2T(e):
    global w;
    return np.polyval(w, e);

if __name__ == '__main__':
    start = time.time()
    ts = np.linspace(-40, 240, num=2801);
    es = GetK_Type_T2E(ts);
    
    w = np.polyfit(es, ts, 18)
    pvts = np.polyval(w, es)

    elapsed_time = time.time() - start
    print ("elapsed: {0}".format(elapsed_time) + " s")
    
今回の方が2801点計算しているのに同じ程度の時間で処理できている.

≫ 続きを読む

2019/04/11 コンピュータ   TakeMe
タグ:Python

熱電対の温度と電圧の変換式を作る

JIS C1602 熱電対 に熱起電力の多項式近似が載っているのでそれをもとに温度-起電力の変換式を用意した.

Pythonで書いてみた.
(数値の一部桁はわざと変えてある.可能性がある)細かい数値はJISを参照していただくとして,...
変換関数自体は問題ないのだが,逆関数は載っていない.
一応 数値最適化を用いて逆関数を作ってみた.
中に,numpyを入れたのはまずかったかもしれない.

import numpy as np
import scipy as scipy
from scipy.optimize import fmin

def GetK_Type_T2E(t):
    return -17.600413686 + 38.921204975 * t + 0.018558770032 * t ** 2 \
        + -0.000099457592874 * t ** 3  + 0.00000031840945719 * t ** 4 \
        + -5.6072844889E-10 * t ** 5 + 5.6075059059E-13 * t ** 6 \
        + -3.2020720003E-16 * t ** 7 + 9.7151147152E-20 * t ** 8 \
        + -1.2104721275E-23 * t ** 9 \
        + 118.5976 * np.exp(-0.0001183432 * (t - 126.9686) ** 2);

def f(t, *args):
    return np.abs(GetK_Type_T2E(t) - args[0])

def GetK_Type_E2T(e):
    t = e / 38.921204975;
    res  = scipy.optimize.minimize_scalar(f, bracket=None, bounds=(t - 0.7, t + 0.7), args=(e), method='brent', tol=1e-10);
    #print(res)
    return res.x;

if __name__ == '__main__':

    t = 20
    e = GetK_Type_T2E(t);
    print(t)
    e0 = GetK_Type_T2E(20)
    print(e0)
    t0 = GetK_Type_E2T(e0)
    print(t0)

このやり方だと逆関数の計算が順方向の数十倍負荷がかかってしまう. もっと時間がかかるが,以下のようにした方がずれが小さくなる(かも).

res  = scipy.optimize.minimize_scalar(f, bracket=None, bounds=(t - 0.7, t + 0.7), args=(e), method='golden', options={'xtol': 1e-15});

≫ 続きを読む

2019/04/06 コンピュータ   TakeMe
タグ:Python