Sending Data to Serial Port through VB

The code looks fine, but it's hard to say what is going on since I'm not really sure how grasshopper calls the code in each routine / class / sub. The error looks like a generic error message, instead of the full message that .NET returns which would give more info.

You don't have something else talking to COM3 at the same time do you? Like another monitoring app, Arduino, or the routine that writes to the port.

No, nothing else was talking to the COM3 port. In fact, that was the only COM port available. I should say that when I did try to run the code (twice), it actually froze the Rhino application. As if it were in a continuous loop. Is there a chance that I didn't call the receive function properly? How should the code between the subs look like?

By "How should the code between the subs look like?" you are talking about the # region area.

The region is just a editing tool for the Visual Studio IDE that allows you to group routines together, and fold the code. It is removed by the compiler.

We could try trapping the error and displaying it directly, instead of allowing grasshopper to catch the error. Try this function instead.

      Function ReceiveSerialData() As String
            ' Receive strings from a serial port.
            Dim returnStr As String = ""

            Try
                  Using com3 As IO.Ports.SerialPort = My.Computer.Ports.OpenSerialPort("COM3", 9600)
                        Do
                              Dim Incoming As String = com3.ReadLine()
                              If Incoming Is Nothing Then
                                    Exit Do
                              Else
                                    returnStr &= Incoming & environment.newline
                              End If
                        Loop
                        com3.Close()
                  End Using

            Catch ex As Exception
                  MessageBox.Show(ex.ToString)
            End Try

            Return returnStr
      End Function

I appreciate all of the help you have been giving me, as I am really learning a lot from these examples. I tried the code snippet you posted, but have gotten a longer error message (as expected, I think). I've also posted a screen shot of both the error message that I get when I call the function and also how my screen looks when I have both the Serial Monitor and the Grasshopper VB interface open at the same time. Again, I'm not sure what I'm doing wrong, and the error message looks quite confusing, but if you have any ideas, I would greatly appreciate it. Thanks again.


Where have you posted the screen shots at?

You can't see them? Huh, I uploaded them to my website and posted the URL. When log in to the forum and check this thread, they show up. Hmm... What if I just attach the URL. Try this.
http://www.liftarchitects.com/storage/research/Grasshopper%20to%20Arduino%20VB01.jpg
http://www.liftarchitects.com/storage/research/Grasshopper%20to%20Arduino%20VBerror.jpg

That's weird, Before looking at the images on your site, I could not see them on the forum, now they show up!?

It looks like you have the Arduino serial monitor attached to the com port. Only one device on the system can use the port, so if Arduino is attached, you won't be able to get Grasshopper attached. The access denied error is telling us the same thing: that something else is already talking to the serial port.

The other thing I noticed is that there was an error message on the window in the background (near the bottom center of the screen). It is referring to a recursive call. I'm not sure if this is related to the issue you have that seems like the code loops forever, but it could be.

So, does that just mean that the Serial Monitor has to be closed for the script to work? That way nothing else is talking to the COM port?
As for the other error message that you pointed out... That is a warning in the Grasshopper Interface. If something isn't working correctly, then Grasshopper will give you a warning message in that area. So, I do think there is still something in the code that is causing it to have a continuous loop.
So, is this what I should do (when I get home tonight). Make sure the Arduino is connected, but do NOT turn on the Serial Monitor. Then, launch Grasshopper and put in the original code (see below). Then call the function (between the subs) using this code "ReceiveSerialData()". Does that make sense?

Sub RunScript()

  End Sub

#Region "Additional methods and Type declarations"
  Function ReceiveSerialData() As String
    ' Receive strings from a serial port.
    Dim returnStr As String = ""

    Using com3 As IO.Ports.SerialPort = _
        My.Computer.Ports.OpenSerialPort("COM3")
      Do
        Dim Incoming As String = com3.ReadLine()
        If Incoming Is Nothing Then
          Exit Do
        Else
          returnStr &= Incoming & vbCrLf
        End If
      Loop
      com3.Close()
    End Using

    Return returnStr
  End Function
#End Region
End Class

Exactly; the serial monitor is connecting to COM3 to listen to the Arduino. The rest of the code should work as you have it, barring whatever recursive error you have in Grasshopper.

Great. I will try it out tonight and let you know how it works. Thanks again!

Well... I've tried this several different ways, and I'm still getting a continuous loop error. I made sure the Serial Monitor wasn't running and I tried a slightly different version of the code to try to get out of the continuous looping problem. But, it still locks up every time I call the function.
Here's how the Grasshopper side of things is set up. I have created a boolean toggle that feeds either a true or false value into the VB script component. I have also connected a Timer Component which should refresh the solution at any given time interval... in this case every 1 sec. So, ideally... when you flip the toggle to True, the script will call the function and retrieve whatever data is coming into the COM3 port. This will be refreshed every 1 sec. However, it's getting stuck. Here is the modified code I tried, but it still isn't working. I've also posted a picture of the setup. If you have any more ideas, I would really appreciate them. Thanks for all the help along the way. I feel like we are really close. Let me know if the images don't show up again :slight_smile:

  Function ReceiveSerialData() As String
    ' Receive strings from a serial port.
    Dim returnStr As String = ""
 
    Using com3 As IO.Ports.SerialPort = _
        My.Computer.Ports.OpenSerialPort("COM3")
      Do
        Dim Incoming As String = com3.ReadLine()
        If Incoming Is Nothing Then
          Exit Do
        Else
          returnStr &= Incoming & vbCrLf
          com3.Close()
          Return returnStr
        End If
      Loop
      
    End Using
 
    Return returnStr
  End Function


For some reason I can't see the images again.

Let's see if just posting the URL works this time. Try these links. If you still can't see them, perhaps I could email you directly. Is there away to do that through this forum?
http://www.liftarchitects.com/storage/research/Grasshopper%20to%20Arduino%20VB02.jpg
http://www.liftarchitects.com/storage/research/Grasshopper%20to%20Arduino%20VB03.jpg

Well, I don't see anything right off hand that looks wrong. The only thing that might cause issues is calling the ReceiveSerialData function every second. If it has not finished the last read it could still be running, which would most likely throw an error.

Can you subscribe to events in Grasshopper? My normal method of using com ports is to create the port, attach an event handler to the "data received event" and open it. Then whenever the com port receives data it raises an event, effectively letting me know that it has happened.

My other suggestion would be to download VB express http://www.microsoft.com/express/vb/Default.aspx to use for debugging your VB code. Once you are sure of how the VB code is going to run, you can put it back into Grasshopper.

Is it possible that the error could be on the Arduino side? I'm using the AnalogeInSerial example sketch (code is below). It's reading the voltage input every 10 ms. The Grasshopper definition is trying to listen to the COM port every N ms (50 ms is the smallest interval I can go in Grasshopper). I can obviously change the Arudino interval to match the Grasshopper interval... but they will probably never be completely in sync since they are starting at different points in time. The Grasshopper Timer is supposed to be a asychronous timer, so I wouldn't think that a mismatched time interval would really matter. But, could I be making a mistake in using the AnalogeInSerial example to send the data to Grasshopper. Is there a better way just to test whether or not I can actual receive the data in Grasshopper? Thanks for the quick replies.

Analog input, serial output
 
 Reads an analog input pin, prints the results to the serial monitor.
 
 The circuit:

 * potentiometer connected to analog pin 0.
   Center pin of the potentiometer goes to the analog pin.
   side pins of the potentiometer go to +5V and ground
 
 created over and over again
 by Tom Igoe and everyone who's ever used Arduino
 
 */
 
 void setup() {
  Serial.begin(9600); 
 }
 
 void loop() {
  // read the analog input into a variable:
   int analogValue = analogRead(0);
   // print the result:
   Serial.println(analogValue);
   // wait 10 milliseconds for the analog-to-digital converter
   // to settle after the last reading:
   delay(10);
 }

In this type of setup, where you are sending a fairly quick stream of data, you are going to want to open the serial port once, and leave it open. I really don't know what Grasshopper is capable of, but it appears that it creates a class and can call routines in that class. For this to work I would think that you will need to be able to have Grasshopper handle an event, or at least open the serial port when the app starts, and then call a function that returns a variable stored when the serial port receives data. I'll work up a code sample and post it here. You may get more help from a Grasshopper forum as far as how to integrate the sample, but once you know what works it should be easier to get help with.

Again, I think that it would be easier to debug, and test the code from within VB, and then integrate it once you know it works.

Thanks Robert. I have also been sending questions to one of the Rhino developers about this problem... so hopefully we will be able to come up with a solution. But, thanks for the input and I look forward to the example. I had wondered about opening and closing the port each time the function was called. It seems like you could put the Opening portion of the code in the If/Else part of the code... so that if the boolean toggle is switched to True, then the port will be opened and then call the Receive data function. If the toggle is switched back to False, then the COM port is closed. Would that work?

Another thought; do you need all of the data that you are trying to send from the Arduino, or just whatever the current value is when you are ready for it?

I think whatever the current value is would be just fine. That way, you could just change the Timer Interval in Grasshopper to adjust how quickly you get your data.

It really depends upon how Rhino / Grasshopper compiles and maintains the class in memory. If it is done once (at startup, or first reference), then you could theoretically change the scope of the com port object, and keep it alive between calls (what my sample will do). If they recompile the class whenever it is referenced, then you can't do that.