Let's Make Robots!

The Tale of One Pleased Robot Owner

 

I can't tell you how much I am enjoying this FEZ Mini Robot!

My coding in C# is rapidly improving and now I can do just about anything I want, it compiles (not even many warnings!) and runs great on the robot. The Microsoft emulator no longer puts out those error messages (as long as the hardware is attached to the system.)

When I started out I thought maybe I couldn't learn C# but I am happy to be wrong about that. I still have a LOT to learn in C#, but my desire to learn it is VERY strong.

It's true, FEZ is Fricking Easy! :-)

I had to get the mini board with the robot, but now I want a bigger FEZ board in a bigger robot.

UPDATE: This is better than I could have ever expected! This thread has now become a discussion from beginner (me) to seasoned programmer (Geir) about programming in C#. Others are becoming involved now too. That is sooooo cool!

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.

 

Hi Will

I think you might overestimate my C# skills, but I’ll try to answer some of your questions.

The source files for C# has the file extension .cs and yes they are the source files that the compiler uses to build the executable code. In C# they are called class files and you can add as many as you need to your project. I normally split up my program in to different class files. For example I could have a file called COM_LCD.cs that holds the class for the LCD handling, or a GPS.cs for doing all the work on a GPS stream.

So if we look at the COM_LCD.cs file 

using System;
using System.Threading;
using Microsoft.SPOT;
using System.Text;
using System.IO.Ports;
using GHIElectronics.NETMF.FEZ;
using GHIElectronics.NETMF.Hardware;

namespace SauID

{

    class COM_LCD

    {

        static PWM Buzz;

        private SerialPort LCDhandle;
        const byte DISP_ON = 0xC;           //Turn visible LCD on  
        const byte DISP_OFF = 0X08;   
        const byte CLR_DISP = 0x01;         //Clear display             
        const byte CUR_HOME = 2;            //Move cursor home and clear screen memory            
        const byte SET_CURSOR = 0x80;       //SET_CURSOR + X : Sets cursor position to X             
        const byte MOVE_CURSOR_LEFT = 0x10;
        const byte MOVE_CURSOR_RIGHT = 0x14;
        const byte SCROLL_RIGHT = 0x1C;
        const byte SCROLL_LEFT = 0x18;
        const byte CURS_UNDERLINE_ON = 0x0E;
        const byte CURS_UNDERLINE_OFF = 0x0C;
        const byte CURS_BOX_ON = 0x0D;
        const byte CURS_BOX_OFF = 0x0C;

        const byte BRIGHTNESS_OFF = 128;
        const byte BRIGHTNESS_40 = 140;
        const byte BRIGHTNESS_73 = 150;
        const byte BRIGHTNESS_ON = 157;

 

        private void Command(byte cmd) 

        { 

            SendByte(0xFE); 

            SendByte(cmd); 

        }  

 

        private void SendByte(byte value)

        {

            byte[] buffer = new byte[1];

            buffer[0] = value;

            LCDhandle.Write(buffer, 0, buffer.Length);

        }

 

        public void ClearScreen() 

        { 

            Command(CLR_DISP); 

        }

 

        public void Biip()

        {

            Buzz.Set(true);

            Thread.Sleep(400);

            Buzz.Set(false);

        }

 

        public void Error()

        {

            for (int i = 0; i < 5; i++)

            {

                Buzz.Set(true);

                Thread.Sleep(200);

                Buzz.Set(false);

                Thread.Sleep(200);

            }

        }

 

        public void ScrollLeft()

        {

            Command(SCROLL_LEFT);

        }

 

        public void SetCursor(byte row, byte col) 

        { 

            Command((byte)(SET_CURSOR | row << 6 | col)); 

        } 

 

        public void BacklightOn()

        {

            Command(BRIGHTNESS_ON);

        }

 

        public void Write(string Tekst)

        {

            string LCDTekst = Tekst + "                ";

            LCDTekst = LCDTekst.Substring(0, 16);

            byte[] buffer = Encoding.UTF8.GetBytes(LCDTekst);

            LCDhandle.Write(buffer, 0, buffer.Length);

            Thread.Sleep(10);

        }

 

        public COM_LCD(string comPort, int baudrate)

        {

            Buzz = new PWM((PWM.Pin)FEZ_Pin.PWM.Di10);

            LCDhandle = new SerialPort(comPort, baudrate);

            LCDhandle.Open();

 

            Command(DISP_ON); 

            Command(CLR_DISP); 

        }

 

    }

}

 

You will see the following things

The using statements includes the .net libraries that is needed for the class

Then you have the namespace that should be the same as your main program

Now the class definition starts with the class COM_LCD statement. All classes must have at least one constructor and that’s the ‘public COM_LCD(string comPort, int baudrate)’ this will build your object and needs two input parameters, the COM port and the baudrate.

All the public functions like ‘public void ClearScreen()’ will be available to the user and recognized by intellicense. So in your main program you could have a line like myLCD.ClearScreen(); 

All private functions are internal functions for this class like ‘private void Command(byte cmd)’ This will not show up when you use the object and will not show up in intellicense.

I can understand that you are a bit confused about this function / method stuff, but think of it this way. A function is a subroutine in the program or class that you’re working on. So if you are in the Main() part of your program you can call functions within that block. If you have an LCD object then you can call a function in that object like myLCD.ClearScreen(); but this is a function within that class and then it is referred to as a method.

So in your Main() program loop you could have a statement like

runMotor(20,60);

And further down (below the main block) you should add your function

 

        static void runMotor(int LeftMotor, int RightMotor)

        {

            ... do something

        }

 

Notice the ‘static’ that says that this function should be available everywhere within the ‘program’ class. ‘void’ indicates that we are not expecting any result back, and you have your parameters…

I don’t know if this helps. But there are tons of C# tutorials out there and most of them apply when it comes down to the basics of C#

Keep up the good work and keep spreading the word 

 

 

 

 

I don't think I overestimated a thing.

That information was excellent. I will pick it apart and get the very most out of it.

I have a Microsoft Beginning C# book that is a lot harder to understand than that, Maybe you missed your calling to be a teacher or a technical writer???

I have noticed in just about any language linear coding is possible (and one of the easiest methods). Problem is if the whole thing is in a huge "while" loop adding more code to expand the program slows it down.. (I think I must have gotten that from learning Basic, that method is a very popular way to start writing programs.) 

I was starting to use function coding in C on the Arduino. (It was pretty easy.) Then I popped into C# and the learning curve went through the roof! (OK, it isn't THAT bad!)

Everyone I talk to get to hear about my .NET Micro Framework based robot and the satisfaction of learning a "hard" language C# and the joy of having really cool programs run in some really neat hardware!!! I don't think one gets to be more of an evangelist than that!!!

Wishing you happy robotics and computing!

Thanks again,

Will

Will, you’re on the right track and you are talking about event driven programming.

In a desktop application you don’t have a big while loop that checks all the buttons and text boxes in your application. You add event handlers to the controls so that the application reacts to the buttons you push or the text you’re inputting.

The same thing can apply to your FEZ.

This is the Main() part of a project that I’m working on for the moment.

using System;
using System.Threading;
using Microsoft.SPOT;
using Microsoft.SPOT.Hardware;
using GHIElectronics.NETMF.FEZ;
using System.Text;
using System.IO;
using Microsoft.SPOT.IO;
using GHIElectronics.NETMF.USBClient;
using GHIElectronics.NETMF.Hardware;
using GHIElectronics.NETMF.IO;
using GHIElectronics.NETMF.System;

namespace SauID
{
    public class Program
    {
        static COM_LCD LCD = new COM_LCD("COM4", 9600);
        static COM_SD SD = new COM_SD(LCD);
        static COM_RFID RFID = new COM_RFID("COM1", 9600, LCD, SD);
       
        public static void Main()
        {
            Debug.EnableGCMessages(false);
            //RealTimeClock.SetTime(new DateTime(2012, 3, 11, 10, 26, 0, 0));
            Utility.SetLocalTime(RealTimeClock.GetTime());

            LCD.Biip();
            Welcome("Version 2.00");

            Thread.Sleep(Timeout.Infinite);

        }

        static void Welcome(string Version)
        {
            LCD.ClearScreen();
            LCD.BacklightOn();
            LCD.SetCursor(0, 0);
            LCD.Write("Sau-ID");
            LCD.SetCursor(1, 0);
            LCD.Write(Version);
        }

    }

}

As you can see I start of creating three objects; LCD, SD & RFID.

Then set the system date to the value from the battery backed up RTC (real time clock) and send a welcome message to the LCD.
Then this ‘thread’ goes to sleep with the Thread.Sleep(Timeout.Infinite); statement. You need to put the main thread to sleep or the application would just stop (just like an PC application exiting back to windows, but there is no OS to exit out to)
After that all the mechanics of the application is handled by the LCD, SD & RFID object and not by a main while loop.

This is one of the things that set the NETMF apart from other microcontrollers like Arduino, -is the  threading and event handling. So you can have an event handler doing all the work related to a serial in port, you can have a separate thread monitoring a ping sensor or the battery status and have them raise an event if certain thresholds are met.

You’re on the right track my friend.

 

 

Thank you again for the excellent code example! It sure looks like your project will work and be an awesome one.

I spent some time converting my straight-line code into something much more like a good C# program. It compiles without errors and even without any warnings. That is the good news. The bad news is it won't run on the robot!!! The ugly code (big while loop) runs great!

(Obviously I have a whole lot more to learn...)  It could be implementation or a little "logic error" that is keeping it from running.

If I put the working "loop" and the function based(?) version up here would you mind a quick glance to see if I am really messsing up bad some place??? (and I am pretty sure I am)  

(At least the code would be good for a laugh or two. :-)                                     I really am trying to learn something,

I can always have a look at your code but I can’t guarantee that I can figure it out.

But this is where the on chip debugger comes to your aid. Try setting breakpoints in your code by clicking in the light grey to the left of your code (you will get a red dot indicating a breakpoint). When the program (on your chip) comes to that line it will pause and allow you to examine the values of your variables. Then you can step line by line and follow what’s going on in your code.
I don’t know if your familiar with this debugger, but it’s one of the best!

Right now when I try to use the debugger the program crashes the debugger in their source files (like led.cs). I commented that out in my code and now it crashes in another of their source files, and on and on. (Yes the robot is on the bus and turned on,)

I know so little of how a C# program works I don't know what is causing what to crash. I will wait until I understand C# better before I try to debug that program because right now all I am doing is spinning my wheels. It does help me get more confused! :-)

I am very happy that MY program works so well and all my effort to make it work was definitely worth it. The robot runs great!

This doesn't reduce my love for any of this (it just lets me know I need to study more!)

What I hope to see (soon!) is someone elses good code for their FEZ Mini, to give me a better idea what I am shooting for.

By the way, what do you think of the Panda 2 and would it be a good board to buy and work with???

It sounds strange that the program crashes when you’re using the debugger, as your starting the debugger every time you upload the program to your FEZ.

So try this;

Make a new C# project and start with the ‘FEZ mini application’. Change the transport to USB and upload it to the FEZ as you always do (with the green arrow or F5)

Now you should have the FEZ blinking happily away on your board. And you are at this point already in debug mode.

Now in your program, click at the light grey border to the fare left on the line ledState = !ledState; And you will get a red circle with a yellow arrow inside. And if you look at the FEZ the LED has stopped blinking.

Now hit F11 and the program will step line by line and you can see what is going on (keep an eye on the LED).

If you click on the red debug mark, and hit F5 (continue) the program will run as normal.

FEZ Panda II is a great board and my favorite. I’m currently working on a custom shield for it for my current RFID project.
There is also a new board out, the FEZ Cerbuino Bee that has an onboard Xbee adapter that looks great http://www.ghielectronics.com/catalog/product/351 (not to fond of the Gadgeteer interface though and would rather have the 40pin Panda II header. )

I just noticed my working program debugs just fine! No debugger crash and you can set breakpoints and do all the other stuff. It is the broken program that crashes the debugger consistantly! 

Until I (slowly) learn more about C#, I am going to consider my program to be functional code.(It may not be "pure" C# code, but right now I don't know how to write better code.

I did find another guy on the web who made a tranformed a RC car to a FEZ Mini based robot and he was kind enough to put his code up. With 2 or 3 functions at the end of the program (I can do that!), most of his coding was simple and linear.

I strongly suspect that a lot of code for the FEZ Mini WILL be written in a fairly linear fashion. What I really like is the robot will function so well like that. That truly is "Fast and Easy" programming (I saw A LOT of Arduino scripts written in that fashion.)

Thanks again for all the great help and expect me to be back from time to time with more questions.

There is nothing wrong with linear code. Most C# NETMF code will probably have a main while (true) loop as a backbone and other functions and threads doing work in the background.

It’s better to write code that’s easy to read, than some fancy smancy code that is hard to follow.

There might still be room for improvement in your code as these two code block could probably be written as a single function?


                myGreen.TurnOn();
                myRed.ShutOff();

                for (y = 170; y > 110; y = (byte)(y - 10))
                {
                    anaSensorReading = anaIn.Read();

                    myServo.SetPosition(y);
                    Debug.Print("Angle: " + y.ToString());
                    Thread.Sleep(100);
                    value = avg(10);
                    mood(value, dist, caut, turn);
                    if ((value < turn) | (anaSensorReading < 50))
                    {
                        anaSensorReading = 100;

                        FEZMini_Robot.Move(0, 0);

                        FEZMini_Robot.MoveRamp(n1, n2, 10); // negative to reverse and ramp
                        Thread.Sleep(50); // how long to backup

                        turn_right(200);

                        stop();

                        beep();

                        FEZMini_Robot.MoveRamp(m1, m2, 10);

                        Thread.Sleep(10);
                    }
                }

Your doing great Will so just keep up the good work and post a question if you need help.
Geir

 

First, you do know that is a section of my BAD code that won't run on the robot! It is horrible code and I hope nobody attemps to see how to write a C# program because they will create a program that won't run!!! :-)

I cannot seem to make work the "value=avg(10)" function or the "mood(value, dist, caut, turn)" without major compile errors (I got them to compile in the bad program but I am pretty sure neither one actually works.}

I am having huge amounts of problems with the "scope" of variables. I find myself wishing for real "global" variables usable and recognized in any part of the program. I see C# doesn't like that and then the scope thing just kills me...

I am pretty sure I CAN'T combine those 2 code blocks (at least without the program getting trashed and unrunnable.

Thanks again for being there, and I bet you couldn't guess how hard it was going to be to help ME learn C#. (Big smilie here.)