Fez Panda Simple Controls

I’ve had my panda for over a week now and been doing alot of work in that time, but just cant seem to get my head around it as i’ve never really done any programming. Basically all i’m wanting to do is control it through a laptop. basically like press the up key, it makes a pin high, press the left arrow, it makes another pin high. sounds simple, but i don’t know where to start.

Admittedly i’m still working through the beginner’s guide and wouldn’t bother you guys, but at the moment i’m in a hurry. i was wondering if there was any easy to unedrstand sample code for something like this?

I’ve to have a prototype ready for monday. But after that i have some time to learn more and not bother u guys.

Also i was wondering what the output current is like from the digital outputs on the panda. I know usb is 500mA, and 103mA is needed to power the board, but when i made one of the outputs constantly on, it only showed 2.3mA. This seems very small…

Thanks, and sorry for seeming lazy, i’m not… just desperate :stuck_out_tongue:

up/down keys from PC do not mean much themselves They only forward a key press to the software in focus on windows.

An option is to use a terminal software like teraterm and then the key presses are translated into serial bytes. I am not sure if the arrow keys will work though but I am sure other keys will work.

…then those serial bytes can be transferred to FEZ over USB or serial port.

… on fez you can then read the data coming in process the data anyway you lie, like control a pin if I press “A” key.

=============
To do the above, you need to add a serial port (RS232) to FEZ. You can use the shield GHI offers to do that. After that, ti is about 10 lines of code to do all you asked for.

Ah yes well using the arrow keys isn’t essential. I knew i couldn’t just do it directly without another program on the PC of course. So does that mean i could do this through teraterm without having to write a seperate program on visual C# express?

Another question. When i go into loader mode (which from what i understand is the virtual com port mode, through holding LDR button when plugging usb in) and try to ping with teraterm, it doesn’t ping. COM1 shows normally and nothing else, then when i plug it in COM4 shows on the selection menu. so it is detecing, but it just isn’t pinging. Is this possibly due to the power issue when using virtual serial?

Edit: sorry just read that last part. So is there no way i can do this using the usb port and the CDC virtual com port driver? Thanks Gus

Using the same USB cable for debugging/deploying and also use it in your application is possible. This is one of the many GHI exclusive features. The feature is great but I do not recommend it for beginners as you may get lost between the multiple interfaces available on the USB cable.

You can read this for details microframeworkprojects.com

Yeh i’ve read through all of that actually. But i still didnt understand why it was such a problem for beginners. Surely you can just use usb debugging to write the program. Then just disconnect and connect as virtal com for communication, easy no? The only complication i could see would be if you wanted simultaneous debugging and serial commnicatin on the port/cable. but i dont need that…
I’m sorry, clueless

Ahh, but if you don’t have a serial port and debugging at the same time when how will you debug? If you can’t send test data via the comport then debugging is pointless… :slight_smile:

In the current problem: The USB port can give 500mA, but each output of the chip can only supply ±2mA. If you want to switch bigger currents then you will need either relays or other drivers. Personally I like ULN2003 as they are easy to use and quite robust. They also give 500mA max per output, of which it has 7…

Ah yeh the current thing was just curiosity. That does look like a nice a very suitable transistor array for my needs. I was testing with a BD438 transistor and couldn’t get the signal to switch on a simple LED circuit. i was probably just doing something stupid though i’ll be trying to get that working. I’ll look into that ULN2003.

Ok so i’m still not understanding the com thing completely, are you saying that i can’t use the virtual com port option on the panda send test data via the USB port and that I have no choice but to get the RS232 shield?

No, what i’m saying is that you must look in to the combined virtual comport/debug usb interface. I know it’s in there, but I have not played with it…

Then you can send data AND you can debug.

If you want to switch on single chars, ie you don’t have a packet structure, then this whole project should be 20 or 30 lines of code…

If I get some time tonight then i’ll look into it and post you some code…

This is a simple(and perhaps dirty) program to switch the led on a Panda. You can change as you like… :slight_smile:

“A” turns on the led.
“a” turns off the led.

After running the project though you will hear a USB disconnect, but the board will not reconnect for some reason. You must reset the board, then you will hear it reconnect as a normal board, then disconnect and reconnect as a debug/cdc board.

you will also need the drivers from http://www.ghielectronics.com/downloads/NETMF/Library%20Documentation/GHI_NETMF_Interface_with_CDC.zip


using System.Threading;
using Microsoft.SPOT;
using Microsoft.SPOT.Hardware;
using GHIElectronics.NETMF.USBClient;
using GHIElectronics.NETMF.Hardware;
using System;
namespace USBClient_Example
{
    public class Program
    {
        public static void Main()
        {
            // Check debug interface
            if (Configuration.DebugInterface.GetCurrent() != Configuration.DebugInterface.Port.USB1)
                throw new InvalidOperationException("Interface must be USB.");
            // Start CDC

            USBC_CDC cdc = USBClientController.StandardDevices.StartCDC_WithDebugging();
            byte[] Buffer=new byte[1];
            OutputPort Led=new OutputPort((Cpu.Pin)GHIElectronics.NETMF.FEZ.FEZ_Pin.Digital.LED,false);
            cdc.ReadTimeout = 1000;
            while (true)
            {
                cdc.Read(Buffer, 0, 1);
                switch ((char)Buffer[0])
                {
                    case 'a':
                        {
                            Led.Write(false);
                            Buffer[0] = 0;

                            byte[] bytes = System.Text.Encoding.UTF8.GetBytes("Led Off!\r\n");
                            cdc.Write(bytes, 0, bytes.Length);
                        }
                        break;
                    case 'A':
                        {
                            Led.Write(true);
                            Buffer[0] = 0;

                            byte[] bytes = System.Text.Encoding.UTF8.GetBytes("Led On!\r\n");
                            cdc.Write(bytes, 0, bytes.Length);
                        }
                        break;
                }
            }
        }
    }
}

You can also have a look at FezTerm - that does just what your asking.
[url]microframeworkprojects.com

Wow you really are a lifesaver Errol. I have it hooked up at the moment to a transistor, which switches a relay and turns an LED on, and it’s all working perfect. Thank you so much. It’s actually for an ROV, so i’ll let you know how i get on come monday. Thank you also William, going to look into that now.

I’ve got it all up and running switching motors with transistors. I do it through TeraTerm using Pinnacle Game Profiler and an xbox 360 controller to change the controller buttons into keyboard presses that teraterm will understand. However it occassionally crashes the panda and i have to take out the USB and restart it and whatnot, can anyone see why?
Here’s the code

using System.Threading;
using Microsoft.SPOT;
using Microsoft.SPOT.Hardware;
using GHIElectronics.NETMF.USBClient;
using GHIElectronics.NETMF.Hardware;
using System;
namespace USBClient_Example
{
    public class Program
    {
        public static void Main()
        {
            // Check debug interface
            if (Configuration.DebugInterface.GetCurrent() != Configuration.DebugInterface.Port.USB1)
                throw new InvalidOperationException("Interface must be USB.");
            // Start CDC

            USBC_CDC cdc = USBClientController.StandardDevices.StartCDC_WithDebugging();
            byte[] Buffer = new byte[1];
            OutputPort LeftThruster = new OutputPort((Cpu.Pin)GHIElectronics.NETMF.FEZ.FEZ_Pin.Digital.Di6, false);
            OutputPort LeftThrusterReverse = new OutputPort((Cpu.Pin)GHIElectronics.NETMF.FEZ.FEZ_Pin.Digital.Di1, false);
            OutputPort RightThruster = new OutputPort((Cpu.Pin)GHIElectronics.NETMF.FEZ.FEZ_Pin.Digital.Di8, false);
            OutputPort RightThrusterReverse = new OutputPort((Cpu.Pin)GHIElectronics.NETMF.FEZ.FEZ_Pin.Digital.Di11, false);
            OutputPort SideRightThruster = new OutputPort((Cpu.Pin)GHIElectronics.NETMF.FEZ.FEZ_Pin.Digital.Di9, false);
            OutputPort SideRightThrusterReverse = new OutputPort((Cpu.Pin)GHIElectronics.NETMF.FEZ.FEZ_Pin.Digital.Di12, false);
            OutputPort SideLeftThruster = new OutputPort((Cpu.Pin)GHIElectronics.NETMF.FEZ.FEZ_Pin.Digital.Di10, false);
            OutputPort SideLeftThrusterReverse = new OutputPort((Cpu.Pin)GHIElectronics.NETMF.FEZ.FEZ_Pin.Digital.Di13, false);
                            PWM servo = new PWM((PWM.Pin)GHIElectronics.NETMF.FEZ.FEZ_Pin.PWM.Di5);
            cdc.ReadTimeout = 1000;
            while (true)
            {
                cdc.Read(Buffer, 0, 1);
                switch ((char)Buffer[0])
                {

                    case 'Q':
                        {
                            LeftThruster.Write(true);
                            Buffer[0] = 0;
                            LeftThrusterReverse.Write(false);
                            Buffer[0] = 0;

                            byte[] bytes = System.Text.Encoding.UTF8.GetBytes("Left Thruster Forward\r\n");
                            cdc.Write(bytes, 0, bytes.Length);
                        }
                        break;
                    case 'W':
                        {
                            LeftThruster.Write(false);
                            Buffer[0] = 0;
                            LeftThrusterReverse.Write(false);
                            Buffer[0] = 0;

                            byte[] bytes = System.Text.Encoding.UTF8.GetBytes("Left Thruster off\r\n");
                            cdc.Write(bytes, 0, bytes.Length);
                        }
                        break;

                    case 'E':
                        {
                            LeftThruster.Write(true);
                            Buffer[0] = 0;
                            LeftThrusterReverse.Write(true);
                            Buffer[0] = 0;

                            byte[] bytes = System.Text.Encoding.UTF8.GetBytes("Left Thruster Reverse\r\n");
                            cdc.Write(bytes, 0, bytes.Length);
                        }
                        break;
                    case 'R':
                        {
                            RightThruster.Write(true);
                            Buffer[0] = 0;
                            RightThrusterReverse.Write(false);
                            Buffer[0] = 0;

                            byte[] bytes = System.Text.Encoding.UTF8.GetBytes("Right Thuster Forward\r\n");
                            cdc.Write(bytes, 0, bytes.Length);
                        }
                        break;
                    case 'T':
                        {
                            RightThruster.Write(false);
                            Buffer[0] = 0;
                            RightThrusterReverse.Write(false);
                            Buffer[0] = 0;

                            byte[] bytes = System.Text.Encoding.UTF8.GetBytes("Right Thuster Off\r\n");
                            cdc.Write(bytes, 0, bytes.Length);
                        }
                        break;
                    case 'Y':
                        {
                            RightThruster.Write(true);
                            Buffer[0] = 0;
                            RightThrusterReverse.Write(true);
                            Buffer[0] = 0;

                            byte[] bytes = System.Text.Encoding.UTF8.GetBytes("Right Thuster Reverse\r\n");
                            cdc.Write(bytes, 0, bytes.Length);
                        }
                        break;
                    case 'A':
                        {
                            SideLeftThruster.Write(true);
                            Buffer[0] = 0;
                            SideLeftThrusterReverse.Write(false);
                            Buffer[0] = 0;

                            byte[] bytes = System.Text.Encoding.UTF8.GetBytes("Side Left Thruster Forward/Down\r\n");
                            cdc.Write(bytes, 0, bytes.Length);
                        }
                        break;
                    case 'S':
                        {
                            SideLeftThruster.Write(false);
                            Buffer[0] = 0;
                            SideLeftThrusterReverse.Write(false);
                            Buffer[0] = 0;

                            byte[] bytes = System.Text.Encoding.UTF8.GetBytes("Side Left Thruster Off\r\n");
                            cdc.Write(bytes, 0, bytes.Length);
                        }
                        break;
                    case 'D':
                        {
                            SideLeftThruster.Write(true);
                            Buffer[0] = 0;
                            SideLeftThrusterReverse.Write(true);
                            Buffer[0] = 0;

                            byte[] bytes = System.Text.Encoding.UTF8.GetBytes("Side Left Thruster Reverse/up\r\n");
                            cdc.Write(bytes, 0, bytes.Length);
                        }
                        break;
                    case 'F':
                        {
                            SideRightThruster.Write(true);
                            Buffer[0] = 0;
                            SideRightThrusterReverse.Write(false);
                            Buffer[0] = 0;

                            byte[] bytes = System.Text.Encoding.UTF8.GetBytes("Side Right Thruster Forward/Down\r\n");
                            cdc.Write(bytes, 0, bytes.Length);
                        }
                        break;
                    case 'G':
                        {
                            SideRightThruster.Write(false);
                            Buffer[0] = 0;
                            SideRightThrusterReverse.Write(false);
                            Buffer[0] = 0;

                            byte[] bytes = System.Text.Encoding.UTF8.GetBytes("Side Right Thruster off\r\n");
                            cdc.Write(bytes, 0, bytes.Length);
                        }
                        break;
                    case 'H':
                        {
                            SideRightThruster.Write(true);
                            Buffer[0] = 0;
                            SideRightThrusterReverse.Write(true);
                            Buffer[0] = 0;

                            byte[] bytes = System.Text.Encoding.UTF8.GetBytes("Side Right Thruster Reverse/Up\r\n");
                            cdc.Write(bytes, 0, bytes.Length);
                        }
                        break;
                    case 'Z':
                        {
                            servo.SetPulse(20 * 1000 * 1000, 1000 * 1000);
                            Buffer[0] = 0;

                            byte[] bytes = System.Text.Encoding.UTF8.GetBytes("servo 1\r\n");
                            cdc.Write(bytes, 0, bytes.Length);
                        }
                        break;
                    case 'X':
                        {
                            servo.SetPulse(20 * 1000 * 1000, 1250 * 1000);
                            Buffer[0] = 0;

                            byte[] bytes = System.Text.Encoding.UTF8.GetBytes("servo 1.25\r\n");
                            cdc.Write(bytes, 0, bytes.Length);
                        }
                        break;
                    case 'C':
                        {
                            servo.SetPulse(20 * 1000 * 1000, 1500 * 1000);
                            Buffer[0] = 0;

                            byte[] bytes = System.Text.Encoding.UTF8.GetBytes("servo 1.5\r\n");
                            cdc.Write(bytes, 0, bytes.Length);
                        }
                        break;
                    case 'V':
                        {
                            servo.SetPulse(20 * 1000 * 1000, 1750 * 1000);
                            Buffer[0] = 0;

                            byte[] bytes = System.Text.Encoding.UTF8.GetBytes("servo 1.75\r\n");
                            cdc.Write(bytes, 0, bytes.Length);
                        }
                        break;
                    case 'B':
                        {
                            servo.SetPulse(20 * 1000 * 1000, 2000 * 1000);
                            Buffer[0] = 0;

                            byte[] bytes = System.Text.Encoding.UTF8.GetBytes("servo 2\r\n");
                            cdc.Write(bytes, 0, bytes.Length);
                        }
                        break;
                    case 'N':
                        {
                            servo.SetPulse(20 * 1000 * 1000, 2250 * 1000);
                            Buffer[0] = 0;

                            byte[] bytes = System.Text.Encoding.UTF8.GetBytes("servo 2.25\r\n");
                            cdc.Write(bytes, 0, bytes.Length);
                        }
                        break;
                }
            }
        }
    }
}

Is there anything wrong with this code or should is it just something i’ll have to live with? It seems to crash more often when pressing lots of different buttons at a time

Not related to your crash.

Why do you reset Buffer[0] in every case statement (sometimes even twice):


case 'Q':
{
    LeftThruster.Write(true);
    Buffer[0] = 0;
    LeftThrusterReverse.Write(false);
    Buffer[0] = 0;
 
    byte[] bytes = System.Text.Encoding.UTF8.GetBytes("Left Thruster Forward\r\n");
    cdc.Write(bytes, 0, bytes.Length);
}
break;

You only need to do it once before you do cdc.Read.

You should remove all the Buffer[0] = 0; I think they are useless.

What does the GC calls shows about your memory ? is the freeblocks value stable ? Is something increasing ?

[quote]This is a sample:
GC: 3msec 30504 bytes used, 33876 bytes available
Type 0F (STRING ): 876 bytes
Type 11 (CLASS ): 3900 bytes
Type 12 (VALUETYPE ): 756 bytes
Type 13 (SZARRAY ): 1968 bytes
Type 15 (FREEBLOCK ): 33876 bytes
Type 17 (ASSEMBLY ): 14808 bytes
Type 18 (WEAKCLASS ): 48 bytes
Type 19 (REFLECTION ): 48 bytes
Type 1B (DELEGATE_HEAD ): 576 bytes
Type 1D (OBJECT_TO_EVENT ): 288 bytes
Type 1E (BINARY_BLOB_HEAD ): 24 bytes
Type 1F (THREAD ): 1920 bytes
Type 20 (SUBTHREAD ): 240 bytes
Type 21 (STACK_FRAME ): 2892 bytes
Type 22 (TIMER_HEAD ): 144 bytes
Type 23 (LOCK_HEAD ): 60 bytes
Type 24 (LOCK_OWNER_HEAD ): 24 bytes
Type 27 (FINALIZER_HEAD ): 144 bytes
Type 31 (IO_PORT ): 144 bytes
Type 34 (APPDOMAIN_HEAD ): 72 bytes
Type 36 (APPDOMAIN_ASSEMBLY ): 1572 bytes[/quote]

You said you are disconnecting USB and restarting it.
How is your board powered ? Is it only using USB, or with external power too ? If using only USB, you should try powering it with external power too.

Ah ok sorry i dont know anything really about coding. All i’ve done is the stuff in the getting started guide. I’ll remove them. How do i check the GC calls?
It’s only powered by USB, no external power. how would i go about adding external power? it would have to come from a battery as it’d be onboard the ROV…

Thanks for your help

Forget about the battery for now, we just need to find from where the crash are coming ! One possibility is that the power from an usb port is not reliable : a micro-interruption in power could result in a crash in your application. So the best would be to use an external power like this one for an example : http://www.robotshop.com/ca/transformateur-mural-parallax-75vdc-1a-1.html
If you don’t have it, you can eventualy power using usb, but not directly the PC but a usb powered switch, which is more reliable.

How are you deploying the software to your board ? serial or usb ? you should see the gc calls result like in red in my previous message on your output screen. You can also use MFDEPLOY (look into the beginner guide). This debugging information will help find out what is happening; could be a memory leak, or an exeption you are not catching, you will see it then.

Good luck :slight_smile: !

Ok it doesnt crash at all without the motors connected (they are in uni). But without the “Buffer[0] = 0;” in the cases, it repeats the last command over and over every second until a new one is pressed, is that a problem?
Could it be that possibly too much current or voltaga is flowing into the ground? the panda outputs go directly into the base of transistors which switch motors that can draw over 3A, with the collector going back to the ground in the panda. I’ll check the CG calls tommorow with everything wired up.

External power like that is not an option, the panda is inside an ROV which is underwaterm the only wire coming from it is a usb extender cable.

just put one Buffer[0] = 0; just before the cdc.Read line should be ok.
The transistors should not draw too much current.
However, are you sure that when the 3A motors are pulling all the current, you do not have a loss of power out of the usb ?

You will probably see your problem by looking at the debug info…

:slight_smile: