Does anyone have swift (iOS app) code example on how to connect to VESC via bluetooth?

Hello everyone,
I try to build my own free iOS (iPhone) app, which connects to board with this chip:


I want an app to allow me to read some data from VESC and also to change power settings.

I saw some people here made similar projects:


I have problem with connecting to ESC via bluetooth. If I would find some code (the best would be in Swift language) showing how to connect to ESC, receive data and change settings I would be able to do rest of the app on my own.
I wasn’t able to find any documentation or code example, I will appreciate any help with this.

2 Likes

@sofu

Can you steer him in the right direction? Thanks!

1 Like

I don’t usually work with Swift but the following should give you a good idea of what you’ll need.

You’ll wanna look at CBCentralManager. Documentation here: https://developer.apple.com/documentation/corebluetooth/cbcentralmanager

It’s fairly standard bluetooth peripheral handling beyond that.

To read data, you need to read characteristics from the connected peripheral. Look at -[CBPeripheral readValueForCharacteristics] and handle it accordingly with -[CBPeripheralDelegate peripheral:didUpdateValueForCharacteristic:error:].

From there, you should process the incoming bytes from characteristic.value. Keep in mind the first byte is the packet ID. You should look at the communication commands typedef in datatypes.h to see applicable packet IDs. Find it here: https://github.com/vedderb/bldc/blob/master/datatypes.h

That should be everything you need to get started. Good luck!

4 Likes

Awesome. Thank you!

Here are two codebases that may be useful.

First, a minimal working example of sending a duty cycle command to a VESC from a PC using the BLE protocol. This leverages a python library from the good folks at Adafruit.

Second, an iOS app on github that will connect to my Flipsky/BLE/NRF device. I haven’t been able to send commands because the UART interface is ASCII. I’m going to try and find the callback for the send UART data function and hard code some hex strings in there and see if it works. I’ve got some time to tackle this and will report back with any luck.

2 Likes

Thank you a lot guys, both replies are very helpful.

1 Like

I was able to read and write small (~12 byte) packets (COMM_GET_VALUES_SELECTIVE and COMM_SET_DUTY) to a VESC using Swift and BLE. Here are two even more useful code bases that helped me:

The Adafruit app has a tutorial associated with it that is useful for learning the CoreBluetooth calls.
Lines 86–102 of this file show how to send and receive byte arrays rather than strings.

The last thing that I haven’t worked out yet, is how to receive the large (~70 byte) package from COMM_GET_VALUES. I’m getting packets of inconsistent length so I think it is a buffer issue. I’m very interested in your approach if you are able to resolve that issue.

1 Like

So a general idea of how I did it is as follows (not Swift sorry):

You need to look at the implementation of the method. A rough idea of what I did was define a struct that has all the values I wanna store (actually just copied from the vesc tool struct), have an index value to keep track of where I am in the packet, and increase that index by the relevant number of indexes every time I process a set of bytes.

For example, for COMM_FW_VERSION, You can do the following:

First, declare an index tracker, some way of keeping track of your original payload, and the struct you’re writing data to. Sorry it’s not Swift, I’m not too familiar with the ins and outs of Swift yet.

    int32_t ind = 0;
    uint8_t payload2[sizeof(payload)];
    memcpy(payload2, payload + 1, sizeof(payload) - 1);
    struct vescFW fw;

Then,

fw.fw_version_major = buffer_get_int8(payload2, &ind);
fw.fw_version_minor...

where

uint8_t buffer_get_int8(const uint8_t *buffer, int32_t *index) {
    uint8_t res = buffer[*index];
    *index += 1;
    return res;
}

Of course, you need to be mindful of what kind of stuff you’re processing. uint16 needs to increase index by 2, uint32 by 4, etc. Same applies to floats.

For the following hardware string, you just need to copy the remainder of the original payload starting from [ind] with a 30 character limit. You can simply interpret the remaining as a C string and use something like -[NSString stringWithCString:encoding] to decode it.

Basically, look at the implementation of the method itself as defined in the firmware (not tool, though that’s helpful to determine how things are supposed to be read), and do the reverse of whatever the method is doing in order to read it. Hope this helps.

2 Likes