SerialDevice写入应用程序在将字符串写入串行设备后关闭,没有任何警告。 C#UWP

问题描述 投票:0回答:1

我正在一个必须使用Raspberry Pi将命令发送到Arduino板的项目中。在代码中,有一个空格和一个Task,用于将这些命令发送到电路板。当您初始化程序时,写入Arduino板的工作正常,因此,如果您要求它发送命令,Arduino将会收到它。在运行该程序一段时间后,当您要求它发送命令时,它将停止并且该应用程序崩溃,除了显示0x000000d的错误消息外,没有警告消息。

该应用程序通过以下方式工作:

Arduino将信息发送到程序。当程序收到所有信息后,它将根据该信息计算某些变量,然后向Arduino发送一条消息。 Arduino几乎每1/10秒发送一次信息,因此,程序以相同的速率向Arduino发送一条消息。

发送和接收消息的代码如下:

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Windows.Devices.Enumeration;
using Windows.Devices.SerialCommunication;
using Windows.Storage.Streams;

namespace KronosBrain
{
    class SeriDev
    {
        //SeriDev ---> Serial Device
        private static SerialDevice serialDevice = null;
        private static string message = "";
        private static bool isConnected = false;

        //Message sending related
        public static bool isCommandPoolRunning = false;
        public static bool isReadingCommand = false;
        //public static List<String> commandPool = new List<string>();
        private static string lastCommand = "";
        private static int lastCommandPetitions = 0;

        public static async void StartConnection()
        {
            try
            {
                UInt16 vid = 0x2A03;
                UInt16 pid = 0x0042;
                string deviceFilter = SerialDevice.GetDeviceSelectorFromUsbVidPid(vid, pid);
                DeviceInformationCollection deviceInfo = await DeviceInformation.FindAllAsync(deviceFilter);
                foreach (var device in deviceInfo)
                {
                    Info.WriteLine("<SeriDev> Looking for arduino devices... " + device.Id);
                }
                string device_id = deviceInfo.First().Id;
                serialDevice = await SerialDevice.FromIdAsync(device_id);

                if (serialDevice == null)
                {
                    Info.WriteLine("<SeriDev> Device is null");
                    StartConnection();
                }

                // Configure serial settings
                serialDevice.WriteTimeout = TimeSpan.FromMilliseconds(50); //Refresh write time
                serialDevice.ReadTimeout = TimeSpan.FromMilliseconds(50); //Refresh read time
                serialDevice.BaudRate = 115200;
                serialDevice.Parity = SerialParity.None;
                serialDevice.StopBits = SerialStopBitCount.One;
                serialDevice.DataBits = 8;
                serialDevice.Handshake = SerialHandshake.None;
                //Settings done
                Info.WriteLine("<SeriDev> Connected to Arduino");
                isConnected = true;
                isCommandPoolRunning = false;
                isReadingCommand = false;

                ListenSerialDevice();
            }
            catch (Exception ex)
            {
                Server.LogMessage("Cannot connect with arduino... Waiting for connection");
                Info.WriteLine("<SeriDev> Connot connect with arduino, waiting for connection. Error message: " + ex.Message);
                //Add error messages
                StartConnection();
            }
        }

        private static async void ListenSerialDevice()
        {
            try
            {
                //Check for nullity
                if (serialDevice != null)
                {
                    DataReader dataReader = new DataReader(serialDevice.InputStream);


                    while (isConnected)
                    {
                        await Read(dataReader);
                    }
                }
            }
            catch (Exception ex)
            {
                Server.LogMessage(String.Format("There was an error reading the input."));
                Info.WriteLine(String.Format("<SeriDev> There was an error reading the input. Error message {0}: ", ex.Message));
            }
        }

        private static async Task Read(DataReader dataReader)
        {
            try
            {
                if (!isCommandPoolRunning)
                {
                    isReadingCommand = true;
                    Task<UInt32> loadAsyncTask;

                    var bufferLength = 32;
                    dataReader.UnicodeEncoding = Windows.Storage.Streams.UnicodeEncoding.Utf8;
                    loadAsyncTask = dataReader.LoadAsync((uint)bufferLength).AsTask();
                    dataReader.InputStreamOptions = InputStreamOptions.Partial;

                    UInt32 bytesRead = await loadAsyncTask;
                    isReadingCommand = false;
                    if (bytesRead > 0)
                    {
                        string readInformation = "";
                        try
                        {
                            readInformation = dataReader.ReadString(bytesRead);
                        }
                        catch (Exception ex)
                        {
                            Debug.WriteLine("<SeriDev> There was a problem converting the bytes to a string.");
                        }
                        //Debug.WriteLine(readInformation);

                        message += readInformation;
                        string[] messageSplited = message.Split('?');
                        for (int i = 0; i < messageSplited.Length; i++)
                        {
                            if (i < (messageSplited.Length - 1))
                            {
                                if (!String.IsNullOrEmpty(messageSplited[i]))
                                {
                                    var task = Task.Run(() => HandleData(messageSplited[i]));
                                    task.Wait();
                                } 
                            }
                        }
                        message = messageSplited[(messageSplited.Length - 1)];
                    }
                    dataReader.DetachBuffer();
                }
            }
            catch (Exception ex)
            {
                Debug.WriteLine("<SeriDev> Something strange happened in Read. Error message {0}", ex.Message);
                isConnected = false;
                serialDevice = null;
                Debug.WriteLine("<SeriDev> Disconnected from arduino. Trying to reconnect");
                StartConnection();
            }
        }

        private static void HandleData(string data)
        {
            try
            {
                NumberFormatInfo provider = new NumberFormatInfo();
                provider.NumberDecimalSeparator = ".";
                //Debug.WriteLine("<SeriDev> Message cleaned: " + data);
                //Split data to find coordinates and other information
                string[] keyWords = data.Split('!');
                //Debug.WriteLine("KeyWord[0]: " + keyWords[0] + " KeyWord[1]: " + keyWords[1]);
                if (keyWords.Length > 1)
                {
                    switch (keyWords[0])
                    {
                        case "gps_x":
                            SelfDriving.robot.x = Convert.ToDouble(keyWords[1], provider);
                            //Server.SendMessage("gps_x$" + SelfDriving.robot.x);
                            break;
                        case "gps_y":
                            SelfDriving.robot.y = Convert.ToDouble(keyWords[1], provider);
                            //Server.SendMessage("gps_y$" + SelfDriving.robot.x);
                            break;
                        case "frontU":
                            SelfDriving.robot.frontU = Convert.ToDouble(keyWords[1], provider);
                            //Server.SendMessage("front_u$" + SelfDriving.robot.frontU);
                            break;
                        case "leftU":
                            SelfDriving.robot.leftU = Convert.ToDouble(keyWords[1], provider);
                            //Server.SendMessage("left_u$" + SelfDriving.robot.leftU);
                            break;
                        case "rightU":
                            SelfDriving.robot.rightU = Convert.ToDouble(keyWords[1], provider);
                            //Server.SendMessage("right_u$" + SelfDriving.robot.rightU);
                            break;
                        case "heading":
                            SelfDriving.robot.heading = Convert.ToDouble(keyWords[1], provider);
                            //Server.SendMessage("heading$" + SelfDriving.robot.heading);
                            break;
                        case "gps_fix":
                            Server.SendMessage("gps_fix$" + keyWords[1]);
                            break;
                        case "robotInformationComplete":
                            if (!SelfDriving.isAnalyzing)
                            {
                                //Info.WriteLine("<SeriDev> Calling PreAnalyzerEngine");
                                SelfDriving.hasFix = true;
                                SelfDriving.PreAnalyzerEngine();
                            }
                            break;
                        case "noFix":
                            SelfDriving.hasFix = false;
                            Server.LogMessage("Waiting for fix");
                            break;
                        default:
                            Debug.WriteLine("<SeriDev> Default case {0}", message);
                            Server.LogMessage(message);
                            break;
                    }
                }
            }
            catch (Exception ex)
            {
                Debug.WriteLine("<SeriDev> Handling data failed. Error message: {0}", ex.Message);
            }
        }

        public static async void SendMessage(string command)
        {
            isCommandPoolRunning = true;
            if (!isReadingCommand)
            {
                var task = Task.Run(() => CommandPoolEmptier(command));
                task.Wait();
            }            
            isCommandPoolRunning = false;
        }

        public static async Task CommandPoolEmptier(string command)
        {
            try
            {
                Task<UInt32> storeAsyncTask;
                DataWriter dataWriter = new DataWriter(serialDevice.OutputStream);

                char[] buffer = new char[command.Length];
                command.CopyTo(0, buffer, 0, command.Length);
                String InputString = new string(buffer);
                dataWriter.WriteString(InputString);

                storeAsyncTask = dataWriter.StoreAsync().AsTask();

                UInt32 bytesWritten = await storeAsyncTask;
                if (bytesWritten >= buffer.Length)
                {
                    dataWriter.DetachBuffer();
                    Debug.WriteLine("<SeriDev> Sent.");
                }
                //await dataWriter.FlushAsync();
            }
            catch (Exception ex)
            {
                Debug.WriteLine("There was an error writing the output. Error message {0}: ", ex.Message);
                Server.LogMessage(String.Format("There was an error writing the output. Error message {0}: ", ex.Message));
            }
        }
    }
}

发送和接收消息的Arduino代码如下:

#include <Wire.h>
#include <Adafruit_MotorShield.h>
#include <Adafruit_GPS.h>
#include <SoftwareSerial.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_HMC5883_U.h>

//Declare compass
Adafruit_HMC5883_Unified compass = Adafruit_HMC5883_Unified(12345);

//Declare ultrasonic sensors
int frontEcho = 30;
int frontTrigger = 31;
float frontDistance, frontDuration;
int leftEcho = 32;
int leftTrigger = 33;
float leftDistance, leftDuration;
int rightEcho = 34;
int rightTrigger = 35;
float rightDistance, rightDuration;

//GPS
HardwareSerial mySerial = Serial1;  //hablar al GPS
Adafruit_GPS GPS(&Serial1);  //GPS object
#define GPSECHO  true
char c;   //leer datos del GPS
String NMEA1;
String NMEA2;

//Motors
//MOTORSHIELD
Adafruit_MotorShield afms = Adafruit_MotorShield();
//MOTORS
Adafruit_DCMotor *m1 = afms.getMotor(4);
Adafruit_DCMotor *m2 = afms.getMotor(3);
Adafruit_DCMotor *m3 = afms.getMotor(1);
Adafruit_DCMotor *m4 = afms.getMotor(2);

//Voids
float angle()
{
  //Get compass event
  sensors_event_t event; 
    compass.getEvent(&event);

    //Calculate angle when z is pointing upwards
    float heading = atan2(event.magnetic.y, event.magnetic.x);

    float declinationAngle = 0.0139626;
    heading += declinationAngle;

    //Correct signs
    // Correct for when signs are reversed.
    if(heading < 0)
      heading += 2*PI;

    // Check for wrap due to addition of declination.
    if(heading > 2*PI)
      heading -= 2*PI;

  //Convert from radians to degrees
  float headingDegrees = heading * 180/M_PI; 

  return headingDegrees;
}

void Stop()
{
  m1->run(RELEASE); 
  m2->run(RELEASE); 
  m3->run(RELEASE); 
  m4->run(RELEASE); 
}

void Forwards(int speed)
{
  speed = map(speed, 0, 100, 0, 255);
  m1->run(FORWARD);
  m2->run(FORWARD);
  m3->run(FORWARD);
  m4->run(FORWARD);
  m1->setSpeed(speed);
  m2->setSpeed(speed);
  m3->setSpeed(speed);
  m4->setSpeed(speed);
}

void Left(int speed)
{
  speed = map(speed, 0, 100, 0, 255);
  m1->run(BACKWARD);
  m2->run(FORWARD);
  m3->run(BACKWARD);
  m4->run(FORWARD);
  m1->setSpeed(speed);
  m2->setSpeed(speed);
  m3->setSpeed(speed);
  m4->setSpeed(speed);
}

void Right(int speed)
{
  speed = map(speed, 0, 100, 0, 255);
  m1->run(FORWARD);
  m2->run(BACKWARD);
  m3->run(FORWARD);
  m4->run(BACKWARD);
  m1->setSpeed(speed);
  m2->setSpeed(speed);
  m3->setSpeed(speed);
  m4->setSpeed(speed);
}

//ULTRASONIC SENSORS
float FrontUCalc(){
  digitalWrite(frontTrigger, HIGH);
  delayMicroseconds(1);
  digitalWrite(frontTrigger, LOW);
  frontDuration = pulseIn(frontEcho, HIGH);
  frontDistance = (frontDuration / 58.2);

  return frontDistance;
}

float LeftUCalc(){
  digitalWrite(leftTrigger, HIGH);
  delayMicroseconds(1);
  digitalWrite(leftTrigger, LOW);
  leftDuration = pulseIn(leftEcho, HIGH);
  leftDistance = (leftDuration / 58.2);

  return leftDistance;
}

float RightUCalc(){
  digitalWrite(rightTrigger, HIGH);
  delayMicroseconds(1);
  digitalWrite(rightTrigger, LOW);
  rightDuration = pulseIn(rightEcho, HIGH);
  rightDistance = (rightDuration / 58.2);

  return rightDistance;
}

void ReadSerial()
{
  String readData = "";
  if(Serial.available())
  {
    delay(1);
    while(Serial.available() > 0){
        // statement
      readData = Serial.readString();
    }
  }

  if(readData != ""){
      HandleData(readData);
  }
}

void HandleData(String data)
{
  if(data == "s")
  {
    //Serial.print(data + "!0?");
    Stop();
  }
  if(data == "g")
  {
    //Serial.print(data + "!0?");
    Forwards(90);
  }
  if(data == "r")
  {
    //Serial.print(data + "!0?");
    Right(60);
  }
  if(data == "l")
  {
    //Serial.print(data + "!0?");
    Left(60);
  }
}

float GetLatitude()
{
  //ReadGPS();
  float latitude;

  if(GPS.fix == 1){
      latitude = GPS.latitudeDegrees;
  }

  return latitude;
}

float GetLongitude()
{
  //ReadGPS();
  float longitude;

  if(GPS.fix == 1){
      longitude = GPS.longitudeDegrees; 
  }

  return longitude;
}

void ReadGPS()
{
  while(!GPS.newNMEAreceived())
  {
    c = GPS.read();
  }
  GPS.parse(GPS.lastNMEA());
  NMEA1 = GPS.lastNMEA();
  while(!GPS.newNMEAreceived())
  {
    c = GPS.read();
  }
  GPS.parse(GPS.lastNMEA());
  NMEA2 = GPS.lastNMEA();
}

void ClearGPS()
{
  while(!GPS.newNMEAreceived())
  {
    c = GPS.read();
  }
  GPS.parse(GPS.lastNMEA());
  while(!GPS.newNMEAreceived())
  {
    c = GPS.read();
  }
  GPS.parse(GPS.lastNMEA());
}

void setup() {
  Serial.begin(115200);
  Serial.print("\n");
  Serial.print("\n////////////////////////////////////////");
  Serial.print("\nDRAPSOR 2017 - KRONOS II - Active"); 
  Serial.print("\n////////////////////////////////////////");
  Serial.print("\n");


  if(!compass.begin())
  {
    /* There was a problem detecting the HMC5883 ... check your connections */
    Serial.println("Compass could not initialize, chek wiring.");
    while(1);
  }

  //GPS
  //GPS.sendCommand("$PMTK251,38400*27<CR><LF>"); // Change GPS baud to 38400 
  GPS.begin(9600);

  GPS.sendCommand(PMTK_SET_NMEA_UPDATE_10HZ); 
  //GPS.sendCommand(PMTK_SET_NMEA_OUTPUT_RMCGGA);

  //GPS.begin(9600);
  GPS.sendCommand(PMTK_SET_NMEA_OUTPUT_RMCONLY);
  GPS.sendCommand("$PGCMD,33,0*66");
  //GPS.begin(38400);
  //delay(250); //Pause
  //GPS.sendCommand("$PMTK220,100*2F<CR><LF>"); // 10 Hz update rate
  Serial.println("Finished GPS Setup");
  //delay(500); //Pause

  delay(1000);

  //MOTORS
  afms.begin();
  m1->setSpeed(0);  //v inicio motor
  m1->run(FORWARD);
  m1->run(FORWARD);
  m1->run(RELEASE);  //v = 0 --> como apagar

  m2->setSpeed(0);  
  m2->run(FORWARD);
  m2->run(FORWARD);
  m2->run(RELEASE);  

  m3->setSpeed(0);  
  m3->run(FORWARD);
  m3->run(FORWARD);
  m3->run(RELEASE);  

  m4->setSpeed(0);  
  m4->run(FORWARD);
  m4->run(FORWARD);
  m4->run(RELEASE);  

  //ULTRASONIC SENSORS
  pinMode(frontEcho, INPUT);
  pinMode(frontTrigger, OUTPUT);

  pinMode(leftEcho, INPUT);
  pinMode(leftTrigger, OUTPUT);  

  pinMode(rightEcho, INPUT);
  pinMode(rightTrigger, OUTPUT);
}

void loop() {
  // put your main code here, to run repeatedly:
  ReadSerial();
  ReadGPS();
  ReadSerial();
  if(GPS.fix)
  {
    Serial.print("heading!" + (String)angle());
    ReadSerial();
    Serial.print("?");
    ReadSerial();
    Serial.print("frontU!" + (String)FrontUCalc());
    ReadSerial();
    Serial.print("?");
    ReadSerial();
    Serial.print("leftU!" + (String)LeftUCalc());
    ReadSerial();
    Serial.print("?");
    ReadSerial();
    Serial.print("rightU!" + (String)RightUCalc());
    Serial.print("?");
    ReadSerial();
    Serial.print("gps_fix!" + (String)GPS.fix);
    ReadSerial();
    Serial.print("?");
    ReadSerial();
    Serial.print("gps_x!");
    Serial.print(GetLatitude(), 13);
    ReadSerial();
    Serial.print("?");
    ReadSerial();
    Serial.print("gps_y!");
    Serial.print(GetLongitude(), 13);
    ReadSerial();
    Serial.print("?");
    ReadSerial();
    Serial.print("robotInformationComplete!");
    ReadSerial();
    Serial.print("?");
  }
  else
  {
    Serial.print("gps_fix!0");
    Serial.print("?");
    Serial.print("noFix!");
    Serial.print("?");
  }
}

所以当Arduino发送'robotInformationComplete!'将触发HandleData,然后,程序将根据接收到的信息调用另一个类,该类将通过CommandPoolEmptier发送“ g”,“ s”,“ l”或“ r”。由于Arduino发送了“ robotInformationCompelte!”程序每隔十分之一秒就发送一次命令。

要模拟程序,请转到HandleData void,并在“ case“ robotInformationComplete”:'情况下更改:

//Info.WriteLine("<SeriDev> Calling PreAnalyzerEngine");
SelfDriving.hasFix = true;
SelfDriving.PreAnalyzerEngine();

对于:

SelfDriving.hasFix = true;
Task.Delay(5);
SendMessage("g");

任务延迟将模拟程序计算这些变量然后发送消息所花费的时间。

在程序中,当您多次调用SendCommand时,它会崩溃,使应用程序崩溃。我尝试了许多不同的可能解决方案,但没有一个起作用。

c# uwp arduino read-write
1个回答
0
投票

official code sample派生,使WriteCancelLock避免设备OutputStream无阻塞。

private async Task WriteAsync(CancellationToken cancellationToken)
{

    Task<UInt32> storeAsyncTask;

    if ((WriteBytesAvailable) && (WriteBytesInputValue.Text.Length != 0))
    {
        char[] buffer = new char[WriteBytesInputValue.Text.Length];
        WriteBytesInputValue.Text.CopyTo(0, buffer, 0, WriteBytesInputValue.Text.Length);
        String InputString = new string(buffer);
        DataWriteObject.WriteString(InputString);
        WriteBytesInputValue.Text = "";

        // Don't start any IO if we canceled the task
        lock (WriteCancelLock)
        {
            cancellationToken.ThrowIfCancellationRequested();

            // Cancellation Token will be used so we can stop the task operation explicitly
            // The completion function should still be called so that we can properly handle a canceled task
            storeAsyncTask = DataWriteObject.StoreAsync().AsTask(cancellationToken);
        }

        UInt32 bytesWritten = await storeAsyncTask;
        if (bytesWritten > 0)
        {
            WriteBytesTextBlock.Text += InputString.Substring(0, (int)bytesWritten) + '\n';
            WriteBytesCounter += bytesWritten;
            UpdateWriteBytesCounterView();
        }
        rootPage.NotifyUser("Write completed - " + bytesWritten.ToString() + " bytes written", NotifyType.StatusMessage);
    }
    else
    {
        rootPage.NotifyUser("No input received to write", NotifyType.StatusMessage);
    }

}

我已尝试发送带有您的代码的消息。不幸的是,我无法重现您的问题,我想消息太短了,以至于非阻塞I / O。您可以创建一个WriteAsync方法(如代码示例)以排除上述假设。

© www.soinside.com 2019 - 2024. All rights reserved.