Software > Software

Dweeno Link: Visual Basic robot control

(1/2) > >>

I'm not sure how much interest there will be in this. Most of the VB posts are rather old it seems but the Arduino Android App topic got a lot of interest, so here goes nuthin'.

This is a how-to for writing a Visual Basic program and an Arduino sketch, to allow both of them to communicate with each other using Serial over a USB cable.

I have named it Dweeno Link to clarify it from other similar efforts.
In the online world, everything needs a unique name to identify it.
The name Dweeno Link currently has no results in Google, so I'm using that.

The Dweeno Link Visual Basic program doesn't do anything that requires an Arduino specifically, it is just a program that allows two-way communication over the USB/serial port. You could use it with PICs or stamps or propellers or whatever else microcontroller board you wanted to, as long as you can make them do serial over USB.

The only hardware that you need to try this example is a Windows PC, an Arduino Uno/Nano/Mega and the USB cable to connect the Arduino board to your PC. Hooking up a couple normally-open push buttons and a couple LEDs + resistors to the Arduino helps too if you have them, but isn't necessary to see that the example provided works.

The only software you need is the Arduino IDE and Microsoft Visual Studio Community Edition, both of which are free downloads.

The VB program and Arduino sketch I wrote is tested with Arduino Unos, Nanos and Megas.

The Visual Basic program is called Dweeno Link, and the Arduino sketch is called Dweeno Slave.

When checked for an Uno, Dweeno Slave uses 12% of program storage space and 15% of dynamic memory.
You would probably want to add some more functions to it--but even on an Uno or Nano, you still have a lot of space left to do that.

When built, the version-1 of Dweeno Link (the VB program) is about 20kb.

The Dweeno Slave sketch has some functions already written in.
Two of them send a message to the PC when either of the two buttons is pressed.
Two of them are for blinking the pin-13 LED slow and fast, as many times as you tell it.
Four are for reading and writing to Arduino pins (the functions for reading pins report the result back to the PC).
The last one is one that uses the Arduino to intentionally cause a time delay in the Visual Basic program.
And from those you can see how to add more functions of your own.

I wrote this because there's a lot of other programs that can communicate with an Arduino over serial/USB, but many of them are pre-constructed products that limit what you can do with them.
Also, most of them cost money....
Visual Studio Community is free for hobbyists to use, and Visual Basic is a 'real' programming language that doesn't limit how you use it.

There is a lot of attempts online to do this in VB already, but most of those are not 2-way messaging, and when I searched I found that many of them were so old that they wouldn't even work in the current version of Visual Studio. Dweeno Link was written in the current version of Visual Studio 2017.

I also could have done this in C#, but VB is still a little easier to use I think.

I looked into writing a cross-platform version in Eclipse/Java, but ran into problems with finding a suitable Java cross-platform serial port library.

I may write a Linux version eventually, but I don't have a Linux computer around so I currently have no way to do that now... And most people still use Windows, so (I think) a Linux version wouldn't have nearly as wide of an appeal as something that can run on Windows.

A lot of other pages online show you how to make simple programs in various programming languages (many even in VB) to send individual characters to the Arduino, but they skip explaining how to do anything useful with it. They don't provide any way for the Arduino to respond back to the PC at all, and because of this, they are only good for human ?remote control? use. They aren't really suitable for using the PC to control the Arduino on its own. You can use Dweeno Link just as a human-operated remote control if you want, but it also allows you to have the PC control the Arduino all on its own.

In order for the computer to automatically control the Arduino, the PC has to be prevented from sending commands faster than the Arduino can carry them out. That requires a messaging setup that works both ways. The Arduino gets a command sent to it, and when it is done performing that command, it has to reply back to the PC to ask for another command. The Arduino also needs the ability to send data back to the PC as well. Providing two-way communication requires writing a multi-threaded program, and most amateur Arduino users aren't familiar enough with PC/OS programming to do that.
So I'm going to show how to do that part.

Visual Studio Community is the free version of Microsoft's Visual Studio programming IDE, available on Microsoft's own website. To download that, you need to register an MSN or a Microsoft account (and for that you need an email address) but it doesn't cost any money to do. They just want the email address so they can send you developer spam now and then.
Every few months the Visual Studio program makes you verify the email address that you used to register your Microsoft account. If you don't do that when it asks, then Visual Studio STOPS WORKING. So you MUST use a real email address that you have access to. Don't use a throwaway email address for your Microsoft account!

Also another warning:
The Microsoft program that you need here is Visual Studio Community, that is for programming with Visual Basic and C#. It is a BIG download of several hundred megabytes.

Microsoft also has a free coding text editor now called ?Visual Studio Code?, but that is the wrong thing. It is just a small download of only a few megabytes, but it won't work for this.

Another thing the other pages don't explain real well is how to do anything useful with the single characters that the Arduino receives. As is typical with most other microprocessors, the Atmel chips used in the Arduino boards can only retrieve one byte at a time from their serial input buffer. You need a way to reconstruct the individual characters into -some- kind of useful data.
I'm going to show an Arduino sketch that does that too.

The message system that I use here has a particular format.

For the messages that you sent TO the Arduino, each SINGLE message is limited to sending a maximum of twelve positive integer numbers, and each of those numbers can be up to 4 digits long.

Each number is followed by a colon, and at the end of each line you must have an asterisk because the asterisk is used as the end-of-line marker. The asterisk is a printing character and so it's much less confusing to use than the typical invisible cr/lf. 

So a message of twelve values would look sort-of like this:
--where each of the XXXX parts could be any number up to four digits long.

If you don't need to send twelve values, you don't have to.
You just need the colon after every number, and the asterisk at the very end.
Below is shown an example that only has five numbers (but with XXXX where the numbers would be):

Also you don't need to send numbers that are four digits long, if you don't need such big numbers.
You do not need to insert leading zeros into the unused number places, since these fields get converted back to real-actual-integer-numbers in the Arduino and any leading zeroes would get dropped anyway.
One of the real actual example commands is as follows:
Where {101} is the command for [blink fast], and {30} means [thirty times]. But we'll get to that later below...

What if you want to do something that needs more than 11 different values? Say, 20 values?
Then you just send the values in two different messages of two different function numbers, with no more than 11 values in each (the first value would be the function number).
For transferring 20 pieces of data to the Arduino, the first and second messages could have 10 values each.
The first message could be numbered 138, and the Arduino just stores the data from the first message.
The second message could be numbered 139, and the Arduino stores the data from the second message, and then begins performing the command.
Since the two messages are numbered different, the Arduino will know which one is which. You only need to send the commands in the proper order.
--Also those functions don't exist yet.
You would need to write those functions yourself, but you can do that.

Why is there a 12-number limit?
Because the default Arduino serial input buffer is only 64 bytes. If you add up those characters-- 4 digits + a colon is 5 characters per [number]. 5 characters per number x 12 numbers = 60 characters, and adding the asterisk on the end makes 61 characters. Keeping the Arduino's message length under 64 bytes and making the PC wait for an Arduino response means the PC won't ever cause the issue of running over the Arduino's default-size serial input buffer.

(The serial buffer size is just a software setting that can be changed--but it's a bit in-depth, it isn't without side effects and it really isn't necessary anyway since you can just use multiple commands to send more than 11 data values)

Why only allow sending numbers?
Because mostly that's what you would want to send, and it simplifies converting the message on the Arduino side. You only need one coded routine to convert every field to a useful piece of data.

So that is the restriction on what messages to send to the Arduino.
What restrictions are there on messages that the Arduino sends to the PC?
Well... technically... not much really.

The default incoming serial buffer size is 4Kb in Sending that much data back to the PC in one message (from an Arduino!) isn't very likely IMO, and the PC can empty its input buffer WAY faster than the Arduino can send stuff anyway.
Also you can send strings back in the message to the PC if you want, if there was any reason. A PC can handle juggling strings way better than an Arduino can.
The main suggestion I would make (and what I use here) is to use the same format as the messages to the Arduino: values separated by colons, and ended with an asterisk. This way in the PC you can split the message into another String array at the colons, and deal with each field data type separately as you need to.

Lastly before proceeding: I will say right now that the messaging system I've written here is NOT made to be as compact & fast as possible.
Right off--I could have used the bitwise values of bytes and crammed more data into the 64-byte Arduino buffer limit, but doing that would make the code a lot harder to understand (as well as harder to type by hand) so I didn't do it.
You can re-write it like that if you want.

First off, we shall deal with the Arduino sketch.
See this pastebin page:

With each message sent, the Arduino gets a series of numbers + colons + one asterisk.
What do all those numbers in the messages stand for?
Well, whatever you want them to. There is no default definition. You get to write that part. :)

How I do it is like this:
The FIRST numeric field of the message sent to the Arduino is a number that indicates what function to call.
All the other fields are the data that this function needs to work.

Using the first field to indicate the function means that you can *only* have 10,000 possible different functions, but that's probably enough.

This sketch has a number of functions already written.
They appear at the bottom of the sketch, so you can skip all the way down to see them and how they are called.
I began numbering them from 100, but you could start from zero if you wanted to:

button1_pressed() ----- this function reports from the Arduino whenever button 1 on the Arduino is pressed.
There is no way to call this function from the PC; the button #1 pin on the Arduino must be shorted to ground to trigger this message.
This function sends the below message to the PC:

button2_pressed() ----- this function is just like above, but is for button #2 on the Arduino.
This function sends the below message to the PC:

The two button messages above are the only two that send back any string values. All the rest below just send back numbers.

blink_slow(int) ----- this function blinks pin 13, 1-second-on/1-second-off, as many times as you tell it (the int value)
to call this function you send:
 --- where X is the number of times you want it to blink.
It reports back to the PC after it has completed:

blink_quick(int) ----- this function blinks pin 13, four times on and off per second, as many times as you tell it (the int value)
to call this function you send:
------where X is the number of times you want it to blink.
It reports back to the PC after it has completed:

digitalRead_pin_D3() ----- this function digitalReads pin 3 and reports the value to the PC.
you call it by sending the command:
and it answers with the reply:
------where X is the value of the pin, either zero or 1.

analogRead_pin_A3() ----- this function analogReads pin A3 and reports the value to the PC.
you call it by sending the command:
and it answers with the reply:
------where X is the value of the pin, an integer from zero to 1023.

digitalWrite_pin_D4(int) ----- this function digitalWrites pin 4.
you call it by sending the command:
------where X is either zero or 1, that you want the pin set to.
and it answers with the reply:
------to confirm that it has completed.

analogWrite_pin_D5(int) ----- this function analogWrites pin D5 (which is a PWM pin).
------where X is a number from zero to 255.
and it answers with the reply:
------to confirm that it has completed.

arduinoTimeDelay(int t_Minutes, int t_Seconds)] ----- This function causes a time delay.
------where X is the time in minutes to wait.
------Y is the time in seconds to wait.
After the specified time interval has passed, the Arduino replies:

More info about the arduinoTimeDelay() function:
When a lot of people start using Visual Basic, they ask if there is a way to make it slow down or pause while doing something. There are different ways to do that, but--just like the Arduino's delay() function--the simplest and easiest ways have some serious drawbacks overall and so they are hardly ever used in the professional world.

This function allows the Arduino to perform a pause instead, that also causes the PC to pause. And the way that this function is written, it doesn't use the delay() function at all, so it does not interfere with any other tasks that the Arduino is supposed to be doing at the same time. For example: if you press one of the Arduino buttons when a the arduinoTimeDelay() function is running, the Arduino will still send the button message back to the PC.

commandNotFound() ----- if a function number that you send cannot be matched with a function in the Arduino, this function is called and sends back the following message:
You can verify this by entering a non-existent command, such as 999:*

WARNING: other than identifying non-existent commands, none of these functions currently has any error-catching code in them. You must send the correct data they require.

You can use this sketch with the usual Arduino IDE serial monitor, to verify that the sketch is working as it should.
The Arduino sketch is set to a serial speed of 115200, so the serial monitor must also be set to the same speed.
Type the commands and send them, or press the Arduino buttons 1/2, and you should see the responses in the serial monitor's reply window.
Also the pin 13 LED should blink, if you try those two commands.

Note that if you send the LED-blink commands or the arduinoTimeDelay command, the end message will not appear until the function has completed.
That is a very important detail that will get used later on.

The Arduino response messages do not send line feeds, so in the Arduino IDE serial monitor they end up all printing on one line. That isn't a mistake; the line feeds are of no use to the Dweeno Link PC program, so I left them out on purpose.

On to the Visual Basic program.

Microsoft Visual Studio projects are not easily transportable, because they contain a lot of files that have absolute file path references in them. If you make one in one place and then cut and paste it into some other folder on your PC, it isn't going to work anymore. So we aren't doing that.

This program doesn't need a lot of controls so it is easier to just add them manually.

First we need a new Forms project: open Visual Studio, and start a new project.
If the Start page is showing, there is a link there to ?Create new project?. Or-
Go to the top menu bar and click on [File] and then [New Project...].

A New Project dialog window will pop up, with 3 sections. On the left side there is a treeview menu.
1) In the treeview, select [Installed], and then [Templates], and then [Visual Basic].
2) Then in the center pane of the dialog window, select the choice that says ?Windows Forms App (.NET Framework)?. Further to the right it should say ?Visual Basic?.

See image below:

(Mine is black because I set it to that theme. Yours may look gray, but it should still be the same dialog)

3) At the bottom of the center pane of the window, is a long textbox that says ?Name?. Enter a suitable name for the project (such as Dweeno_slave_01). There may be something already in there, but you can delete that first.
4) press the [OK] button in the bottom of the right pane, and after a few moments, you should see a ?blank? window on the main area of the screen.

It should look like the image below, but maybe with a couple differences:
...Again, yours may not be black, but that doesn't matter.
...Mine has a bunch of toolbars and windows showing, that yours may not have showing. That doesn't matter either, right now.
...You just need to have that center area, with the ?blank window? form showing.

Next, you will want to open two more windows: the Properties window and the Toolbox window.
These may be already open. They may also not be in the same place as mine because you can move them around, but that doesn't matter. You just need them open.
If they're not both open, then go to the menu bar and click on [View].
The Properties window option is near the bottom, and the Toolbar window option is about halfway down.
(see the below image)

In the Properties window, there is five little icons along the top.
If the second and third ones are not highlighted, then they need to be.
Click on the THIRD one first, and then click on the second one.
(See the picture below; the two selected icons are in blue squares. This will list the selected object's properties in alphabetical order.)

Next we will create the controls needed.
The picture below (04_form_layout) shows what I made mine look like. You want it to look like this but the exact sizing of anything isn't critical.

Below is the steps to create and name these things properly.
Some of them must be renamed because you will copy & paste the page code in, and your control names must match what is in the pasted code.

Whenever you highlight an object, the Properties window changes to show the Properties of that object, and you can change the individual property settings.

1) Click on the blank form and then in the Properties window, find the property in the left column named Text. To the right it will say Form1. This is the text that will appear in the Window's title bar. You don't NEED to change it, but I changed mine to say Dweeno Link 2017 v1.0. Edit it if you want and hit the [enter] key or mouse-click into any other property value, and the changes will appear on the Form1 [Design] tab. Note that this ONLY changes the window's title bar text; it doesn't change anything else about the program or project.

Non-numbered step: click on the blank form and then click down on the lower-right corner, and drag it down and right to make the form area bigger. This is just to make it easier to place controls on, you can make it smaller again later.

To add controls onto the form in a particular place, you drag the control you want from the Toolbox and then drop it on the form where you want it.

2) Find the GroupBox control (in the Containers sub-section) and drag it onto the form. With the GroupBox still highlighted, go to the property that says Text and change its value to Select port. Arrange this on the left side of the form. You don't need to change the name.

3) Drag another GroupBox onto the right side of the form. Change the Text property of this one to say Serial connection.  You don't need to change the name.

Note: GroupBoxes usually don't really do anything, they are just a way to group related controls visually.

4) Drag and drop the Button tool from the toolbox into the left Select port groupbox. Change the button's Name property to RSP_Button , and then change the button's Text property to Refresh serial ports.

5) Drag and drop the ListBox tool into the left Select Port groupbox, under the button. The ListBox Name property should be ListBox1 and you should leave it as that. Check that the SelectionMode property says One.

6) Drag and drop the Label tool into the left Select Port groupbox. Change the Label's Text property to Selected port: . The Label's name does not need to be changed.

7) In the Toolbox, find the TextBox tool and drag it into the left Select Port groupbox. Change its Name property to SelectedPort_TextBox , and set its ReadOnly property to True.

8) Drag and drop another Label into the right Serial connection groupbox. Change its Text property to Data to send: . The label's name does not need to be changed.

9) Drag and drop another TextBox below the label you just made in the right Serial connection groupbox. Change the textbox's Name property to Sending_TextBox .

10) Drag another Button onto the form, and drop it in the right Serial connection groupbox. Change its Name property to Send_Button , and change its Text property to Send button .

11) Drag and drop another Label into the right Serial connection groupbox. Change its Text property to Data received: . The Label's name does not need to be changed.

12) Drag and drop another TextBox into the right Serial connection groupbox. Change its Name property to Receiving_TextBox , and set its ReadOnly property to True.

Whenever you click on a control, its drag handles appear and you can use them to resize the control.
It may be helpful to drag the Form1 and the groupboxes out bigger to get all the controls in, and then reduce them afterwards.
Drag them around until you get something similar to what I showed in the first image above.


[0] Message Index

[#] Next page

Go to full version