Skip to content

Basic interface

a-brannen edited this page May 27, 2021 · 9 revisions

The Basic interface consists of the following:

MQTT

Arduino

MQTT is used on the Alset Vehicle (Arduino Board), and the Android Application. The connection can be configured to connect to any host.

The car subscribes to the following topics:

namespace mqtt_topic 
{
    const auto CONTROL_GLOBAL = "/smartcar/control/#";
    const auto CONTROL_SPEED = "/smartcar/control/speed";
    const auto CONTROL_STEERING = "/smartcar/control/steering";
    const auto TELEMETRY_SPEED = "/smartcar/telemetry/speed";
    const auto TELEMETRY_FRONT_ULTRASONIC = "/smartcar/telemetry/frontUltrasonic";
    const auto TELEMETRY_BACK_INFRARED = "/smartcar/telemetry/backInfrared";
    const auto CAMERA = "/smartcar/camera";
}

Each topic is then published through stand-alone methods:

Camera:

void publishCameraFrame()
{
#ifdef __SMCE__
        Camera.readFrame(frameBuffer.data());
        mqtt.publish(mqtt_topic::CAMERA, frameBuffer.data(), frameBuffer.size(), false, 0);
#endif
}

Speed:

void publishCarSpeed()
{
      mqtt.publish(mqtt_topic::TELEMETRY_SPEED, String(car.getSpeed()));
}

Front Ultrasonic Sensor:

void publishFrontUltrasonic()
{
#ifdef __SMCE__
    const long distance = frontUSSensor.getDistance();
    static long previousDistance = -1;

    if (distance == previousDistance) {
        return;
    }

    previousDistance = distance;

    mqtt.publish(mqtt_topic::TELEMETRY_FRONT_ULTRASONIC, String(distance));
#endif
}

Back Infrared Sensor:

void publishBackInfrared()
{
#ifdef __SMCE__
    const long distance = backIRSensor.getDistance();
    static long previousDistance = -1;

    if (distance == previousDistance) {
        return;
    }

    previousDistance = distance;

    mqtt.publish(mqtt_topic::TELEMETRY_BACK_INFRARED, String(distance));
#endif
}

Android Application

This part of the MQTT implementation is adapted from: https://medium.com/swlh/android-and-mqtt-a-simple-guide-cb0cbba1931c

The app declares the following topics:

public final class SmartCarTopics {
    public static final String CONTROL_STEERING = "/smartcar/control/steering";
    public static final String CONTROL_SPEED = "/smartcar/control/speed";
    public static final String TELEMETRY_SPEED = "/smartcar/telemetry/speed";
    public static final String CAMERA = "/smartcar/camera";
}

If the connection is a success, the Camera and Speed will be listened to from the Alset Vehicle.

private final IMqttActionListener mqttConnectionListener = new IMqttActionListener() {
    @Override
    public void onSuccess(IMqttToken asyncActionToken) {
        mqtt.subscribe(SmartCarTopics.CAMERA, 1, mqttSubscriptionListener);
        mqtt.subscribe(SmartCarTopics.TELEMETRY_SPEED, 1, mqttSubscriptionListener);
    }

Both of those subscriptions are handled with the below function:

@Override
public void messageArrived(String topic, MqttMessage message) {
    if (topic.equals(SmartCarTopics.CAMERA)) {
        final byte[] payload = message.getPayload();
        final int[] pixels = new int[IMAGE_WIDTH * IMAGE_HEIGHT];
        for (int ci = 0; ci < pixels.length; ++ci) {
            final byte r = payload[3 * ci];
            final byte g = payload[3 * ci + 1];
            final byte b = payload[3 * ci + 2];
            pixels[ci] = Color.rgb(r, g, b);
        }

        if (cameraFrameReceivedCallback != null) {
            cameraFrameReceivedCallback.onCameraFrameReceived(pixels, IMAGE_WIDTH, IMAGE_HEIGHT);
        }
    }

    if(topic.equals(SmartCarTopics.TELEMETRY_SPEED)){
        final double newSpeedMS = Double.parseDouble(message.toString());
        if (currentSpeedMS == newSpeedMS) {
            return;
        }

        currentSpeedMS = newSpeedMS;

        if (speedUpdatedCallback != null) {
            speedUpdatedCallback.onSpeedUpdated(currentSpeedMS);
        }
    }
}

The topics for controlling the movement of the car is managed by these methods:

    @Override
    public void setSteeringAngle(int angle) {
        /* Caps the value of the angle of the car's movement to 90 degrees or -90 degrees to save on
           data transmission */
        angle = angle < -90 ? -90 : Math.min(angle, 90);
        mqtt.publish(SmartCarTopics.CONTROL_STEERING, String.valueOf(angle), 1, mqttPublishListener);
    }

    @Override
    public void setSpeed(int speed) {
        if (mqtt.isConnected() && status == ACTIVE) {
            mqtt.publish(SmartCarTopics.CONTROL_SPEED, String.valueOf(speed), 1, mqttPublishListener);
            if (motorPowerUpdatedCallback != null) {
                motorPowerUpdatedCallback.onMotorPowerUpdated(speed);
            }

            direction = Integer.signum(speed);
        }
    }

User Interface

Functional Requirements:

  • There should be a way for the app to display readings from the car’s sensors in a manner that assists with parking.
  • The app should provide a joystick for manually controlling the car.
  • The app should provide an option for the user to select between a park mode and a driving mode.
  • The app should provide a screen for the user to access his car.

Non-functional Requirements:

  • The system should be easy to use
  • The screen should use a modern design language
  • The screen will not be ugly

The interface had plenty of iterations before it finally gave that feeling of the ultimate driving experience. The screens are listed below, the components that were implemented within the Basic Interface Milestone were the following: The Park & Drive button, which is toggled in order to show the Alset Dashboard and control the Alset Vehicle. The Speedometer, which is shown when the driving is active to highlight the KM/H and the current Power percentage used. The Joystick, which is the knob seen at the bottom which controls the entire steering of the car.

Login Screen

Login Screen

User Logged in Screen

Logged in Screen

Driving Screen Parked

DrivingScreenParked

Driving Screen Driving

DrivingScreenDriving

Clone this wiki locally