C# example

Forums:

Can someone please help me on the way in using the UltraBorg with Windows 10 IoT on my Raspberry Pi 2B, please?
I'm looking for an example on addressing the UltraBorg via C#.
I can already address the card through the I2C, but I'm having trouble with the rest of the communication.
How can I read the HC-SR04 distance or command the connected servo?
I think I'm missing a link for the different commands?
The board works with the python examples so the connections are ok, but I would like to use C#...

Thanks to anyone who can help me on the way :-)

piborg's picture

All you should really need to do is mimic the same I2C messages that the UltraBorg.py script is sending / receiving already.

I can give you a couple of examples, but they are completely untested.
All of the C# code has been derived from: https://ms-iot.github.io/content/en-US/win10/samples/I2CAccelerometer.htm

Setting up the connection:

using Windows.Devices.Enumeration;
using Windows.Devices.I2c;

// UltraBorg Constants
const byte I2C_ID_SERVO_USM         = 0x36;
const double USM_US_TO_MM           = 0.171500;
const int PWM_MIN                   = 2000;  // Should be a 1 ms burst, typical servo minimum
const int PWM_MAX                   = 4000;  // Should be a 2 ms burst, typical servo maximum
const byte COMMAND_SET_PWM1         = 5;     // Set the PWM duty cycle for drive #1 (16 bit)
const byte COMMAND_GET_FILTER_USM1  = 41;    // Get the filtered time measured by ultrasonic #1 in us (0 for no detection)
// Other constants are at the top of UltraBorg.py...

// Initialization for UltraBorg
private void UltraBorgInit() {
    try {
        // Set the I2C address and speed
        var settings = new I2cConnectionSettings(I2C_ID_SERVO_USM);
        settings.BusSpeed = I2cBusSpeed.StandardMode;

        // Try to find the UltraBorg on the I2C bus
        string aqs = I2cDevice.GetDeviceSelector();
        var dis = await DeviceInformation.FindAllAsync(aqs);
        ubI2C = await I2cDevice.FromIdAsync(dis[0].Id, settings);
        if (ubI2C == null) {
            // Cannot access the device...
            return;
        }

        // You will probably want to read the set limit values here, the example will assume the defaults are used
    }
}

Setting the position for the first servo:

private void SetServoPosition1(double position) {
    // Work out the values to send based on the limits
    // We are using the defaults to keep the example simple
    double powerOut = (position + 1.0) / 2.0;
    int pwmDuty = (int)((powerOut * (self.PWM_MAX - self.PWM_MIN)) + self.PWM_MIN);
    byte pwmDutyLow = (byte)(pwmDuty & 0xFF);
    byte pwmDutyHigh = (byte)((pwmDuty >> 8) & 0xFF);

    // Build the command data and send it
    byte[] sendBytes = new byte[] {COMMAND_SET_PWM1, pwmDutyHigh, pwmDutyLow};
    try {
        ubI2C.Write(sendBytes);
    } catch (Exception ex) {
        // Failed to send...
    }
}

Reading the filtered distance from sensor #1:

private double GetDistance1() {
    // Build the command data, send it and read the reply
    byte[] recvBytes = new byte[I2C_MAX_LEN];
    byte[] sendBytes = new byte[] {COMMAND_GET_FILTER_USM1};
    try {
        ubI2C.WriteRead(sendBytes, recvBytes);
    } catch (Exception ex) {
        // Failed to read...
        return 0.0;
    }

    // Work out the distance value
    int time_us = ((int)recvBytes[1] << 8) + (int)recvBytes[2];
    if (time_us == 65535) time_us = 0; // Error value
    return (double)time_us * USM_US_TO_MM;
}

Thank you for the quick reply.
I can move the servo with the SetServoPosition function,
but the ubI2C.WriteRead in GetDistance1 keeps returning FFFF?
I loop the function 50 times, but always the WriteRead returns 4x255?
The python code confirms that the USM is working and on USM port 1.
What could I be missing?

piborg's picture

It may simply be that a slight gap is required between the write and read operations.
Usually this is handled by the remote device (UltraBorg in this case) using a method called clock streching.
Unfortunately when testing we found the Raspberry Pi did not seem to work correctly when we used clock stretching.

Try this version which splits the write and read into two operations to see if it works that way:

private double GetDistance1() {
    // Build the command data, send it and read the reply
    byte[] recvBytes = new byte[I2C_MAX_LEN];
    byte[] sendBytes = new byte[] {COMMAND_GET_FILTER_USM1};
    try {
        ubI2C.Write(sendBytes);
        ubI2C.Read(recvBytes);
    } catch (Exception ex) {
        // Failed to read...
        return 0.0;
    }

    // Work out the distance value
    int time_us = ((int)recvBytes[1] << 8) + (int)recvBytes[2];
    if (time_us == 65535) time_us = 0; // Error value
    return (double)time_us * USM_US_TO_MM;
}

Works like a charm :-D
Thank you!!!

This is awesome! I can't wait to explore what I can do with PiBorg hardware and Windows IoT

Hi,

There's already a few people that have already said they've ported the python code to C# but I could not find any complete examples so I've started one here:

https://github.com/johnkattenhorn/picoborgrev

Subscribe to Comments for &quot;C# example&quot;