Skip to content

Basic interface

Jensah edited this page May 21, 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 the 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

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