Pages: 1 2 3 [4] 5   Go Down
Author Topic: Sending Data to Serial Port through VB  (Read 6445 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

Andy,

Sorry, that was a message left from my own test app for testing a Blue Tooth serial device. If you are seeing it then the port could not be opened, but it's masking the actual message.

Change it to:

MessageBox.Show(ex.tostring)

and it will show the complete message, but I suspect that it's not gaining access to the port. My thought is that with the loop at half a second, the open port is getting called multiple times. I'll put something together to stop it from trying to open it a second time.

The OpenPort routine creates a new instance of the SeriaPort class, and attempts to open the port specified. If it errors, it jumps to the "Catch" part of the code to catch the error.

No problem on the help, I just wish I had a copy of Rhino, Grasshopper in front of me to figure it out, oh well.

Logged

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

You can always download the trial version http://www.rhino3d.com/download.htm.  This one is the full version... however, it only allows you to save Rhino 25 times... You'll also want the Grasshopper plugin, which is free: http://grasshopper3d.ning.com/forum/topics/grasshopper-060019-available.  The nice thing about this setup... is that you can save as many Grasshopper files as you want... as long as you don't save the actual Rhino files (The Grasshopper interface is a completely different interface... so you save as many Grasshopper files .ghx without ever causing the Rhino eval version to expire...I think this would make sense if you install both packages).  I've actually written a 150 page manual about helping beginners get up to speed with the plugin and you can download it for free on my website: http://www.liftarchitects.com/downloads/.  Maybe this could help us figure this thing out.
Logged

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

Hi Rob.  I hope you had a great weekend.  I was wondering if you had had a chance to look at the issue that was creating the error trap when opening the port... that we talked about on Friday.
Logged

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

Hey Andy,

Had a long weekend of work!

If you can post the scipt class (or email it to me, there should be a link at the bottom of the message), I will add a little code to only try to open the port if it isn't open. That way I'll be changing your current version, instead of giving you a bunch of pieces of code to splice in.

Rob
Logged

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

Hi Rob,
Sorry to hear you had to work all weekend smiley-sad  I actually have the latest file at home (I don't have it here at work).  I can post/email you the current script file as soon as I get home in a few hours (probably around 6:30 PST).  Thanks again for your help.
Logged

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

Rob, here is the code where I last left off.  Basically, I'm feeding a variable input called StepNumber (which is either a 0,1, or 2) to call one of the three different Case functions.  We figured out that it's getting stuck when the Timer component tries to rebuild the solution that it's trying to continually re-open the port.  

Code:
 Sub RunScript(ByVal StepNumber As Integer)
  
    Select Case StepNumber
      Case 0
        OpenPort()
        print("Port has been opened")
      Case 1
        print(storedvalue)
      Case 2
        ClosePort()
        print("Port has been closed")
    End Select
 
  End Sub

#Region "Additional methods and Type declarations"

  ' 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 Region
Logged

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

Andy,

Give this a shot. I moved the port creation so that it is created during the class creation, and added a check so that we don't call open if we are already open.

Code:

      Sub RunScript(ByVal StepNumber As Integer)

            Select Case StepNumber
                  Case 0
                        OpenPort()
                        Print("Port has been opened")
                  Case 1
                        Print(StoredValue)
                  Case 2
                        ClosePort()
                        Print("Port has been closed")
            End Select

      End Sub

#Region "Additional methods and Type declarations"

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

      Private WithEvents CPort As New 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.
            Try
                  If CPort.IsOpen = False Then
                        CPort = My.Computer.Ports.OpenSerialPort("COM3", 9600)
                  End If
            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 IsNot Nothing Then
                  If CPort.IsOpen = True Then
                        CPort.Close()
                  End If
                  CPort.Dispose()
            End If
      End Sub
#End Region


Logged

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

Hi Rob,
I tried out the script you wrote.  When I first run the script, I make sure that the StepNumber is set to 0 to open the port.  Then I switch the StepNumber to 1... but nothing happens.  I did put in another print line just to see if it was calling Step 1... and it does make it into the loop... but it isn't returning any values for the StoredValue from the COM port.  So, I then switch the StepNumber to 2 to close the port.  When I retrace the steps (meaning... I've connected a slider to the input... so to get back to 0, I first have to slide to 1 and then to 0 to open the port)... The funny thing is, that when I get back to 0... I get that same error message that says "No Port".  Which seems odd because you would think that the port would have been closed when I took the slider up to 2.  Perhaps there is an error in the close port method too.  Do you have any ideas?  Also, why would it not be reporting whatever the StoredValue is the first time I input the number 1 into the StepNumber?  Any ideas?  
Logged

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

Actually! It worked... I don't know what the difference was... but I unconnected the Arduino and closed the program... and re-tried everything... Only this time when I opened the file... it works.  I'm getting a stream of data from the potentiometer... just like the serial monitor.  It's great...
I did notice something odd though.  When I go and update the code (I wanted to take the extra print line out of the VB script)... when I return to the Grasshopper canvas... even though the StepNumber is set to 1... I'm not getting anything coming out of the Out box... So, I plugin the number 2 to close the port... and when I try to re-open the port by plugging in the number 0... I get that error message again, saying "No Port".  Then, I can no longer get the streaming numbers back... unless I close the entire program and re-launch it.  Can you think of any ideas why this would be?
Logged

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

Also... I have one other follow up question... I noticed that the numbers coming in over the COM port are some value between 0-1024 (this makes sense... I have a potentiometer coming in so it would be read as a 10bit number)  However, I've noticed that the data type is a "string" and not an integer... But, this is a little unfortunately because I'd like to be able to take those integers and feed them into some component that requires a number... but since Grasshopper thinks the data coming in is a String... it can't read the numbers... How would I modify the code to convert those strings to integer values?  Thanks again for all the help... I feel like we made huge progress (even though there are still some kinks to work out).  
Logged

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

Andy,

It sounds like the port is not being closed, or released properly.
Most likely it is related to the way that the port object handled when Grasshopper releases the object to allow you to edit it, but it could be that the port can't be recreated properly.

You could change the "MessageBox.Show("no port")" line to "messagebox.show(ex.tostring)" or ex.message and you should get a little more descriptive error.

Logged

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

How are you trying to get the numbers? I would assume that the print function returns a string value, but depending upon what Grasshopper expects, they could certainly be converted.
Logged

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

It's really weird... Sometimes I get that error message that I just told you about... but I unplugged the Arduino again... and closed Rhino... I restarted everything... and now everything is working perfectly.  I changed the process of feeding the StepNumber... Before I was using a slider so that I either had to go from 0,1, and then 2... but to get back to 0 to open the port... you had to first pass the number 1 to the code... which I think was part of the problem... Now, I just have three parameters, each containing a single number.  Now, I just connect the first parameter to open the port... Then I connect the Get Value parameter (number 1).  Then I close the port... only now, I just re-connect the Open Port parameter and re-trace my steps... and it seems to work.  
So, as for the string to number conversion...  The string is just coming in because we have defined the "Private StoredValue As String = String.Empty".  Wouldn't we want to change this part of the code so it thinks the data coming in isn't a string but instead a number?  I can't think of a way off the top of my head for Grasshopper to convert the string to a number after the fact.  I will play around with some different techniques... but if you think changing the VB code to read the numbers directly... let me know.
Logged

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

Try changing your print statement to this:

Print(CInt(Val(StoredValue))) That will convert it to an integer before it sends it back to Grasshopper.
Logged

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

This is great... It's totally working... I rigged up my arduino to read a simple photocell setup... I used your trick to convert the string to a number before sending it to the text panel... And then I just feed the data from a text panel to drive the radius of a circle... I know that's pretty simple... but it totally works.  Below is a screenshot of the definition setup and I've set the Timer interval to 100ms so the data stream is fairly smooth (I think 50ms is the lowest I can go in Grasshopper).  So, I just shine a flashlight on the photocell... and the circle changes shape... My next step is going to be reading in the data from a wii remote (I've already gotten the wii remote to drive a pan/tilt servo... but I wanted to try to recreate the motion in Grasshopper).  But, I think the steps should be fairly straight forward.  Thanks again for all of you help... I never would have made it this far without your help.  If your ever out in the Bay Area... definitely let me know... I owe you a beer (or several).

http://www.liftarchitects.com/storage/research/Arduino%20to%20Grasshopper_working01.jpg
Logged

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