diff --git a/.idea/runConfigurations.xml b/.idea/runConfigurations.xml
deleted file mode 100644
index 7f68460d..00000000
--- a/.idea/runConfigurations.xml
+++ /dev/null
@@ -1,12 +0,0 @@
-
-
-
-
-
-
\ No newline at end of file
diff --git a/app/src/main/java/com/schneewittchen/rosandroid/widgets/button/ButtonData.java b/app/src/main/java/com/schneewittchen/rosandroid/widgets/button/ButtonData.java
index 04894eaa..1428f513 100644
--- a/app/src/main/java/com/schneewittchen/rosandroid/widgets/button/ButtonData.java
+++ b/app/src/main/java/com/schneewittchen/rosandroid/widgets/button/ButtonData.java
@@ -1,5 +1,7 @@
package com.schneewittchen.rosandroid.widgets.button;
+import android.util.Log;
+
import com.schneewittchen.rosandroid.model.entities.widgets.BaseEntity;
import com.schneewittchen.rosandroid.model.repositories.rosRepo.node.BaseData;
@@ -28,6 +30,7 @@ public ButtonData(boolean pressed) {
@Override
public Message toRosMessage(Publisher publisher, BaseEntity widget) {
+ Log.d("name", widget.name);
std_msgs.Bool message = (Bool) publisher.newMessage();
message.setData(pressed);
return message;
diff --git a/app/src/main/java/com/schneewittchen/rosandroid/widgets/button/ButtonView.java b/app/src/main/java/com/schneewittchen/rosandroid/widgets/button/ButtonView.java
index 1fb54780..626d93f9 100644
--- a/app/src/main/java/com/schneewittchen/rosandroid/widgets/button/ButtonView.java
+++ b/app/src/main/java/com/schneewittchen/rosandroid/widgets/button/ButtonView.java
@@ -11,6 +11,8 @@
import android.util.AttributeSet;
import android.view.MotionEvent;
+
+
import com.schneewittchen.rosandroid.R;
import com.schneewittchen.rosandroid.ui.views.widgets.PublisherWidgetView;
diff --git a/app/src/main/java/com/schneewittchen/rosandroid/widgets/directional/DirectionalData.java b/app/src/main/java/com/schneewittchen/rosandroid/widgets/directional/DirectionalData.java
new file mode 100644
index 00000000..e886743a
--- /dev/null
+++ b/app/src/main/java/com/schneewittchen/rosandroid/widgets/directional/DirectionalData.java
@@ -0,0 +1,81 @@
+package com.schneewittchen.rosandroid.widgets.directional;
+
+import com.schneewittchen.rosandroid.model.entities.widgets.BaseEntity;
+import com.schneewittchen.rosandroid.model.repositories.rosRepo.node.BaseData;
+import com.schneewittchen.rosandroid.widgets.joystick.JoystickEntity;
+
+import org.ros.internal.message.Message;
+import org.ros.node.topic.Publisher;
+
+import geometry_msgs.Twist;
+import geometry_msgs.Vector3;
+
+import android.util.Log;
+
+
+/**
+ * TODO: Description
+ *
+ * @author Nico Studt
+ * @version 1.0.0
+ * @created on 17.03.20
+ * @updated on 17.03.20
+ * @modified by
+ */
+public class DirectionalData extends BaseData {
+
+ public static final String TAG = DirectionalData.class.getSimpleName();
+
+ private double getSpeed(String sense, double value) {
+ if (sense.equals("Positive") && value >= 0) {
+ return value;
+ } else if (sense.equals("Positive") && value < 0) {
+ return -value;
+ } else if (value < 0) {
+ return value;
+ } else {
+ return -value;
+ }
+ }
+
+ @Override
+ public Message toRosMessage(Publisher publisher, BaseEntity widget) {
+
+ DirectionalEntity dirWidget = (DirectionalEntity) widget;
+
+ Log.d("name", dirWidget.name);
+ Log.d("topic", dirWidget.topic.name);
+ Log.d("position", Integer.toString(dirWidget.posX));
+ Log.d("axis", dirWidget.axis);
+ Log.d("dir", dirWidget.direction);
+ Log.d("sense", dirWidget.sense);
+
+ geometry_msgs.Twist message = (Twist) publisher.newMessage();
+ Vector3 dirVector;
+
+ double speed = 0.3;
+ if (dirWidget.direction.equals(("Linear"))) {
+ dirVector = message.getLinear();
+ } else {
+ dirVector = message.getAngular();
+ }
+ if (dirWidget.speed > 0) {
+ speed = dirWidget.speed;
+ }
+ String sense = dirWidget.sense;
+
+ switch (dirWidget.axis) {
+ case "X":
+ dirVector.setX(getSpeed(sense, speed));
+ break;
+ case "Y":
+ dirVector.setY(getSpeed(sense, speed));
+ break;
+ case "Z":
+ dirVector.setZ(getSpeed(sense, speed));
+ break;
+ }
+
+ return message;
+ }
+}
diff --git a/app/src/main/java/com/schneewittchen/rosandroid/widgets/directional/DirectionalDetailVH.java b/app/src/main/java/com/schneewittchen/rosandroid/widgets/directional/DirectionalDetailVH.java
new file mode 100644
index 00000000..58e3d9fb
--- /dev/null
+++ b/app/src/main/java/com/schneewittchen/rosandroid/widgets/directional/DirectionalDetailVH.java
@@ -0,0 +1,111 @@
+package com.schneewittchen.rosandroid.widgets.directional;
+
+import android.util.Log;
+import android.view.View;
+import android.widget.ArrayAdapter;
+import android.widget.EditText;
+import android.widget.Spinner;
+import android.widget.TextView;
+
+import com.schneewittchen.rosandroid.R;
+import com.schneewittchen.rosandroid.model.entities.widgets.BaseEntity;
+import com.schneewittchen.rosandroid.ui.views.details.PublisherWidgetViewHolder;
+import com.schneewittchen.rosandroid.utility.Utils;
+import com.schneewittchen.rosandroid.widgets.button.ButtonEntity;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.Locale;
+
+import geometry_msgs.Twist;
+import std_msgs.Bool;
+
+
+/**
+ * TODO: Description
+ *
+ * @author Nico Studt
+ * @version 1.0.2
+ * @created on 13.02.20
+ * @updated on 20.05.20
+ * @modified by Nico Studt
+ * @updated on 05.11.2020
+ * @modified by Nico Studt
+ */
+public class DirectionalDetailVH extends PublisherWidgetViewHolder {
+
+ private EditText textText;
+ private EditText speedText;
+ private Spinner rotationSpinner;
+ private Spinner axisSpinner;
+ private Spinner senseSpinner;
+ private Spinner directionSpinner;
+ private ArrayAdapter rotationAdapter;
+ private ArrayAdapter axisAdapter;
+ private ArrayAdapter senseAdapter;
+ private ArrayAdapter directionAdapter;
+
+
+ @Override
+ public void initView(View view) {
+ textText = view.findViewById(R.id.btnTextTypeText);
+ speedText = view.findViewById(R.id.speedTextTypeText);
+
+ rotationSpinner = view.findViewById(R.id.btnTextRotation);
+ axisSpinner = view.findViewById(R.id.btnTextAxis);
+ directionSpinner = view.findViewById(R.id.btnTextDirection);
+ senseSpinner = view.findViewById(R.id.btnTextSense);
+
+ // Init spinners
+ rotationAdapter = ArrayAdapter.createFromResource(view.getContext(),
+ R.array.button_rotation, android.R.layout.simple_spinner_dropdown_item);
+ rotationSpinner.setAdapter(rotationAdapter);
+
+ axisAdapter = ArrayAdapter.createFromResource(view.getContext(),
+ R.array.directional_twist_axis, android.R.layout.simple_spinner_dropdown_item);
+ axisSpinner.setAdapter(axisAdapter);
+
+ directionAdapter = ArrayAdapter.createFromResource(view.getContext(),
+ R.array.directional_twist_dir, android.R.layout.simple_spinner_dropdown_item);
+ directionSpinner.setAdapter(directionAdapter);
+
+ senseAdapter = ArrayAdapter.createFromResource(view.getContext(),
+ R.array.directional_twist_sense, android.R.layout.simple_spinner_dropdown_item);
+ senseSpinner.setAdapter(senseAdapter);
+ }
+
+ @Override
+ protected void bindEntity(BaseEntity entity) {
+ DirectionalEntity buttonEntity = (DirectionalEntity) entity;
+
+ textText.setText(buttonEntity.text);
+ speedText.setText(String.valueOf(buttonEntity.speed));
+
+ String degrees = Utils.numberToDegrees(buttonEntity.rotation);
+
+ rotationSpinner.setSelection(rotationAdapter.getPosition(degrees));
+ axisSpinner.setSelection(axisAdapter.getPosition(buttonEntity.axis));
+ directionSpinner.setSelection(directionAdapter.getPosition(buttonEntity.direction));
+ senseSpinner.setSelection(senseAdapter.getPosition(buttonEntity.sense));
+ }
+
+ @Override
+ protected void updateEntity(BaseEntity entity) {
+ DirectionalEntity buttonEntity = (DirectionalEntity)entity;
+
+ buttonEntity.text = textText.getText().toString();
+ if (speedText.getText().length() > 0 ) {
+ buttonEntity.speed = Double.parseDouble(speedText.getText().toString());
+ }
+ String degrees = rotationSpinner.getSelectedItem().toString();
+ buttonEntity.rotation = Utils.degreesToNumber(degrees);
+ buttonEntity.axis = axisSpinner.getSelectedItem().toString();
+ buttonEntity.direction = directionSpinner.getSelectedItem().toString();
+ buttonEntity.sense = senseSpinner.getSelectedItem().toString();
+ }
+
+ @Override
+ public List getTopicTypes() {
+ return Collections.singletonList(Bool._TYPE);
+ }
+}
diff --git a/app/src/main/java/com/schneewittchen/rosandroid/widgets/directional/DirectionalEntity.java b/app/src/main/java/com/schneewittchen/rosandroid/widgets/directional/DirectionalEntity.java
new file mode 100644
index 00000000..ec0bdeb0
--- /dev/null
+++ b/app/src/main/java/com/schneewittchen/rosandroid/widgets/directional/DirectionalEntity.java
@@ -0,0 +1,41 @@
+package com.schneewittchen.rosandroid.widgets.directional;
+
+import com.schneewittchen.rosandroid.model.entities.widgets.PublisherWidgetEntity;
+import com.schneewittchen.rosandroid.model.repositories.rosRepo.message.Topic;
+
+import geometry_msgs.Twist;
+
+
+/**
+ * TODO: Description
+ *
+ * @author Nico Studt
+ * @version 1.1.1
+ * @created on 31.01.20
+ * @updated on 10.05.20
+ * @modified by Nico Studt
+ */
+public class DirectionalEntity extends PublisherWidgetEntity {
+
+ public String text;
+ public int rotation;
+ public String axis;
+ public String direction;
+ public String sense;
+ public double speed;
+
+ public DirectionalEntity() {
+ this.width = 2;
+ this.height = 2;
+ this.topic = new Topic("cmd_vel", Twist._TYPE);
+ this.publishRate = 20f;
+ this.text = "Move on";
+ this.rotation = 0;
+ this.immediatePublish = true;
+ this.axis = "X";
+ this.direction = "Linear";
+ this.sense = "Positive";
+ this.speed = 0.3;
+ }
+
+}
diff --git a/app/src/main/java/com/schneewittchen/rosandroid/widgets/directional/DirectionalView.java b/app/src/main/java/com/schneewittchen/rosandroid/widgets/directional/DirectionalView.java
new file mode 100644
index 00000000..f13bca56
--- /dev/null
+++ b/app/src/main/java/com/schneewittchen/rosandroid/widgets/directional/DirectionalView.java
@@ -0,0 +1,140 @@
+package com.schneewittchen.rosandroid.widgets.directional;
+
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.MotionEvent;
+
+import androidx.annotation.Nullable;
+
+import com.schneewittchen.rosandroid.R;
+import com.schneewittchen.rosandroid.model.entities.widgets.BaseEntity;
+import com.schneewittchen.rosandroid.ui.views.widgets.PublisherWidgetView;
+import com.schneewittchen.rosandroid.widgets.button.ButtonData;
+
+import android.text.StaticLayout;
+import android.text.TextPaint;
+import android.graphics.Color;
+import android.graphics.Rect;
+import android.text.Layout;
+
+/**
+ * TODO: Description
+ *
+ * @author Nico Studt
+ * @version 1.1.0
+ * @created on 18.10.19
+ */
+public class DirectionalView extends PublisherWidgetView {
+
+ public class MoveThread extends Thread {
+
+ @Override
+ public void run() {
+ while (!Thread.currentThread().isInterrupted()) {
+ try {
+ Thread.sleep(1);
+ publishViewData(new DirectionalData());
+ } catch (InterruptedException ex) {
+ Thread.currentThread().interrupt();
+ ex.printStackTrace();
+ }
+ }
+ }
+ }
+
+ public static final String TAG = DirectionalView.class.getSimpleName();
+
+ Paint buttonPaint;
+ TextPaint textPaint;
+ StaticLayout staticLayout;
+ MoveThread t;
+
+ public DirectionalView(Context context) {
+ super(context);
+ init();
+ }
+
+ public DirectionalView(Context context, @Nullable AttributeSet attrs) {
+ super(context, attrs);
+ init();
+ }
+
+
+ private void init(){
+ buttonPaint = new Paint();
+ buttonPaint.setColor(getResources().getColor(R.color.colorPrimary));
+ buttonPaint.setStyle(Paint.Style.FILL_AND_STROKE);
+
+ textPaint = new TextPaint();
+ textPaint.setColor(Color.BLACK);
+ textPaint.setStyle(Paint.Style.FILL_AND_STROKE);
+ textPaint.setTextSize(26 * getResources().getDisplayMetrics().density);
+ t = new MoveThread();
+ }
+
+ private void changeState(boolean pressed) {
+ invalidate();
+ }
+
+
+ @Override
+ public boolean onTouchEvent(MotionEvent event) {
+ if (this.editMode) {
+ return super.onTouchEvent(event);
+ }
+ switch (event.getActionMasked()) {
+ case MotionEvent.ACTION_OUTSIDE:
+ case MotionEvent.ACTION_CANCEL:
+ case MotionEvent.ACTION_BUTTON_RELEASE:
+ case MotionEvent.ACTION_UP:
+ buttonPaint.setColor(getResources().getColor(R.color.colorPrimary));
+ changeState(false);
+ t.interrupt();
+ t = new MoveThread();
+ break;
+ case MotionEvent.ACTION_DOWN:
+ buttonPaint.setColor(getResources().getColor(R.color.color_attention));
+ changeState(true);
+ t.start();
+ break;
+ default:
+ return false;
+ }
+
+ return true;
+ }
+
+
+ @Override
+ public void onDraw(Canvas canvas) {
+ super.onDraw(canvas);
+
+ float width = getWidth();
+ float height = getHeight();
+ float textLayoutWidth = width;
+
+ DirectionalEntity entity = (DirectionalEntity) widgetEntity;
+
+ if (entity.rotation == 90 || entity.rotation == 270) {
+ textLayoutWidth = height;
+ }
+
+ canvas.drawRect(new Rect(0, 0, (int) width, (int) height), buttonPaint);
+
+ staticLayout = new StaticLayout(entity.text,
+ textPaint,
+ (int) textLayoutWidth,
+ Layout.Alignment.ALIGN_CENTER,
+ 1.0f,
+ 0,
+ false);
+ canvas.save();
+ canvas.rotate(entity.rotation, width / 2, height / 2);
+ canvas.translate(((width / 2) - staticLayout.getWidth() / 2), height / 2 - staticLayout.getHeight() / 2);
+ staticLayout.draw(canvas);
+ canvas.restore();
+ }
+}
diff --git a/app/src/main/res/layout/widget_detail_directional.xml b/app/src/main/res/layout/widget_detail_directional.xml
new file mode 100644
index 00000000..c7b93056
--- /dev/null
+++ b/app/src/main/res/layout/widget_detail_directional.xml
@@ -0,0 +1,172 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/values/widgets.xml b/app/src/main/res/values/widgets.xml
index 93278309..1ce7921e 100644
--- a/app/src/main/res/values/widgets.xml
+++ b/app/src/main/res/values/widgets.xml
@@ -8,7 +8,7 @@
- Debug
- Gps
- Joystick
- - Label
+ - Directional
- Logger
- RqtPlot
- Viz2D
@@ -99,7 +99,6 @@
You can zoom in and out by pinching 2 or more fingers together or apart.
-
The Joystick node is designed for teleoperational control of robotic systems.
@@ -124,6 +123,31 @@
+
+
+ The Directional node is designed for teleoperational control of robotic systems. You can create
+ a button which allows the robot to move or turn.
+ It will communicate to the topic specified in the details. The inherited message is thereby
+ the geometry_msgs/Twist. In the details section of the directional, you can specify the axis
+ of the speed and the kind of speed (linear / angular).
+
+
+
+ - Linear
+ - Angular
+
+
+
+ - X
+ - Y
+ - Z
+
+
+
+ - Positive
+ - Negative
+
+
A Label which does not interact with ROS but helps to organize your screen.