LinuxQuestions.org

LinuxQuestions.org (/questions/)
-   Programming (https://www.linuxquestions.org/questions/programming-9/)
-   -   c# code for Maplin USB Robot arm. :) (https://www.linuxquestions.org/questions/programming-9/c-code-for-maplin-usb-robot-arm-851033/)

RichardUK 12-18-2010 05:27 AM

c# code for Maplin USB Robot arm. :)
 
Uses the LibUsbDotNet lib with a bug fix. I'm going to create a WinForms app and then create a web page for it all. Just wanted to post this so others can play with it over xmas. ;) Go get your robot arms, only 30 and fun!

Robot Arm

If you're using prebuilt bin you'll need to use the LibMonoUsb code, if you have the LibUsbDotNet source and want to use that then you'll need to fix the MonoUsbControlSetup.SetData function with the following code.

Code:

//Fixed function.
        public void SetData(IntPtr data, int offset, int length)
        {                       
            Byte[] temp = new byte[length];
              Marshal.Copy(data,temp,0,length);
            Marshal.Copy(temp, 0, PtrData, length);
        }

//Just one chunk of code, you'll have to make an app out of it.
The robot arm takes three bytes. first two bytes is for the motors. The last one, set to 1 for light on.
Set all to zero for all off.

First byte
Gripper close == 0x01
Gripper open == 0x02
Wrist Up == 0x04
Wrist Down == 0x08
Elbow up == 0x10
Elbow down == 0x20
Shoulder up == 0x40
Shoulder down == 0x80

Second byte
Base rotate right == 0x01
Base rotate left == 0x02

Third byte
Light on == 0x01

:)
Code:

using System;
using System.Runtime.InteropServices;
using System.Threading;

using LibUsbDotNet;
using LibUsbDotNet.Main;
using MonoLibUsb;

namespace RobotArmtest1
{
        class MainClass
        {
        public static void Main(string[] args)
        {
                        MoveWith_LibUsbDotNet();
//                        MoveWith_LibMonoUsb();
                }
               
                private static void MoveWith_LibUsbDotNet()
                {
            ErrorCode ec = ErrorCode.None;
                        UsbDevice robotArm = null;
            try
            {
                // Find and open the usb device.
                robotArm = UsbDevice.OpenUsbDevice(new UsbDeviceFinder(0x1267, 0x0000));
                               
                // If the device is open and ready7
                if (robotArm == null)
                                {
                                        Console.WriteLine("Device Not Found.");
                                        return;
                                }
                               

                // If this is a "whole" usb device (libusb-win32, linux libusb)
                // it will have an IUsbDevice interface. If not (WinUSB) the
                // variable will be null indicating this is an interface of a
                // device.
                IUsbDevice wholeUsbDevice = robotArm as IUsbDevice;
                if (!ReferenceEquals(wholeUsbDevice, null))
                {
                                        Console.WriteLine("SetConfiguration && ClaimInterface");
                    // This is a "whole" USB device. Before it can be used,
                    // the desired configuration and interface must be selected.

                    // Select config #1
                    wholeUsbDevice.SetConfiguration(1);

                    // Claim interface #0.
                    wholeUsbDevice.ClaimInterface(0);
                }
                               
                               
                                UsbSetupPacket usbPacket;
                                int transferred;
                                byte[] data;
                               
                                data = new byte[]{4,0,0};
                                IntPtr dat = Marshal.AllocHGlobal(3);
                                Marshal.Copy(data,0,dat,3);

                                usbPacket = new UsbSetupPacket((byte)UsbRequestType.TypeVendor,6,0x0100,0,0);
                                robotArm.ControlTransfer(ref usbPacket,dat,data.Length,out transferred);
                                Thread.Sleep(1000);

                                data[0] = 0;
                                Marshal.Copy(data,0,dat,3);
                                robotArm.ControlTransfer(ref usbPacket,dat,data.Length,out transferred);
                               
            }
            catch (Exception ex)
            {
                Console.WriteLine();
                Console.WriteLine((ec != ErrorCode.None ? ec + ":" : String.Empty) + ex.Message);
            }
            finally
            {
                if (robotArm != null)
                {
                    if (robotArm.IsOpen)
                    {
                        // If this is a "whole" usb device (libusb-win32, linux libusb-1.0)
                        // it exposes an IUsbDevice interface. If not (WinUSB) the
                        // 'wholeUsbDevice' variable will be null indicating this is
                        // an interface of a device; it does not require or support
                        // configuration and interface selection.
                        IUsbDevice wholeUsbDevice = robotArm as IUsbDevice;
                        if (!ReferenceEquals(wholeUsbDevice, null))
                        {
                            // Release interface #0.
                            wholeUsbDevice.ReleaseInterface(0);
                        }

                        robotArm.Close();
                    }
                    robotArm = null;

                    // Free usb resources
                    UsbDevice.Exit();

                }
            }
        }
               
                private static void MoveWith_LibMonoUsb()
                {
                        MonoUsbSessionHandle sessionHandle = null;
                        MonoUsbDeviceHa any no zerondle device_handle = null;
                        IntPtr dat = IntPtr.Zero;
                        int r;
                        try
                        {
                    sessionHandle=new MonoUsbSessionHandle();
                    if (sessionHandle.IsInvalid) throw new Exception("Invalid session handle.");
       
                    Console.WriteLine("Opening Device..");
                    device_handle = MonoUsbApi.OpenDeviceWithVidPid(sessionHandle, 0x1267, 0x0000);
                    if ((device_handle == null) || device_handle.IsInvalid) return;
       
                    // If TEST_REST_DEVICE = True, reset the device and re-open
                    if (true)
                    {
                        MonoUsbApi.ResetDevice(device_handle);
                        device_handle.Close();
                        device_handle = MonoUsbApi.OpenDeviceWithVidPid(sessionHandle, 0x1267, 0x0000);
                        if ((device_handle == null) || device_handle.IsInvalid) return;
                    }
       
                    // Set configuration
                    Console.WriteLine("Set Config..");
                    r = MonoUsbApi.SetConfiguration(device_handle, 1);
                    if (r != 0) return;
       
                    // Claim interface
                    Console.WriteLine("Set Interface..");
                    r = MonoUsbApi.ClaimInterface(device_handle, 0);
                    if (r != 0) return;
                       
                    /////////////////////
                    // Write test data //
                    /////////////////////
                    int packetCount = 0;
                    int transferredTotal = 0;
                               
                                byte []testWriteData = new byte[]{0x80,0,0};
                               
                                dat = Marshal.AllocHGlobal(3);
                               
                                Marshal.Copy(testWriteData,0,dat,3);
                    r = MonoLibUsb.MonoUsbApi.ControlTransfer(device_handle,0x40,6,0x0100,0,dat,3,2000);

                                Thread.Sleep(1000);
       
                                testWriteData[0] = 0;//Stop the motors.
                                Marshal.Copy(testWriteData,0,dat,3);
                    r = MonoLibUsb.MonoUsbApi.ControlTransfer(device_handle,0x40,6,0x0100,0,dat,3,2000);
                               
                    if (r == (int) MonoUsbError.ErrorTimeout)
                    {
                        // This is considered normal operation
                        Console.WriteLine("Write Timed Out. {0} packet(s) written ({1} bytes)", packetCount, transferredTotal);
                    }
                    else if (r != (int) MonoUsbError.ErrorTimeout && r != 0)
                    {
                        // An error, other than ErrorTimeout was received.
                        Console.WriteLine("Write failed:{0}", (MonoUsbError) r);
                    }
                }
                finally
                {
                                if( dat != IntPtr.Zero)
                                {
                                        Marshal.FreeHGlobal(dat);
                                }
                               
                    // Free and close resources
                    if (device_handle != null)
                    {
                        if (!device_handle.IsInvalid)
                        {
                            MonoUsbApi.ReleaseInterface(device_handle, 0);
                            device_handle.Close();
                        }
                    }
                    if (sessionHandle!=null)
                    {
                        sessionHandle.Close();
                        sessionHandle = null;
                    }
                }
                }
    }
}


devnull10 12-19-2010 05:05 AM

Certainly looks very interesting however with most people on here being Linux users, I doubt many will program (or at least choose program) in c#.

RichardUK 12-20-2010 09:22 AM

I've now created a binary and a project page on google code.

http://code.google.com/p/maplin-robot-arm-for-linux/

You'll need mono runtime. I'm using version 2.6.7

RichardUK 12-20-2010 09:32 AM

Quote:

Originally Posted by devnull10 (Post 4196589)
Certainly looks very interesting however with most people on here being Linux users, I doubt many will program (or at least choose program) in c#.

Yes agreed. I'm a hardcore coder, been so for many years in the games industry as well as military stuff. I've always thought there was only a need for two languages. Raw asm for real hardcore stuff and c/c++ for everything else. But in my current job (industrial and medical automation) most of the other coders use c#, .net and asp.net And they have a good reason to do so. They need robustness not speed but quick application turnaround.

c# offers easy internet integration as well as better bug resistance.

Anyway having in the past few years been coming a Linux advocate I looked into Mono as a way for the current applications they have to run on Linux. And as it turns out c# is outstanding in allowing cross platform integration. I've spent years maintaining code that works on many platforms, not just Linux and Windows. c# just makes that work go away.

Really, if you've not, go check it out. It wont fulfill the hardcore coders needs but it will allow you to create one binary that will run on all systems.

bigearsbilly 12-22-2010 05:01 PM

off topic...

does mono work ok?

I'm a staunch freeBSD perl c/c++ vi/make man - but unfortunately in my job
i need to learn c# asp.NET.
(that or quit and go scrabbling about for occasional perl contracts again).

sad but rent needs to be paid.

kernel_geek 12-28-2010 02:47 PM

Quote:

Originally Posted by RichardUK (Post 4197768)
I've now created a binary and a project page on google code.

http://code.google.com/p/maplin-robot-arm-for-linux/

You'll need mono runtime. I'm using version 2.6.7


Hi Richard, I've no luck using the code. :(

dmesg recognises a usb device, but doesn't try to load any drivers or anything:

Code:

[ 3822.512183] usb 5-1: new low speed USB device using uhci_hcd and address 2
[ 3822.665725] usb 5-1: configuration #1 chosen from 1 choice

The application loads, but the buttons do nothing and the title says "Robot arm not connected"

Where am I going wrong?

I'm using ubuntu lucid, kernel 2.6.32-25, mono version 2.4.4.

Cheers!

EDIT (might have been an idea to include some errors haha):

Here's the output of the program when I load it and press every button. Maybe I'm missing a mono library?

Code:

Stacktrace:

  at (wrapper managed-to-native) Gtk.Application.gtk_main () <0x00004>
  at (wrapper managed-to-native) Gtk.Application.gtk_main () <0xffffffff>
  at Gtk.Application.Run () <0x0000a>
  at MaplinRobotArm.MainClass.Main (string[]) <0x0003f>
  at (wrapper runtime-invoke) MaplinRobotArm.MainClass.runtime_invoke_void_object (object,intptr,intptr,intptr) <0xffffffff>

Native stacktrace:

        mono() [0x80ca6e4]
        mono() [0x80f6893]
        [0xa21410]
        /lib/libglib-2.0.so.0(g_main_loop_run+0x1ba) [0x14f84a]
        /usr/lib/libgtk-x11-2.0.so.0(gtk_main+0xb9) [0x3b2b3c9]
        [0x9cb500]
        [0x9cb4c3]
        [0x9b82c8]
        [0x9b8204]
        mono(mono_runtime_exec_main+0xde) [0x8113b1e]
        mono(mono_runtime_run_main+0x15a) [0x811429a]
        mono(mono_main+0x18c4) [0x80b3524]
        mono() [0x805ad25]
        /lib/tls/i686/cmov/libc.so.6(__libc_start_main+0xe6) [0x215bd6]
        mono() [0x805ac61]

Debug info from gdb:

[Thread debugging using libthread_db enabled]
[New Thread 0x8a9b70 (LWP 5492)]
[New Thread 0x1eeb70 (LWP 5491)]
0x00a21422 in __kernel_vsyscall ()
  3 Thread 0x1eeb70 (LWP 5491)  0x00a21422 in __kernel_vsyscall ()
  2 Thread 0x8a9b70 (LWP 5492)  0x00a21422 in __kernel_vsyscall ()
* 1 Thread 0x6e76f0 (LWP 5490)  0x00a21422 in __kernel_vsyscall ()

Thread 3 (Thread 0x1eeb70 (LWP 5491)):
#0  0x00a21422 in __kernel_vsyscall ()
#1  0x00a13736 in nanosleep () from /lib/tls/i686/cmov/libpthread.so.0
#2  0x081a6af8 in ?? ()
#3  0x00a0b96e in start_thread () from /lib/tls/i686/cmov/libpthread.so.0
#4  0x002cca4e in clone () from /lib/tls/i686/cmov/libc.so.6

Thread 2 (Thread 0x8a9b70 (LWP 5492)):
#0  0x00a21422 in __kernel_vsyscall ()
#1  0x00a12245 in sem_wait@@GLIBC_2.1 ()
  from /lib/tls/i686/cmov/libpthread.so.0
#2  0x0812e199 in ?? ()
#3  0x081527ea in ?? ()
#4  0x081c3062 in ?? ()
#5  0x081e1925 in ?? ()
#6  0x00a0b96e in start_thread () from /lib/tls/i686/cmov/libpthread.so.0
#7  0x002cca4e in clone () from /lib/tls/i686/cmov/libc.so.6

Thread 1 (Thread 0x6e76f0 (LWP 5490)):
#0  0x00a21422 in __kernel_vsyscall ()
#1  0x00a12f5b in read () from /lib/tls/i686/cmov/libpthread.so.0
#2  0x080ca87e in ?? ()
#3  0x080f6893 in ?? ()
#4  <signal handler called>
#5  0x00a0f311 in __pthread_mutex_unlock_usercnt ()
  from /lib/tls/i686/cmov/libpthread.so.0
#6  0x0014f84a in g_main_loop_run () from /lib/libglib-2.0.so.0
#7  0x03b2b3c9 in gtk_main () from /usr/lib/libgtk-x11-2.0.so.0
#8  0x009cb500 in ?? ()
#9  0x009cb4c3 in ?? ()
#10 0x009b82c8 in ?? ()
#11 0x009b8204 in ?? ()
#12 0x08113b1e in mono_runtime_exec_main ()
#13 0x0811429a in mono_runtime_run_main ()
#14 0x080b3524 in mono_main ()
#15 0x0805ad25 in ?? ()
#16 0x00215bd6 in __libc_start_main () from /lib/tls/i686/cmov/libc.so.6
#17 0x0805ac61 in ?? ()

=================================================================
Got a SIGSEGV while executing native code. This usually indicates
a fatal error in the mono runtime or one of the native libraries
used by your application.
=================================================================

Aborted


kernel_geek 01-09-2011 01:31 PM

Sorted!
 
just found this, solved all my problems! Now programming my robot arm in C!

http://notbrainsurgery.livejournal.com/38622.html

RichardUK 01-10-2011 03:07 AM

Quote:

Originally Posted by bigearsbilly (Post 4200541)
off topic...

does mono work ok?

I'm a staunch freeBSD perl c/c++ vi/make man - but unfortunately in my job
i need to learn c# asp.NET.
(that or quit and go scrabbling about for occasional perl contracts again).

sad but rent needs to be paid.

The Mono editor is ok, but I do all development in vs2010 and just run the code on the linux box. The mono runtime is very good, is missing a few little bits like WPF. You winforms seem to work fine.

I was where you are now 8 months ago. Now unless i'm hacking, i'll use c#. Just so much more productive.

RichardUK 01-10-2011 03:12 AM

Quote:

Originally Posted by kernel_geek (Post 4218572)
just found this, solved all my problems! Now programming my robot arm in C!

http://notbrainsurgery.livejournal.com/38622.html

Sorry, missed you post. Didn't get a mail from the site saying that someone posted to my thread, a bit odd.

Good to here you got it running in C. The main reason I did mine in C# was to see how easy it was to do C# code and power USB devices.

There are two possible issues that may have cause your problems. Did you have libusb-1.0 installed? Also the libusbdotnet c# lib is buggy, it's using unmanaged memory incorrectly causing it to misbehave on 64bit systems.

poly 01-15-2011 05:53 PM

Hi guys, your details have been very useful to me. I've got this working in Python using your command structure etc. This is part of my "teach myself Python properly" plan as its something I wanted / need to do, rather than just dabbling in yet another language. I'm planning that it will evolve from a very basic program to a simple module, and then I'll add some other features too! I'm also hoping to use this as a test for the deployment tools and possible wxpython to wrap a pretty user interface around it. So I've registered a little blog python-poly at blogspot (I can't include a link as its my first post) to track the progress! I'll start by adding the basic module tomorrow night (if anyone is desperate for it you can email me and I'll send you the "ugly" version).

poly 01-16-2011 03:33 AM

OK I've added some very rudimentary python code (http://python-poly.blogspot.com/2011...lest-code.html). It only needs about eleven lines of code - so this might be quite attractive to anyone new to programming or new to USB!

Here's the simplest prog I've done, but do pop over to the blog for more detailed versions or "documentation" and explanation of what I'm trying to do etc!

Code:

# Minimalist version of USB arm control to show how simple it could be! (c) N Polwart,  2011

import usb.core, time

dev = usb.core.find(idVendor=0x1267, idProduct=0x0000)
if dev is None:
    raise ValueError('Device not found')          # if device not found report an error

dev.set_configuration()

datapack=0x40,0,0      # change this to vary the movement
bytesout=dev.ctrl_transfer(0x40, 6, 0x100, 0, datapack, 1000)

time.sleep(1)    # waits for 1 second whilst motors move.

datapack=0,0,0
bytesout=dev.ctrl_transfer(0x40, 6, 0x100, 0, datapack, 1000)


NickPoole 01-02-2012 07:40 AM

Robot arm control ported to Ruby
 
I realise this thread has gone quite a while back, but for the sake of sharing examples here is another port of the USB control code (this time in Ruby).
Please note that this is still a work in progress; however, it does work and should act as a good starting point for working with Ruby and USB.

Code:

require 'rubygems'
require 'libusb'
usb = LIBUSB::Context.new

# Generic constant
off = 0x00

# First byte
gClose = 0x01
gOpen = 0x02
wUp = 0x04
wDown = 0x08
eUp = 0x10
eDown = 0x20
sUp = 0x40
sDown = 0x80


# Second byte
brRight = 0x01
brLeft = 0x02


# Third byte
lOn = 0x01

# Get the device object
arm = nil
arm = usb.devices(:idVendor => 0x1267, :idProduct => 0x0000).first
if arm == nil
        puts "Arm not found!"
        exit
end

# Take control of the device
handle = arm.open
handle.claim_interface(0)

# Send the signal to start rotating the base right (clockwise)
datapack=[off,brRight,off]
handle.control_transfer(:bmRequestType => 0x40, :bRequest => 6, :wValue => 0x100, :wIndex => 0, :dataOut => datapack.pack('CCC'), :timeout => 1000)

# Wait for a secnd while the arm moves
sleep(1)

# Send the stop signal
datapack=[off,off,off]
handle.control_transfer(:bmRequestType => 0x40, :bRequest => 6, :wValue => 0x100, :wIndex => 0, :dataOut => datapack.pack('CCC'), :timeout => 1000)

# Release the device
handle.release_interface(0)


Gorea235 07-07-2013 03:09 PM

Arm not supported?
 
Quote:

Originally Posted by NickPoole (Post 4563723)
I realise this thread has gone quite a while back, but for the sake of sharing examples here is another port of the USB control code (this time in Ruby).
Please note that this is still a work in progress; however, it does work and should act as a good starting point for working with Ruby and USB.

Code:

require 'rubygems'
require 'libusb'
usb = LIBUSB::Context.new

# Generic constant
off = 0x00

# First byte
gClose = 0x01
gOpen = 0x02
wUp = 0x04
wDown = 0x08
eUp = 0x10
eDown = 0x20
sUp = 0x40
sDown = 0x80


# Second byte
brRight = 0x01
brLeft = 0x02


# Third byte
lOn = 0x01

# Get the device object
arm = nil
arm = usb.devices(:idVendor => 0x1267, :idProduct => 0x0000).first
if arm == nil
        puts "Arm not found!"
        exit
end

# Take control of the device
handle = arm.open
handle.claim_interface(0)

# Send the signal to start rotating the base right (clockwise)
datapack=[off,brRight,off]
handle.control_transfer(:bmRequestType => 0x40, :bRequest => 6, :wValue => 0x100, :wIndex => 0, :dataOut => datapack.pack('CCC'), :timeout => 1000)

# Wait for a secnd while the arm moves
sleep(1)

# Send the stop signal
datapack=[off,off,off]
handle.control_transfer(:bmRequestType => 0x40, :bRequest => 6, :wValue => 0x100, :wIndex => 0, :dataOut => datapack.pack('CCC'), :timeout => 1000)

# Release the device
handle.release_interface(0)


I have tried this code and it throws this error:

C:/Ruby200/lib/ruby/gems/2.0.0/gems/libusb-0.3.4-x86-mingw32/lib/libusb/constants.rb:56:in `raise_error': LIBUSB::ERROR_NOT_SUPPORTED in libusb_open (LIBUSB::ERROR_NOT_SUPPORTED)
from C:/Ruby200/lib/ruby/gems/2.0.0/gems/libusb-0.3.4-x86-mingw32/lib/libusb/device.rb:58:in `open'
from D:/MyName/Google Drive/Programs/Ruby/RobotArmCode.rb:36:in `<main>'

I have tried the arm with the program that comes with it and it works, and I have installed the 'ffi' and 'libusb' gems. I have tried using a Windows 7 64 bit OS and a Windows XP 32 OS, but neither have worked. Any idea why?

NickPoole 07-08-2013 01:12 AM

Quote:

Originally Posted by Gorea235 (Post 4985810)
I have tried this code and it throws this error:

C:/Ruby200/lib/ruby/gems/2.0.0/gems/libusb-0.3.4-x86-mingw32/lib/libusb/constants.rb:56:in `raise_error': LIBUSB::ERROR_NOT_SUPPORTED in libusb_open (LIBUSB::ERROR_NOT_SUPPORTED)
from C:/Ruby200/lib/ruby/gems/2.0.0/gems/libusb-0.3.4-x86-mingw32/lib/libusb/device.rb:58:in `open'
from D:/MyName/Google Drive/Programs/Ruby/RobotArmCode.rb:36:in `<main>'

I have tried the arm with the program that comes with it and it works, and I have installed the 'ffi' and 'libusb' gems. I have tried using a Windows 7 64 bit OS and a Windows XP 32 OS, but neither have worked. Any idea why?

I think this means that you've not created a driver that will let libusb control the device. Take a look at this thread over on the ruby forums:
https://www.ruby-forum.com/topic/3961426

The code I posted was tested on Ruby 1.8.7 and should probably have worked with 1.9 too, but I have no idea what sort of changes Ruby 2 requires; it's still really new and I don't know anyone who's adopted it yet.


All times are GMT -5. The time now is 02:15 PM.