Jump to content

Keynotfound when transfering from .net app to Vision130


Marco G

Recommended Posts

Hey there,

I've been tweaking around a bit and i got the software i'm writing at the point that it does connect to the plc and reads things like the PLC name,

However: When i want to send data to the plc it gets a error: 

System.Collections.Generic.KeyNotFoundException was unhandled

  Message=De gegeven sleutel is niet aanwezig in het woordenboek.
  Source=mscorlib
  StackTrace:
       bij System.Collections.Generic.Dictionary`2.get_Item(TKey key)
       bij Unitronics.DataTables.Collections.DataTablesCollections`2.get_Item(TKey key)
       bij Voersysteem.Hoofdscherm.btnWrite_Click(Object sender, EventArgs e) in C:\Users\Marco\Documents\Visual Studio 2010\Projects\Voerkar v0.1\Voerkar v0.1\homescreen.vb:regel 445
       bij System.Windows.Forms.Control.OnClick(EventArgs e)
       bij System.Windows.Forms.Button.OnClick(EventArgs e)
       bij System.Windows.Forms.Button.OnMouseUp(MouseEventArgs mevent)
       bij System.Windows.Forms.Control.WmMouseUp(Message& m, MouseButtons button, Int32 clicks)
       bij System.Windows.Forms.Control.WndProc(Message& m)
       bij System.Windows.Forms.ButtonBase.WndProc(Message& m)
       bij System.Windows.Forms.Button.WndProc(Message& m)
       bij System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m)
       bij System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m)
       bij System.Windows.Forms.NativeWindow.DebuggableCallback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)
       bij System.Windows.Forms.UnsafeNativeMethods.DispatchMessageW(MSG& msg)
       bij System.Windows.Forms.Application.ComponentManager.System.Windows.Forms.UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop(IntPtr dwComponentID, Int32 reason, Int32 pvLoopData)
       bij System.Windows.Forms.Application.ThreadContext.RunMessageLoopInner(Int32 reason, ApplicationContext context)
       bij System.Windows.Forms.Application.ThreadContext.RunMessageLoop(Int32 reason, ApplicationContext context)
       bij Microsoft.VisualBasic.ApplicationServices.WindowsFormsApplicationBase.OnRun()
       bij Microsoft.VisualBasic.ApplicationServices.WindowsFormsApplicationBase.DoApplicationModel()
       bij Microsoft.VisualBasic.ApplicationServices.WindowsFormsApplicationBase.Run(String[] commandLine)
       bij Voersysteem.My.MyApplication.Main(String[] Args) in 17d14f5c-a337-4978-8281-53493378c1071.vb:regel 81
       bij System.AppDomain._nExecuteAssembly(RuntimeAssembly assembly, String[] args)
       bij System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args)
       bij Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
       bij System.Threading.ThreadHelper.ThreadStart_Context(Object state)
       bij System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean ignoreSyncCtx)
       bij System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
       bij System.Threading.ThreadHelper.ThreadStart()
  InnerException: 
 

 

The code where the error occur's:
    
 If Not plc Is Nothing Then
            Dim dt As Unitronics.DataTables.DataTables
            dt = New DataTables(plc, DataTablesReadOptions.StructureAndValues) ' You can also read just the structure. depending on your needs

            ' we are working with unitronics data tables, not the .net data tables. those are 2 different objects
            Dim table As Unitronics.DataTables.Table
            table = dt.Tables("verzenden")

            ' alter the data on the tables, for example:
            table.Rows(0).Cells(0).Fields(0).Value = lblvoerzend1.Text
            table.Rows(0).Cells(1).Fields(0).Value = lblzendgewicht1.Text
            table.Rows(0).Cells(2).Fields(0).Value = lblvoerbaknr.Text

            
            dt.SaveToUDT("C:\Voerkar\" & sDateTimePicker & ".udt")

            ' We can now read the file to a bytes array voor het schrijven naar d eplc
            Dim fileContent As Byte()
            fileContent = System.IO.File.ReadAllBytes("c:\Voerkar\" & sDateTimePicker & ".udt")

            plc.SD.WriteFile(SD.SdFolder.EXCEL_EXCEL1, sDateTimePicker & ".udt", fileContent, Nothing)
        End If

To be precise: Where the code wants to transfer the data(3 numeric items, for example 10, 20 and 2) to the datatable at table = dt.Tables("verzenden")

 

 

Link to comment
Share on other sites

Thanks, that was indeed the problem, i named the table in the plc something else then i did in the code. Now that part works. :) I thought i did something wrong in the code but couldn't find it. 

Now it's up to the last part of the inserting to the datatable(i also have a other issue but i think that's related to this one so let's finish this first).

I don't get a error, yet when i use visiLogic to read the datatable in the PLC, the inserted data(some numbers) are not there, it's all "0"

Link to comment
Share on other sites

Hi, I see that you write a file to the SD. Are you loading that file afterwards by ladder from the SD Card into the Data Table?

Hmm, i do indeed got a part where i write to SD, but i thought this code would write directly to the PLC.

This is how i have it right now.

When i use the part where it save's to the pc first i get a error at the first(bold) savetoUDT statement:

  
dt.SaveToUDT("C:\Voerkar\" & sDateTimePicker & ".udt") 

            ' We can now read the file to a bytes array voor het schrijven naar d eplc
            Dim fileContent As Byte()
            fileContent = System.IO.File.ReadAllBytes("c:\Voerkar\" & sDateTimePicker & ".udt")


            plc.SD.WriteFile(SD.SdFolder.EXCEL_EXCEL1, sDateTimePicker & ".udt", fileContent, Nothing)
        End If
Cannot save into UDT file format from XML or FDT file formats, or from Data Tables Structure that was read from PLC.

 

Communicating with a PLC is quite new for me so bear with me. ;)

Link to comment
Share on other sites

Hi, you are correct. Because the file was originally created from the PLC and might contain several tables, we don't allow creating a UDT file.

You can save it as FDT (Use the Save function, which accepts path and file type).

 

If you want to directly write to the PLC, then why do you use a file?

 

You can do:

table = dt.Tables("verzenden")

table.Write();  (which will write the whole table back top the PLC).
Link to comment
Share on other sites

 

Hi, you are correct. Because the file was originally created from the PLC and might contain several tables, we don't allow creating a UDT file.

You can save it as FDT (Use the Save function, which accepts path and file type).

 

If you want to directly write to the PLC, then why do you use a file?

 

You can do:

table = dt.Tables("verzenden")

table.Write();  (which will write the whole table back top the PLC).

 

Thanks. :) I will look into it, the using of a file is prefered, but just to make it easier to look back at the settings previously used. 

I believe a collegue of mine already has some experience with the Unitronics datatables so he can help me set up a checker so that tasks are executed at a by the user specified date and time. 

I'm also busy with some other things, but if it worked i'll report it to you.

Link to comment
Share on other sites

No, SaveToUDT saves the file as UDT (it won't save the file to other formats).

You can use the Save function (rather than SaveToUDT)

 

This function accepts a filename and file type (an enum), which can be either XML, FDT or UDT. 

(If UDT is chosen, then SaveToUDT is being called).

 

 

As much as I remember, the PLC doesn't let you load an FDT file from the ladder (but rather than from the INFO), but in your case, you can save the file as FDT for later use (if you want to save the data, and load it few hours later and only then write it to PLC).

If you intend to write the data immediately then table.Write looks like a good choice.

Link to comment
Share on other sites

No, SaveToUDT saves the file as UDT (it won't save the file to other formats).

You can use the Save function (rather than SaveToUDT)

 

This function accepts a filename and file type (an enum), which can be either XML, FDT or UDT. 

(If UDT is chosen, then SaveToUDT is being called).

 

 

As much as I remember, the PLC doesn't let you load an FDT file from the ladder (but rather than from the INFO), but in your case, you can save the file as FDT for later use (if you want to save the data, and load it few hours later and only then write it to PLC).

If you intend to write the data immediately then table.Write looks like a good choice.

Hmm, then saving to FDT isn't of much use(except the future reference). 

If i use the table.write() function, do i need to specify only the tablename in it or also the textbox.text values that will fill the table? Because if i use the code i got sofar it won't give me any errors but i have the feeling that it's not doing much either because visilogic shows no data in the datatable.

 

On the plus side, i resolved all the earlier errors.  

        Dim dt As Unitronics.DataTables.DataTables
        dt = New DataTables(plc, DataTablesReadOptions.StructureAndValues) ' You can also read just the structure. depending on your needs

        ' we are working with unitronics data tables, not the .net data tables. those are 2 different objects
        Dim table As Unitronics.DataTables.Table
        table = dt.Tables("verzenden")
        table.Write()

        ' alter the data on the tables, for example: (zelf al wat extra velden toegevoegd!)
        table.Rows(0).Cells(2).Fields(0).Value = lblvoerbaknr.Text
        table.Rows(0).Cells(0).Fields(0).Value = lblVoerzend.Text
        table.Rows(0).Cells(1).Fields(0).Value = lblzendgewicht.Text
Link to comment
Share on other sites

Off course you need to put the data in the table first... how else would the PC know what you want to write?

Dim dt As Unitronics.DataTables.DataTables
        dt = New DataTables(plc, DataTablesReadOptions.StructureAndValues) ' You can also read just the structure. depending on your needs

        ' we are working with unitronics data tables, not the .net data tables. those are 2 different objects
        Dim table As Unitronics.DataTables.Table
        table = dt.Tables("verzenden")

        ' alter the data on the tables, for example: (zelf al wat extra velden toegevoegd!)
        table.Rows(0).Cells(2).Fields(0).Value = lblvoerbaknr.Text
        table.Rows(0).Cells(0).Fields(0).Value = lblVoerzend.Text
        table.Rows(0).Cells(1).Fields(0).Value = lblzendgewicht.Text

        table.Write()
Link to comment
Share on other sites

This is a real-time system, so every variable must have a fixed position in RAM, meaning, the table must be predefined and must have a fixed or max size (else, if it keeps growing, then it will need to be reallocated).

 

 

You can define the number of rows you want in teh project itself. The use an MI for pointing to the next free row.

(So the MI will be 0 when the project is first downloaded to the PLC).

 

Now, each time you want to write the rows to the table, then read the MI (for example, now it is 15), In your table, start writing to row 15 (instead of row 0), write the data to the table, and then increase the value of the MI to 16.

Link to comment
Share on other sites

Hello,

If i understand you correctly, i have to keep the pc software the same ( table.rows(0).cells(0).fields(0)) and write the ladder in such a way that when it sees that i want to add a entry to the table, it automatically writes it to a new line? 

Cool. :) thought it was just me because i couldn't find a solution in vb.net. 

Link to comment
Share on other sites

No, if you want to change the start row, then you will need to change your PC software as well.

 

Your PC software will read some MI, use it as a row number, change the values on the Data Tables on the PC (in the correct rows, not from row 0), and Write (or use Update command), and then increase the value of the MI by one by sending a command from the PC.

Link to comment
Share on other sites

Okay... and how can i do that? I thought i already got the pc part working and just needed to change some things in the ladder to make it working like i wanted. 

Row 0 doesnt have to be renewed, all it has to do is add a extra entry to the plc datatable every time i send 1(or multiple) rows to the plc. 

Link to comment
Share on other sites

Use plc.ReadWrite

 

ReadWriteRequest[] rw = new ReadWriteRequest[1];

rw[0] = new ReadOperands()
            {
                OperandType = OperandTypes.MI,
                StartAddress = 100,
                NumberOfOperands = 1,
            };
 
plc.ReadWrite(ref rw);
var startRowIndex = Convert.ToInt16(((rw[0] as ReadOperands).ResponseValues as object[])[0]);
 
// Your code here... but instead of start putting data to row 0, start with row startRowIndex, for example:
table.Rows(startRowIndex).Cells(2).Fields(0).Value = lblvoerbaknr.Text
table.Rows(startRowIndex).Cells(0).Fields(0).Value = lblVoerzend.Text
table.Rows(startRowIndex).Cells(1).Fields(0).Value = lblzendgewicht.Text
 
// Now you increment startRowIndex  by the number of rows you intend to write (in this example, only 1 row):
startRowIndex++;
 
// Now you write the table (You can also use Update, which will only update the cells that you have altered)
table.Write()   // or table.Update()
 
// Now we need to update the value of MI100 in the PLC.
 
rw[0] = new WriteOperands()
            {
                OperandType = OperandTypes.MI,
                StartAddress = 100,
                NumberOfOperands = 1,
                Values = new object[] { startRowIndex }
            };
 
plc.ReadWrite(ref rw);
Link to comment
Share on other sites

Hey, I adjusted the code(see below) 

Right now, it compiles without error but it gives the error: "The number of Operands to read cannot be less than 1" on 

rw(0) = New ReadOperands
        plc.ReadWrite(rw)

The complete code:

  Dim rw() As ReadWriteRequest = New ReadWriteRequest((1) - 1) {}
        rw(0) = New ReadOperands
        plc.ReadWrite(rw)
        Dim startRowIndex = Convert.ToInt16(CType(CType(rw(0), ReadOperands).ResponseValues, Object())(0))

        table.Rows(startRowIndex).Cells(3).Fields(0).Value = DateTimePicker1.Text 'datum en tijd
        table.Rows(startRowIndex).Cells(2).Fields(0).Value = lblvoerbaknr.Text
        table.Rows(startRowIndex).Cells(0).Fields(0).Value = lblVoerzend.Text
        table.Rows(startRowIndex).Cells(1).Fields(0).Value = lblzendgewicht.Text
     
        ' Now you increment startRowIndex  by the number of rows you intend to write (in this example, only 1 row):
        startRowIndex = (startRowIndex + 1)
        ' Now you write the table (You can also use Update, which will only update the cells that you have altered)
        table.Write()
        ' or table.Update()
        ' Now we need to update the value of MI100 in the PLC.
        '30-1-15 ANDERS dan bron! aangepast naar .net en code lichtelijk veranderd! Broncode: 
        Dim Write As WriteOperands = New WriteOperands()
        rw(0) = Write
        With Write
            .NumberOfOperands = 1
            .OperandType = OperandTypes.MI
            .StartAddress = 100
            .NumberOfOperands = 1
            .Values = New Object() {startRowIndex}

        End With

        plc.ReadWrite(rw)

Link to comment
Share on other sites

Off course it gives you that... On the read request you don't tell it what you want to read (what type, what address and how much)

  Dim rw() As ReadWriteRequest = New ReadWriteRequest((1) - 1) {}
Dim Read As WriteOperands = New ReadOperands()
rw(0) = Read
With Read
.NumberOfOperands = 1
.OperandType = OperandTypes.MI
.StartAddress = 100
.NumberOfOperands = 1
End With
        plc.ReadWrite(rw)
        Dim startRowIndex = Convert.ToInt16(CType(CType(rw(0), ReadOperands).ResponseValues, Object())(0))

        table.Rows(startRowIndex).Cells(3).Fields(0).Value = DateTimePicker1.Text 'datum en tijd
        table.Rows(startRowIndex).Cells(2).Fields(0).Value = lblvoerbaknr.Text
        table.Rows(startRowIndex).Cells(0).Fields(0).Value = lblVoerzend.Text
        table.Rows(startRowIndex).Cells(1).Fields(0).Value = lblzendgewicht.Text
     
        ' Now you increment startRowIndex  by the number of rows you intend to write (in this example, only 1 row):
        startRowIndex = (startRowIndex + 1)
        ' Now you write the table (You can also use Update, which will only update the cells that you have altered)
        table.Write()
        ' or table.Update()
        ' Now we need to update the value of MI100 in the PLC.
        '30-1-15 ANDERS dan bron! aangepast naar .net en code lichtelijk veranderd! Broncode: 
        Dim Write As WriteOperands = New WriteOperands()
        rw(0) = Write
        With Write
            .NumberOfOperands = 1
            .OperandType = OperandTypes.MI
            .StartAddress = 100
            .NumberOfOperands = 1
            .Values = New Object() {startRowIndex}

        End With

        plc.ReadWrite(rw)
Link to comment
Share on other sites

Hey, Thanks.

I think there a error though. 

 Dim rw() As ReadWriteRequest = New ReadWriteRequest((1) - 1) {}
        Dim Read As WriteOperands = New ReadOperands() 
        rw(0) = Read
        With Read

It says writeoperand AND readoperand so that gives a error. When i change the readoperand to writeoperand i get the ComDriveException "Values cannot be Null in a Write Operands request"

And if i switch it all to read: "'index' must be non-negative and less than the number of rows in table.

I checked the fields, removed fields and tested some things but the fields do have a value(default value = 0, but it also doesnt work if i enter a value like 24)  
 

 

I suspect that the error comes from the PLC. 

I havn't figured out how to program the plc to make it store the newest empty row in a MI, i think i will ask a collegue for help. 

Parameternaam: index "
Link to comment
Share on other sites

Yes, I've copy pasted it from your code and forgot to change a small part of it. It is supposed to be ReadOperands

(You want to first read the value of the MI, which is the start row)

 

 

My example uses MI 100.

This MI might be in use by your ladder program... If not, it might also have a value from previously downloaded project since those registers are retained.

 

So, assuming your Data Table on the PLC contains a total of 50 rows, and the value of MI 100 is either smaller than 0 or greater than 49, then  you will get the exception: 'index' must be non-negative and less than the number of rows in table

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...