Go Down

Topic: Arduino with WebUSB (and ajax) (Read 157 times) previous topic - next topic

bourginj

Dear all,

I am trying to make an Arduino Leonardo and a web page communicate. This web page is built within the Django framework.

Thanks to the Arduino, I want to fill several forms, which will be sent through AJAX (which allows the communication with the Arduino to continue from one form to another).

My code works perfectly fine on Windows 10, but on Linux (Ubuntu 18.04), I ran into strange issues (tried on Chrome Version 85.0.4183.102 (Build officiel) (64 bits)).

To fill one form (after connecting to the Arduino during the first one), I:
  • click on a button named caliperButton in the ino file
  • click on a button named estimatorButton in the ino file, which triggers the submit button in javascript


And so on.

On Linux, if I fill my forms without ever disconnecting from the Arduino, it works fine.

But if I fill one form, then disconnect from the Arduino, and reconnect to it, when I click on the caliperButton, I have to click three times on it before it works as expected.
The first time, nothing happens.
The second time, the fonction sendCaliperButtonSignal() (mentioned in the ino file) is executed correctly, but then the message sent from the web page to the Arduino in response to the button press is not considered.
The third time, finally everything works as expected.
If I continue without disconnecting the Arduino again, it works fine again. But if I disconnect the Arduino and reconnect it again, the strange behavior reappears.

You will find below the two main scripts I use in my web page.

The one managing communication with the arduino :

Code: [Select]
<script type="text/javascript">
    // Get the device
    serial.requestPort = function() {
      // Return the serial port of the board (0x2341 is for showing only Arduino)
      return navigator.usb.requestDevice({filters: [{vendorId: 0x2341}]})
        .then(device => new serial.Port(device));
    }

    var port;
    // Get the connection link
    // Initialize the decoder for the data from the board
    var textDecoder = new TextDecoder();
    // Initialize the decoder for the data from the board
    var textEncoder = new TextEncoder("utf-8");
    var realGap = {{ current_gap.value }}/10

    // Add an event listener to the connection link
    $(function(){
        $('#connectLink').click(function(e) {
      // If the port exist then disconnect !
      if (port) {
        turnOffCaliper();
      // If the port does not exist, connect to the board and receive data
      } else {
        // then request for a port

        serial.requestPort().then(selectedPort => {
          port = selectedPort
          var waitGap = false;
          // connect promise
          port.connect().then(() => {
            // The first port.send works when done two times but not once.
            var d1 = new Date();
            console.log("Connected!");
            this.value = "Disconnect";
            // Get the data from the board and show it
            port.onReceive = data => {
                var msg = textDecoder.decode(data);
                console.log(msg);
                if (msg.includes('"caliperConnected": "false"')){
                    port.disconnect();
                    this.value = "Connect";
                    port = null;
                }
                if (msg.includes('{"caliperButton": "on"}')){
                    var d1 = new Date();
                    var measurePointText = '{"caliperLED": "off", "realGap":' + realGap + ', "timestamp":"' + d1.toISOString() + '", "estimatorOrigin": "on"}';
                    console.log(measurePointText);
                    port.send(textEncoder.encode(measurePointText)).catch(error => {
                        console.log('Error: ' + error);
                    });
                    waitGap = true;
                }
                if (waitGap && msg.includes('estimatedGap')){
                    var msg_parsed = JSON.parse(msg);
                    document.getElementById("id_estimate").value = msg_parsed.estimatedGap;
                    // port.disconnect()
                    $("#submit-id-save").click()
                    waitGap = false;

                }
            }
            port.onReceiveError = error => {console.log('Receive error: ' + error)}

          }, error => {console.log('Connection error: ' + error)})
        }).catch(error => {console.log('requestPort error : ' + error)})
      }
    })});
</script>


The one managing ajax requests when the form is submitted :

Code: [Select]
<script type="text/javascript">
    $(document).on('submit', '#examform', function (e){
        e.preventDefault();
        $.ajax({
            url: "{% url 'exam_edit' patient_id exam_id %}",
            data: {
                estimate:$('#id_estimate').val(),
                realValue:$('#id_realValue').val(),
                bodyPart:$('#id_bodyPartValue').val(),
                gap:$('#id_gapValue').val(),
                csrfmiddlewaretoken:$('input[name=csrfmiddlewaretoken]').val(),
            },
            type: 'POST',
            success: function (data) {
                console.log("Saved !");
                if (data.response == 'finish'){
                    console.log('finish');
                    turnOffCaliper();
                    setTimeout(() => {window.location.href = "{% url 'exam_home' patient_id %}";}, 2000);
                }else{
                    // var realGap = realValue/10;
                    $('#id_estimate').val('');
                    $('#id_realValue').val(data.realValue/10);
                    $('#trials_table').html(data.new_table);
                    $('#id_bodyPartValue').val(data.current_point_id);
                    $('#id_gapValue').val(data.current_gap_id);
                    realGap = data.realValue/10;
                    $('area').attr('coords', data.current_pointX.toString()+', '+ data.current_pointY.toString()+', 10');
                    $('.map').maphilight();
                    var caliperText = '{"caliperLED":"on"}';
                    port.send(textEncoder.encode(caliperText)).catch(error => {
                        console.log('Error: ' + error);
                    });
                }
                },
            error: function() {
                console.log("Error on save !")
            },
        })
    });
</script>


You will also find attached the .ino file loaded on the Arduino.

Do you have an idea of what I am doing wrong here ?

Please let me know if you need further details.

Thanks a lot for your help.

Best,
Jessica

bourginj

I forgot to add this javascript function, which I call whenever I want to disconnect from the arduino :

Code: [Select]
<script type="text/javascript">
    function turnOffCaliper(){
        if (port){
            var caliperText = '{"caliperLED":"off", "caliperConnected": "false"}';
            port.send(textEncoder.encode(caliperText)).catch(error => {
                console.log('Error: ' + error);
            });
            console.log(caliperText);
        }
    }
</script>


Thanks for your help.

Jessica

bourginj

Dear all,

I found a way around using avr/wdt.h, similarly to what is done here: https://forum.arduino.cc/index.php?topic=582234.0.

Each time I disconnect, I reset the Arduino. This way, the issue does not show anymore (even though I don't understand why it did before).

You will find attached the modified .ino file.

Best,
Jessica

Go Up