Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixed steering wheel range #24

Merged
merged 7 commits into from
Dec 27, 2023
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file modified img/steering_wheel.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
49 changes: 4 additions & 45 deletions resource/steering_wheel.ui
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,11 @@
</property>
<widget class="QTextEdit" name="max_value">
<property name="enabled">
<bool>false</bool>
<bool>true</bool>
</property>
<property name="geometry">
<rect>
<x>330</x>
<x>230</x>
<y>460</y>
<width>51</width>
<height>31</height>
Expand Down Expand Up @@ -76,51 +76,10 @@ p, li { white-space: pre-wrap; }
<string>Topic:</string>
</property>
</widget>
<widget class="QTextEdit" name="min_value">
<property name="enabled">
<bool>false</bool>
</property>
<property name="geometry">
<rect>
<x>140</x>
<y>460</y>
<width>51</width>
<height>31</height>
</rect>
</property>
<property name="html">
<string>&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt;
&lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt;
p, li { white-space: pre-wrap; }
&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:'Ubuntu'; font-size:11pt; font-weight:400; font-style:normal;&quot;&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;-45&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="placeholderText">
<string/>
</property>
</widget>
<widget class="QLabel" name="min_value_label">
<property name="geometry">
<rect>
<x>60</x>
<y>460</y>
<width>81</width>
<height>31</height>
</rect>
</property>
<property name="font">
<font>
<pointsize>12</pointsize>
</font>
</property>
<property name="text">
<string>Min Angle:</string>
</property>
</widget>
<widget class="QLabel" name="max_value_label">
<property name="geometry">
<rect>
<x>240</x>
<x>140</x>
<y>466</y>
<width>81</width>
<height>21</height>
Expand All @@ -132,7 +91,7 @@ p, li { white-space: pre-wrap; }
</font>
</property>
<property name="text">
<string>Max Angle:</string>
<string>Angle:</string>
</property>
</widget>
<widget class="TopicQLineEdit" name="topic_to_subscribe">
Expand Down
12 changes: 6 additions & 6 deletions src/rqt_gauges_2/speedometer_gauge.py
Original file line number Diff line number Diff line change
Expand Up @@ -149,9 +149,9 @@ def setMinValue(self, min_value):
# Modifies the minimum value of the gauge
# Args:
# min: Value to update the minimum value of the gauge.
if self.value < min:
self.value = min
if min >= self.maxValue:
if self.value < min_value:
self.value = min_value
if min_value >= self.maxValue:
self.minValue = self.maxValue - 1
else:
self.minValue = min_value
Expand All @@ -162,9 +162,9 @@ def setMaxValue(self, max_value):
# Modifies the maximum value of the gauge
# Args:
# max: Value to update the maximum value of the gauge.
if self.value > max:
self.value = max
if max <= self.minValue:
if self.value > max_value:
self.value = max_value
if max_value <= self.minValue:
self.maxValue = self.minValue + 1
else:
self.maxValue = max_value
Expand Down
69 changes: 9 additions & 60 deletions src/rqt_gauges_2/speedometer_widget.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,64 +7,7 @@
from rosidl_runtime_py.utilities import get_message
from rqt_py_common.topic_completer import TopicCompleter


def get_topic_type(node, topic):
"""
Subroutine for getting the topic type.

(nearly identical to rostopic._get_topic_type, except it returns rest of name instead of fn)

:returns: topic type, real topic name, and rest of name referenced
if the topic points to a field within a topic, e.g. /rosout/msg, ``str, str, str``
"""
val = node.get_topic_names_and_types()
matches = [(t, t_types) for t, t_types in val if t == topic or topic.startswith(t + '/')]
for t, t_types in matches:
for t_type in t_types:
if t_type == topic:
return t_type, None, None
for t_type in t_types:
if t_type != '*':
return t_type, t, topic[len(t):]
return None, None, None


def _array_eval(field_name, slot_num):
"""
Array evaluation.

:param field_name: name of field to index into, ``str``
:param slot_num: index of slot to return, ``str``
:returns: fn(msg_field)->msg_field[slot_num]
"""
def fn(f):
return getattr(f, field_name).__getitem__(slot_num)
return fn


def _field_eval(field_name):
"""
Field evaluation.

:param field_name: name of field to return, ``str``
:returns: fn(msg_field)->msg_field.field_name
"""
def fn(f):
return getattr(f, field_name)
return fn


def generate_field_evals(fields):
evals = []
fields = [f for f in fields.split('/') if f]
for f in fields:
if '[' in f:
field_name, rest = f.split('[')
slot_num = int(rest[:rest.find(']')])
evals.append(_array_eval(field_name, slot_num))
else:
evals.append(_field_eval(f))
return evals
from .utils import generate_field_evals, get_topic_type


class SpeedometerWidget(QWidget):
Expand Down Expand Up @@ -129,7 +72,7 @@ def updateSubscription(self):
topic_path = self.topic_to_subscribe.text()
topic_type, topic_name, fields = get_topic_type(self.node, topic_path)
self.field_evals = generate_field_evals(fields)
if topic_type is not None:
if topic_type is not None and self.field_evals is not None:
print('Subscribing to:', topic_name, 'Type:', topic_type, 'Field:', fields)
data_class = get_message(topic_type)
self.sub = self.node.create_subscription(
Expand All @@ -142,4 +85,10 @@ def speedometer_callback(self, msg):
value = msg
for f in self.field_evals:
value = f(value)
self.speedometer_gauge.updateValue(float(value))
if value is not None:
if type(value) == int or type(value) == float or type(value) == str:
self.speedometer_gauge.updateValue(float(value))
else:
self.speedometer_gauge.updateValue(self.speedometer_gauge.minValue)
else:
self.speedometer_gauge.updateValue(self.speedometer_gauge.minValue)
19 changes: 17 additions & 2 deletions src/rqt_gauges_2/steering_wheel_gauge.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ def __init__(self, parent=None):
self.progress_width = 25
self.progress_rounded_cap = True
self.progress_color = 0x39F030
self.max_value = 45
self.circle_max_angle = 135
self.font_size = 40
self.scale_font_size = 15
Expand Down Expand Up @@ -98,8 +97,24 @@ def updateValue(self, value: float):
# value: Value to update the gauge with.
value = max(value, self.minValue)
value = min(value, self.maxValue)
self.value = value
self.repaint()

def setMaxValue(self, max_value):
# Modifies the maximum value of the gauge
# Args:
# max: Value to update the maximum value of the gauge.
if self.value > max_value:
self.value = max_value
if max_value <= self.minValue:
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just checking, min_value and max_value cannot be the same?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, then we can create a symmetric steering wheel

self.maxValue = self.minValue + 1
self.minValue = -self.maxValue + 1
else:
self.maxValue = max_value
self.minValue = -max_value

self.update()

def draw_background_circle(self):
painter = QPainter()
painter.begin(self)
Expand All @@ -114,7 +129,7 @@ def paintEvent(self, event):
width = self.width - self.progress_width
height = self.height - self.progress_width
margin = int(self.progress_width / 2)
value = int(self.value * self.circle_max_angle / self.max_value)
value = int(self.value * self.circle_max_angle / self.maxValue)

# Draw Circle
self.draw_background_circle()
Expand Down
83 changes: 23 additions & 60 deletions src/rqt_gauges_2/steering_wheel_widget.py
Original file line number Diff line number Diff line change
@@ -1,70 +1,13 @@
import os

from ament_index_python.resources import get_resource
from PyQt5.QtCore import pyqtSlot
from PyQt5.QtCore import pyqtSlot, Qt
from PyQt5.QtWidgets import QWidget
from python_qt_binding import loadUi
from rosidl_runtime_py.utilities import get_message
from rqt_py_common.topic_completer import TopicCompleter


def get_topic_type(node, topic):
"""
Subroutine for getting the topic type.

(nearly identical to rostopic._get_topic_type, except it returns rest of name instead of fn)

:returns: topic type, real topic name, and rest of name referenced
if the topic points to a field within a topic, e.g. /rosout/msg, ``str, str, str``
"""
val = node.get_topic_names_and_types()
matches = [(t, t_types) for t, t_types in val if t == topic or topic.startswith(t + '/')]
for t, t_types in matches:
for t_type in t_types:
if t_type == topic:
return t_type, None, None
for t_type in t_types:
if t_type != '*':
return t_type, t, topic[len(t):]
return None, None, None


def _array_eval(field_name, slot_num):
"""
Array Evaluation.

:param field_name: name of field to index into, ``str``
:param slot_num: index of slot to return, ``str``
:returns: fn(msg_field)->msg_field[slot_num]
"""
def fn(f):
return getattr(f, field_name).__getitem__(slot_num)
return fn


def _field_eval(field_name):
"""
Field evaluation.

:param field_name: name of field to return, ``str``
:returns: fn(msg_field)->msg_field.field_name
"""
def fn(f):
return getattr(f, field_name)
return fn


def generate_field_evals(fields):
evals = []
fields = [f for f in fields.split('/') if f]
for f in fields:
if '[' in f:
field_name, rest = f.split('[')
slot_num = int(rest[:rest.find(']')])
evals.append(_array_eval(field_name, slot_num))
else:
evals.append(_field_eval(f))
return evals
from .utils import generate_field_evals, get_topic_type


class SteeringWheelWidget(QWidget):
Expand All @@ -87,8 +30,22 @@ def __init__(self, node):
self._topic_completer.update_topics(self.node)
self.topic_to_subscribe.setCompleter(self._topic_completer)

# Objects Properties
self.max_value.setAlignment(Qt.AlignCenter)

self.max_value.setPlaceholderText(str(self.steering_wheel_gauge.maxValue))

self.max_value.textChanged.connect(self.updateMaxValue)
self.subscribe_button.pressed.connect(self.updateSubscription)

@pyqtSlot()
def updateMaxValue(self):
new_max_value = self.max_value.toPlainText()
if new_max_value.isnumeric():
self.steering_wheel_gauge.setMaxValue(int(new_max_value))
else:
self.steering_wheel_gauge.setMaxValue(45)

@pyqtSlot()
def updateSubscription(self):
if self.node.destroy_subscription(self.sub):
Expand All @@ -111,4 +68,10 @@ def steering_wheel_callback(self, msg):
value = msg
for f in self.field_evals:
value = f(value)
self.steering_wheel_gauge.updateValue(float(value))
if value is not None:
if type(value) == int or type(value) == float or type(value) == str:
self.steering_wheel_gauge.updateValue(float(value))
else:
self.steering_wheel_gauge.updateValue(0)
else:
self.steering_wheel_gauge.updateValue(0)
Loading
Loading