Pages: 1 [2] 3 4 5   Go Down
Author Topic: Sending Data to Serial Port through VB  (Read 6464 times)
0 Members and 1 Guest are viewing this topic.
Palmetto, FL USA
Offline Offline
Full Member
***
Karma: 0
Posts: 138
Arduino rocks
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

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.
Logged

0
Offline Offline
Jr. Member
**
Karma: 0
Posts: 84
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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?

Code:
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

Logged

Palmetto, FL USA
Offline Offline
Full Member
***
Karma: 0
Posts: 138
Arduino rocks
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

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.
Logged

0
Offline Offline
Jr. Member
**
Karma: 0
Posts: 84
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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

0
Offline Offline
Jr. Member
**
Karma: 0
Posts: 84
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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 smiley

Code:
 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


Logged

Palmetto, FL USA
Offline Offline
Full Member
***
Karma: 0
Posts: 138
Arduino rocks
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

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

0
Offline Offline
Jr. Member
**
Karma: 0
Posts: 84
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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
Logged

Palmetto, FL USA
Offline Offline
Full Member
***
Karma: 0
Posts: 138
Arduino rocks
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

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.
Logged

0
Offline Offline
Jr. Member
**
Karma: 0
Posts: 84
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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.
Code:
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);
 }
Logged

Palmetto, FL USA
Offline Offline
Full Member
***
Karma: 0
Posts: 138
Arduino rocks
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

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.
Logged

0
Offline Offline
Jr. Member
**
Karma: 0
Posts: 84
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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?
Logged

Palmetto, FL USA
Offline Offline
Full Member
***
Karma: 0
Posts: 138
Arduino rocks
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

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?

Logged

0
Offline Offline
Jr. Member
**
Karma: 0
Posts: 84
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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.
Logged

Palmetto, FL USA
Offline Offline
Full Member
***
Karma: 0
Posts: 138
Arduino rocks
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

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.

Logged

Palmetto, FL USA
Offline Offline
Full Member
***
Karma: 0
Posts: 138
Arduino rocks
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Here's a sample of what you would want to accomplish. I haven't tested this, but will load the sample to my Arduino and refine it in a bit. It should be very close to what you want though. The big question is if you can call other routines in the class, or only RunScript.

One other point, in the code above you are printing "not receiving data" when the boolean is false, but I don't see where you are using the data from the serial port when the boolean is true. I think that you would want to use "Print(ReceiveSerialData())" to send the serial data back to the app.


Code:

Public Class port

' I wrapped this in a class, but you would need to work it into the grasshopper class

      Private WithEvents CPort As IO.Ports.SerialPort      'port with events
      Private TempBuffer As String = String.Empty        'holds the input between events until we get a new line
      Private Delegate Sub HandleComPortDelegate()      'allows com port to run in a background thread without blocking
      Private StoredValue As String = String.Empty      'holds value from port until you call for it

      Sub OpenPort()            'called early in the app, before the port is ever needed. This attaches the port, and opens it to listen.
            CPort = New IO.Ports.SerialPort

            Try
                  CPort = My.Computer.Ports.OpenSerialPort("COM3", 9600)
            Catch ex As Exception
                  MessageBox.Show("no port")
            End Try
      End Sub

      'this would be better as a property, but I don't know how Grasshopper handles properties
      Function GetValue() As String
            Return StoredValue
      End Function

      'this is fired by the port when it has data
      Private Sub CPort_DataReceived(ByVal sender As Object, ByVal e As System.IO.Ports.SerialDataReceivedEventArgs) Handles CPort.DataReceived
            Dim HndlComPort As New HandleComPortDelegate(AddressOf HandleComPort)             'declare thread
            HndlComPort.Invoke() ' invoke a new delegate to digest the events

      End Sub

      Private Sub HandleComPort()      'background handler for com port

            TempBuffer &= CPort.ReadExisting  'append into tempbuffer
            If (Strings.Right(TempBuffer, 2) = vbCrLf) Then        'if end of item            'this may need to be changed, since Arduino's println may use cr or lf only. I can't remember at this point.
                  StoredValue = TempBuffer               'offload
                  TempBuffer = String.Empty               'reset
            End If

      End Sub

      'should be called when the port is no longer needed.
      Private Sub ClosePort()

            If CPort.IsOpen = True Then
                  CPort.Close()
            End If
            CPort.Dispose()

      End Sub

End Class


Logged

Pages: 1 [2] 3 4 5   Go Up
Jump to: