Palmetto, FL USA
Offline
Full Member
Karma: 0
Posts: 138
Arduino rocks
|
 |
« Reply #15 on: August 20, 2009, 09:33:14 am » |
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
Jr. Member
Karma: 0
Posts: 84
Arduino rocks
|
 |
« Reply #16 on: August 20, 2009, 09:55:06 am » |
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
|
|
|
|
|
Logged
|
|
|
|
|
Palmetto, FL USA
Offline
Full Member
Karma: 0
Posts: 138
Arduino rocks
|
 |
« Reply #17 on: August 20, 2009, 10:20:46 am » |
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
Jr. Member
Karma: 0
Posts: 84
Arduino rocks
|
 |
« Reply #18 on: August 20, 2009, 10:45:09 am » |
Great. I will try it out tonight and let you know how it works. Thanks again!
|
|
|
|
|
Logged
|
|
|
|
|
0
Offline
Jr. Member
Karma: 0
Posts: 84
Arduino rocks
|
 |
« Reply #19 on: August 21, 2009, 11:55:16 pm » |
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  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
Full Member
Karma: 0
Posts: 138
Arduino rocks
|
 |
« Reply #20 on: August 22, 2009, 12:00:37 am » |
For some reason I can't see the images again.
|
|
|
|
|
Logged
|
|
|
|
|
|
|
Palmetto, FL USA
Offline
Full Member
Karma: 0
Posts: 138
Arduino rocks
|
 |
« Reply #22 on: August 22, 2009, 09:44:41 am » |
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
Jr. Member
Karma: 0
Posts: 84
Arduino rocks
|
 |
« Reply #23 on: August 22, 2009, 10:06:32 am » |
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); }
|
|
|
|
|
Logged
|
|
|
|
|
Palmetto, FL USA
Offline
Full Member
Karma: 0
Posts: 138
Arduino rocks
|
 |
« Reply #24 on: August 22, 2009, 10:18:53 am » |
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
Jr. Member
Karma: 0
Posts: 84
Arduino rocks
|
 |
« Reply #25 on: August 22, 2009, 10:30:18 am » |
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
Full Member
Karma: 0
Posts: 138
Arduino rocks
|
 |
« Reply #26 on: August 22, 2009, 10:31:09 am » |
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
Jr. Member
Karma: 0
Posts: 84
Arduino rocks
|
 |
« Reply #27 on: August 22, 2009, 10:32:43 am » |
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
Full Member
Karma: 0
Posts: 138
Arduino rocks
|
 |
« Reply #28 on: August 22, 2009, 10:36:12 am » |
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
Full Member
Karma: 0
Posts: 138
Arduino rocks
|
 |
« Reply #29 on: August 22, 2009, 11:08:09 am » |
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. 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
|
|
|
|
|
|