im trying to link my arduino data into my speedometer widget in kivy
Question:
Im trying to link my arduino speed data to my speedometer on kivy. For example, when my speed in the arduino serial monitor is 20.5, i want the needle of my speedometer to point at that value(angle). Right now, i just set the needle to go from left(-90 deg) to right(90 deg) continuously.
Speedometer needle moving from -90deg to 90 deg
.py file
import threading
import serial
from kivy.animation import Animation
from kivy.clock import Clock, mainthread
from kivy.lang import Builder
from kivy.properties import StringProperty
from kivy.uix.screenmanager import Screen, ScreenManager
from kivy.app import App
class SpeedWindow(Screen):
speed_text = StringProperty("")
def __init__(self, **kwargs):
super(SpeedWindow, self).__init__(**kwargs)
threading.Thread(target=self.tm).start()
def tm(self):
while (1):
with serial.Serial('COM4', 9600) as ser:
value = ser.readline()
ser.close()
self.update_fix(value.decode('utf-8'))
@mainthread
def update_fix(self, value):
self.speed_text = value
class WindowManager(ScreenManager):
pass
KV = """
WindowManager:
SpeedWindow:
<SpeedWindow>:
angle: 90
name: 'speedometer'
Image:
source: 'cadran.png'
size_hint: None, None
size: 400, 400
pos_hint: {'center_x': 0.5, 'center_y': 0.5}
Image:
source: 'needle.png'
size_hint: None, None
size: 170, 170
pos_hint: {'center_x': 0.5, 'center_y': 0.5}
# apply rotation matrix to this Image
canvas.before:
PushMatrix
Rotate:
angle: root.angle
axis: (0, 0, 1)
origin: (self.center_x, self.center_y , 0)
canvas.after:
PopMatrix
"""
class MyMainApp(App):
def build(self):
Clock.schedule_once(self.animate_needle, 1.0) # start the animation in 2 seconds
return Builder.load_string(KV)
def animate_needle(self, dt):
# animate the needle from +90 to -90 and then back to +90
self.anim = Animation(angle=-90.0) + Animation(angle=90)
self.anim.repeat = True # repeat forever
speedometer = self.root.get_screen('speedometer')
self.anim.start(speedometer)
if __name__ == "__main__":
MyMainApp().run()
Answers:
I think you can just remove the animate_needle()
method and change your update_fix()
method to calculate an appropriate angle:
@mainthread
def update_fix(self, value):
self.speed_text = value
self.angle = 90.0 - 180.0 * float(value)/100.0
The formula simply gives 90
when the value is 0
and -90
when the value is 100
, and interpolates in between.
I am facing a similar problem. I want to have a smooth moving needle between the different serial or socket inputs. If I only use the def update_fix the needle is jumping hardly from one input to another input. That is not the sense of animations in kivy.
The code must be such, that after the needle reached the point, the next value need to be smoothly driven within one second or a half second.
If I use the animation + animation method, the kivy plays only with the before given input and does not update the value.
Im trying to link my arduino speed data to my speedometer on kivy. For example, when my speed in the arduino serial monitor is 20.5, i want the needle of my speedometer to point at that value(angle). Right now, i just set the needle to go from left(-90 deg) to right(90 deg) continuously.
Speedometer needle moving from -90deg to 90 deg
.py file
import threading
import serial
from kivy.animation import Animation
from kivy.clock import Clock, mainthread
from kivy.lang import Builder
from kivy.properties import StringProperty
from kivy.uix.screenmanager import Screen, ScreenManager
from kivy.app import App
class SpeedWindow(Screen):
speed_text = StringProperty("")
def __init__(self, **kwargs):
super(SpeedWindow, self).__init__(**kwargs)
threading.Thread(target=self.tm).start()
def tm(self):
while (1):
with serial.Serial('COM4', 9600) as ser:
value = ser.readline()
ser.close()
self.update_fix(value.decode('utf-8'))
@mainthread
def update_fix(self, value):
self.speed_text = value
class WindowManager(ScreenManager):
pass
KV = """
WindowManager:
SpeedWindow:
<SpeedWindow>:
angle: 90
name: 'speedometer'
Image:
source: 'cadran.png'
size_hint: None, None
size: 400, 400
pos_hint: {'center_x': 0.5, 'center_y': 0.5}
Image:
source: 'needle.png'
size_hint: None, None
size: 170, 170
pos_hint: {'center_x': 0.5, 'center_y': 0.5}
# apply rotation matrix to this Image
canvas.before:
PushMatrix
Rotate:
angle: root.angle
axis: (0, 0, 1)
origin: (self.center_x, self.center_y , 0)
canvas.after:
PopMatrix
"""
class MyMainApp(App):
def build(self):
Clock.schedule_once(self.animate_needle, 1.0) # start the animation in 2 seconds
return Builder.load_string(KV)
def animate_needle(self, dt):
# animate the needle from +90 to -90 and then back to +90
self.anim = Animation(angle=-90.0) + Animation(angle=90)
self.anim.repeat = True # repeat forever
speedometer = self.root.get_screen('speedometer')
self.anim.start(speedometer)
if __name__ == "__main__":
MyMainApp().run()
I think you can just remove the animate_needle()
method and change your update_fix()
method to calculate an appropriate angle:
@mainthread
def update_fix(self, value):
self.speed_text = value
self.angle = 90.0 - 180.0 * float(value)/100.0
The formula simply gives 90
when the value is 0
and -90
when the value is 100
, and interpolates in between.
I am facing a similar problem. I want to have a smooth moving needle between the different serial or socket inputs. If I only use the def update_fix the needle is jumping hardly from one input to another input. That is not the sense of animations in kivy.
The code must be such, that after the needle reached the point, the next value need to be smoothly driven within one second or a half second.
If I use the animation + animation method, the kivy plays only with the before given input and does not update the value.