1

編集#2:だから何だと思いますか、私はもうすぐそこにいます!プログラミングに関する限り、私は最後の問題と思われるものに直面しています。これは実際には非常に興味深いことです。問題は、次のコード、私の JavaScript 関数にあります。私は通常、非常に簡単に解決できると思われる問題について投稿することはありませんが、ここで何が起こっているのか本当にわかりません。

問題は、更新機能の最初の状態にあるようです。alert('hey'); という行を参照してください。? その行を消去すると、なんらかの理由でアクション関数に何も送信されません。Arduinoやコンソールにも...何も起こりません。私がそれを呼ぶのが好きなように、それは絶対に魅力的です。何も思いつきません。おそらく、alert() が arduino の出力を読み取るために必要な何らかの遅延を作成したのではないかと思いましたが、setTimeout で遅延を作成しても、何も起こりません。それは信じられないです。

もう一度だけ: アラートがなければ、アクション関数は呼び出されません。関数が呼び出された場合に何かを出力するようにして確認しました。何も印刷されません。呼ばれていないだけです。しかし、アラートを使用すると、関数が呼び出され、arduino が LED をオンにします。

説明はありますか?これが私のコードです:

function update(command=0) {
// if command send it
if (command!=0) {
    $.getJSON('/action?command='+command);
    alert('hey');
}

// read no matter what
$.getJSON('/read', {}, function(data) {
    if (data.state != 'failure' && data.content != '') {
        $('.notice').text(data.content);
        $('.notice').hide().fadeIn('slow');
        setTimeout(function () { $('.notice').fadeOut(1000); }, 1500);
    }
    setTimeout(update, 5000);
});
}

update();

Arduino を制御するために、任意のコンピューターからアクセスできる Web インターフェイスを作成しようとしています。私は近づいています。私の問題の 1 つは、次のコードを使用して、ボタンを押して Arduino にコマンドを送信すると、Arduino がそれを取得し ( LEDが設定どおりに点滅します)、メッセージを送信し、Pythonスクリプトが取得することです。データは表示されますが、正しく表示されません。文字列に一部の文字が欠落しておりindex.html、期待どおりに返されません。

基本的に、ボタンが押されると関数が呼び出され、結果が生成された関数とは別の関数で関数の結果を返す必要があります。

コードは次のとおりです。

# -*- coding: utf-8 -*-

import cherrypy, functools, json, uuid, serial, threading, webbrowser, time

try:
    ser = serial.Serial('COM4', 9600)
    time.sleep(2)
    ser.write('1')
except:
    print('Arduino not detected. Moving on')

INDEX_HTML = open('index.html', 'r').read()

def timeout(func, args = (), kwargs = {}, timeout_duration = 10, default = None):
    class InterruptableThread(threading.Thread):
        def __init__(self):
            threading.Thread.__init__(self)
            self.result = default
        def run(self):
            self.result = func(*args, **kwargs)

    it = InterruptableThread()
    it.start()
    it.join(timeout_duration)
    if it.isAlive():
        return it.result
    else:
        return it.result

def get_byte(useless):
    return ser.read().encode('Utf-8')

def json_yield(command):
    @functools.wraps(command)
    def _(self, command):
        if (command == 'Turn the LED on'):
            ser.write('2')
            time.sleep(2)
            print('wrote to port')
        print('ok, ok')
        try:
            m = ''
            while 1:
                print('reading...')
                byte = timeout(get_byte, ('none',), timeout_duration = 5)
                if byte == '*' or byte == None: break
                m = m + byte
            content = m
            time.sleep(1)
            return json.dumps({'state': 'ready', 'content':content})
        except StopIteration:
            return json.dumps({'state': 'done', 'content': None})
    return _

class DemoServer(object):
    @cherrypy.expose
    def index(self):
        return INDEX_HTML

    @cherrypy.expose
    @json_yield
    def yell(self):
        yield 'nothing'

    @cherrypy.expose
    @json_yield
    def command(self):
        yield 'nothing'

if __name__ == '__main__':
    t = threading.Timer(0.5, webbrowser.open, args=('http://localhost:8080',))
    t.daemon = True
    t.start()
    cherrypy.quickstart(DemoServer(), config='config.conf')
4

1 に答える 1

1

まず第一に、私はあなたの前の質問でそれについてあなたに話すことを考えていませんでしたが、しばらく前に私はpyalerと呼ばれるソフトウェアを書きました. ?) wsgi の制限)。

あなたの質問に答えるために、フォームをアクションを送信する JavaScript クエリにして、結果を解析して現在のページを結果で更新できる JSON として取得してみませんか? それははるかにエレガントでシンプルで、2013...

悲しいことに、あなたのコードを考えると、なぜ結果が得られないのか、私には本当にわかりません。やりたいことを本当に実行できるかどうかを理解するには、あまりにも洗練されすぎています... KISS!

モジュール スコープで何かを行うことは避けてください。ただし、モジュールを に配置する場合if __name__ == "__main__"、またはモジュールをインポートして拡張する必要がある場合は、付随的にいくつかのコードを実行し、コードのより良い設計を強制する場合を除きます。

InterruptableThread()タイムアウト関数からクラスを取り出して、パラメーターとして渡すことができdefaultます。InterruptableThread(default)def __init__(self, default): self.result = default。しかし、その部分について言えば、シリアル接続を作成するときに使用できるtimeout引数があるのに、なぜそのような洗練された操作を行うのでしょうか?

コードに少し変更を加えると、次のようになります。

# -*- coding: utf-8 -*-

import cherrypy, functools, json, uuid, serial, threading, webbrowser, time

def arduino_connect(timeout=0):
    try:
        ser=serial.Serial('COM4', 9600, timeout=timeout)
        time.sleep(2)
        ser.write('1')
        return ser
    except:
        raise Exception('Arduino not detected. Moving on')

class ArduinoActions(object):
    def __init__(self, ser):
        self.ser = ser

    def get_data(self):
        content = ""
        while True:
            print('reading...')
            data = self.ser.read().encode('utf-8')
            if not data or data == '*':
                return content
            content += data

    def turn_led_on(self):
        ser.write('2')
        time.sleep(2)
        print('wrote led on to port')

    def turn_led_off(self):
        ser.write('2') # Replace with the value to tur the led off
        time.sleep(2) 
        print('wrote to led off port')

class DemoServer(ArduinoActions):
    def __init__(self, ser):
        ArduinoActions.__init__(self, ser)
        with open('index.html', 'r') as f:
            self.index_template = f.read()

    @cherrypy.expose
    def index(self):
        return self.index_template

    @cherrypy.expose
    def action(self, command):
        state = 'ready'
        if command == "on":
            content = self.turn_led_on()
        elif command == "off":
            content = self.turn_led_off()
        else:
            content = 'unknown action'
            state = 'failure'
        return {'state': state, 'content': content}

    @cherrypy.expose
    def read(self):
        content = self.get_data()
        time.sleep(1)
        # set content-type to 'application/javascript'
        return content

if __name__ == '__main__':
    ser = arduino_connect(5)
    # t = threading.Timer(0.5, webbrowser.open, args=('http://localhost:8080',))
    # t.daemon = True
    # t.start()
    cherrypy.quickstart(DemoServer(), config='config.conf')

yellJavaScript コードでは、文字通り何も返さないリソースを呼び出しています。actionメソッド (指定された python コードを変更したため) と別のメソッドを作成することをお勧めしますread()。したがって、actionメソッドはバイトを書き込むことによってarduinoに作用し、arduinoにコマンドを送信し、 readメソッドは出力を読み取ります。

Web サーバーはシリアル オブジェクトの読み取り/書き込みメソッドへの並列呼び出しを作成する可能性があり、同じオブジェクトを並列で読み取ることはできないため、から継承する新しいクラスを作成することにより、独立したスレッドを作成することをthreading.Threadお勧めします。シリアルの出力を読み取る無限ループ (シリアル オブジェクトをそのクラスの__init__関数のパラメーターとして指定することにより)。次に、以前のすべてのデータのログを保持する場合は、新しいcontentデータをそれぞれ にプッシュします。最後の測定値のみを返す場合は、 にプッシュします。次に、 メソッドで、arduino からの新しい読み取りとともに成長するものを返す必要があるだけです。したがって、すべてのデータのログを作成します (または、キューがある場合は最後のデータを取得します)。listQueue.QueueArduinoActionsread()list

$(function() {
    function update(command) {
        // if you give a command argument to the function, it will send a command
        if (command) {
            $.getJSON('/action?command='+command);
        }
        // then it reads the output
        $.getJSON('/read, {}, function(data) {
        if (data.state !== 'failure' && data.content !== '') {
            $('.notice').text(data.content);
            $('.notice').hide().fadeIn('fast');
            setTimeout(function () { $('.notice').fadeOut('fast'); }, 1500);
        }
        // and rearms the current function so it refreshes the value
        setTimeout(update(), 2); // you can make the updates less often, you don't need to flood your webserver and anyway the arduino reading are blocking
    });
}
update();
});

タイプが強制されないように、javascript では常に===orを使用します。!==関数を再度呼び出す頻度を減らすことができます。JavaScript 引数を評価しない場合、デフォルトでは undefined に設定されます。

それはあなたが書いたもののほんの少しの更新です。今では遅くなっているので、それから何か良いものを作ってくれることを願っています!

HTH

于 2013-06-20T17:06:00.443 に答える