Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

QML Canvas animation breaks QModbus communication



  • I'm working on a custom Qt QML application that needs to communicate with a QModbus client. In this particular case, I'm testing with the Qt Modbus Slave example.

    At the application startup, the communication is initialized and it starts writing five registers every second. Everything works flawlessly until, in the main application, a QML canvas animation starts; after some milliseconds QModbus warnings are printed in the application output console:

    [    13.260 W qt.modbus] unknown:0 - (RTU client) Cannot match response with open request, ignoring
    [    15.261 W qt.modbus] unknown:0 - (RTU client) Cannot match response with open request, ignoring
    

    and it keeps popping out until the animation stops.

    This is the animation code:

    onModeChanged: canvas.requestPaint()
    
        onAnimationActiveChanged: {
            if (animationActive) {
                animation.start()
            } else {
                animation.stop()
            }
        }
    
        Canvas {
            id: canvas
            anchors.fill: parent
            visible: animationActive
    
            property int lineWidth: 24
            property double position: 0
            property string indicatorColor: cleaning ? palette.cleaningIndicator : palette.white
            property real xScale: panelScale
            onPaint: {
                var ctx = getContext("2d")
                var x = width / 2
                var y = height / 2
                var radius = (width / 2) - lineWidth
                var start = Math.PI * (position - 1.5)
                var end = Math.PI * position
                ctx.reset()
                ctx.scale(xScale, 1)
    
                ctx.beginPath()
                ctx.moveTo(0, height / 2)
                ctx.lineTo(0, height)
                ctx.lineTo(width, height)
                ctx.lineTo(width, height / 2)
                ctx.closePath()
                ctx.clip()
    
                ctx.beginPath()
                ctx.arc(x, y, radius, start, end, true)
                var grd = ctx.createLinearGradient(x + radius * Math.cos(start),
                                                   y + radius * Math.sin(start),
                                                   x + radius * Math.cos(end),
                                                   y + radius * Math.sin(end))
                grd.addColorStop(0.00, "transparent")
                grd.addColorStop(1.00, indicatorColor)
                ctx.lineWidth = lineWidth
                ctx.strokeStyle = grd
                ctx.stroke()
    
                ctx.beginPath()
                ctx.arc(x + radius * Math.cos(end), y + radius * Math.sin(end),
                        lineWidth / 2, 0, Math.PI * 2, false)
                ctx.fillStyle = indicatorColor
                ctx.fill()
    
                start = Math.PI * (position - 0.5)
                end = Math.PI * (position + 1)
    
                ctx.beginPath()
                ctx.arc(x, y, radius, start, end, true)
                grd = ctx.createLinearGradient(x + radius * Math.cos(
                                                   start), y + radius * Math.sin(
                                                   start), x + radius * Math.cos(
                                                   end), y + radius * Math.sin(end))
                grd.addColorStop(0.00, "transparent")
                grd.addColorStop(1.00, indicatorColor)
                ctx.lineWidth = lineWidth
                ctx.strokeStyle = grd
                ctx.stroke()
    
                ctx.beginPath()
                ctx.arc(x + radius * Math.cos(end), y + radius * Math.sin(end),
                        lineWidth / 2, 0, Math.PI * 2, false)
                ctx.fillStyle = indicatorColor
                ctx.fill()
            }
            onPositionChanged: canvas.requestPaint()
        }
    
        RotationAnimation {
            id: animation
            running: animationActive
            target: canvas
            property: "position"
            duration: 10000
            from: 2
            to: 0
            easing.type: Easing.Linear
            onStopped: {
                if (animationActive) {
                    animation.start()
                } else {
                    animation.stop()
                }
            }
        }
    

    I'm using Qt 5.12.6 Linux desktop. I noticed that using Qt 5.14.0 the problem doesn't appear, but since the application needs to run on a custom Linux board changes Qt is really expansive now.

    Side note: I had to make this custom canvas/animation to create a sort of spinning circular crown and this is the only way that I'm achieving what I want.

    Any suggestions about this problem?


  • Moderators

    @Rcc21
    doesn't surprise me, the QModbus implementation in 5.12 is buggy af

    Try setting the reties to 0 and/or move your Modbus communication into its own thread



  • @J-Hilk
    Thanks for the answer.
    The communication is already in a different thread. Setting retries to 0 didn't help.


  • Moderators

    @Rcc21

    2 questions:

    • Are you sure your threading is done right ? Have to ask, all to often it's actually not threaded at all
    • Have you set a priority to the Modbus-thread?


  • @J-Hilk

    • I'm pretty sure the threading is correct; I've followed the worker threads pattern.
    • I didn't set the priority, but after your answer, I tried both QThread::HighestPriority and QThread::TimeCriticalPriority, but still not working.

  • Moderators

    @Rcc21
    well, I'm close to out of ideas 🙈

    Have you tried 12.5 ? The private headers changed a lot between 12.5 & 12.6

    I would suggest maybe opening a bug report otherwise and while that is running Subclassing QQuickPaintedItem and doing the drawing in there may result in a significant performance boost, that could also solve your issue



  • @J-Hilk

    A colleague of mine tried the 5.12.4, but the error is still there. I'll try with the QQuickPaintedItem or I'll switch to the 5.14.

    Thanks for your time.