Servo weird behaviour - Broadcom and Linux 2.4

Supporting 2.6 and up
User avatar
Patrick
Lead Developer
Posts: 3165
Joined: Mon Jun 20, 2005 8:46 am
Location: Canada
Contact:

Postby Patrick » Mon Jan 28, 2008 10:11 am

SGM,

Thanks for pointing out this bug in the RFID. The correct fix is to add

Code: Select all

phid->tagTimerThread.thread_status = PTRUE;

instead of the SLEEP. The problem was that I was setting this flag after starting the tread and the condition was failing before it got set. This will be fixed in the next release.

-Patrick

Mike_S

Postby Mike_S » Mon Jan 28, 2008 4:37 pm

Thanks for the suggestions Patrick.
I don't have libhid installed.
I'll try to link libphidgets with external libusb that is available via ipkg system on dd-wrt.
Actually I started adding lots of debugging messages to libusb (lines with "mdbg" prefix, the next number is PID).
For example, usb_control_msg now prints all requests.
One thing that crossed my mind was that maybe there is some problem with thread implementation in uclibc or how the libphidgets uses threads
Ideally I could modify my application to not to use threads (and libphidgets) and have very basic function to change servo position, without worrying about different callbacks etc.

This is a part of my debug log, with usb_control_msg returning -1
(broken pipe error)

Code: Select all

mdbg (2908): Successfully opened /proc/bus/usb/001/001, fd 5
mdbg (2908): Successfully opened /proc/bus/usb/001/002, fd 5
mdbg (2908): Successfully opened /proc/bus/usb/002/002, fd 5
mdbg (2908): control_msg: fd 5, ret 4, type 128, req 6300, val 0, idx 255, size 1000, timeout 0
mdbg (2908): control_msg: fd 5, ret 12, type 128, req 6303, val 1033, idx 255, size 1000, timeout 0
USB error: could not get bound driver: No data available
mdbg (2908): Claimed interface 0
mdbg (2908): control_msg: fd 5, ret 32, type 129, req 62200, val 0, idx 255, size 500, timeout 268470296
mdbg (2908): control_msg: fd 5, ret 4, type 128, req 6300, val 0, idx 255, size 1000, timeout 8704
error sending control message: Broken pipe
mdbg (2908): control_msg: fd 5, ret -1, type 128, req 6304, val 1033, idx 255, size 1000, timeout 8704


There is a note in libusb sources related to threads

Code: Select all

HACK: The use of urb.usercontext is a hack to get threaded applications
   * sort of working again. Threaded support is still not recommended, but
   * this should allow applications to work in the common cases.


so maybe it is worth to implement basic set_motor_position just to
confirm that the problem has nothing to do with the threads, uclibc etc.

Mike_S

Postby Mike_S » Tue Jan 29, 2008 6:42 pm

Patrick, can you please give me a hint what function directly
calls usb_control_msg to change the servo position?

Obviously
CSETINDEX(Servo,MotorPosition,double)
is calling FIRE(..)
which was set up ASGNFPTR, but I have some difficulties finding
actuall call to usb_control_msg. Somehow it ends up in CUSBSendPacket but I couldn't spot what's going on between FIRE and SendPacket.
Going through all these macros isn't very easy.

BTW, when I removed almost all calls to libphidget leaving only create, open and one call to setPosition it almost works. The servo goes to given position at full speed, about 70% of all runs of my test program.
The other 30% it does nothing. Maybe it's some kind of race.

I have found the reason why uhci driver is dumping debug messages and libusb returns error "broken pipe", when I call Phidget_open.
In cusblinux.c the function
int CUSBGetDeviceCapabilities is calling
usb_get_string_simple(udev, 4, (char *)phid->label, 11);
with index = 4 which return error and triggers usbi kernel driver debug messages.
If called with index=1 and index=2 it returns proper values:

Code: Select all

servousb.c(31) usb_get_cap:1 get_string returned 13, Phidgets Inc.
servousb.c(31) usb_get_cap:2 get_string returned 12, PhidgetServo

fitchett
Site Admin
Posts: 266
Joined: Fri Dec 05, 2003 3:45 pm
Location: Canada
Contact:

Postby fitchett » Tue Jan 29, 2008 9:06 pm

In our own dabbling at Phidgets, we have run into issues with uclibc related to pthreads. I can't remember the exact explanation, but we switched to libc to get a full blown threading library. The memory is foggy, but uclibc had some of the pthread functions implemented, resulting in the threading calls going to two separate thread implementations.

Chester

User avatar
Patrick
Lead Developer
Posts: 3165
Joined: Mon Jun 20, 2005 8:46 am
Location: Canada
Contact:

Postby Patrick » Wed Jan 30, 2008 11:23 am

CSETINDEX calls SENDPACKETINDEXED which is a macro that calls CMAKEPACKETINDEXED to build the packet buffer, and then queues it with CSENDPACKET_BUF, which signals the write thread.

The write thread (running WriteThreadFunction in cthread.c) picks up the signal and calls CPhidget_write (defined in cphidget.c) which takes the queued up packet and send it out to USB by calling CUSBSendPacket.

If you want to try and send out packets yourself, look at CMAKEPACKETINDEXED in cphidgetservo.c, to build the packet and CUSBSendPacket in cusblinux.c to send it.

Hope that helps.

-Patrick

Mike_S

Postby Mike_S » Wed Jan 30, 2008 1:42 pm

Patrick, many thanks for the information.
It was not quite easy to get through all those macros, but
with the 'gcc -E' I made it.

Finally I have the servo working properly, I can rotate it smoothly all 180 degrees without any problems.
Fortunately it is not the hardware problem nor kernel driver issue.
Definitely it's a thread problem, I'm not sure where it is exactly, maybe
I'll spend some time finding the main cause.

Probably there are not too many people playing with phidgets on dd-wrt or openwrt but to satisfy google here is the program that works
on dd-wrt v23 sp2, kernel 2.4.34-pre2, uclibc 0.9.28, tested
on asus wl500g premium.

It's using libusb 0.1.12 only.
It's assuming that the motor is connected to port 0.
Get libusb sources, and compile the program with following Makefile (all files except servo.c are from libusb):

Code: Select all

OBJECTS=servo.o descriptors.o error.o linux.o usb.o
CFLAGS=-g -Wall

all: $(OBJECTS)
        $(CC) -o servo $^ $(CFLAGS)

clean:
        rm -f $(OBJECTS)


servo.c

Code: Select all

#include <stdio.h>
#include <strings.h>
#include "usb.h"

#define USB_VENDOR      0x6C2
#define USB_PRODUCT     0x38
#define SERVO_MINPOS    -23
#define SERVO_MAXPOS    232

static int pdd_iid = 0;

static int setpos(struct usb_dev_handle *udev, double pos)
{
        char buf[8];
        int ret, pulse = (int)(pos * 10.6 + 243.8);

        bzero(buf, sizeof buf);

        buf[0] = pulse & 0xFF;
        buf[1] = pulse >> 8;
        ret = usb_control_msg(udev, USB_ENDPOINT_OUT |     USB_TYPE_CLASS | USB_RECIP_INTERFACE,
                        USB_REQ_SET_CONFIGURATION, 0x0200, pdd_iid,
                        (char *) buf, 6, 500);

        return ret;
}

struct usb_bus *bus;
struct usb_device *dev;
usb_dev_handle *udev;

int main(int argc, char **argv)
{
        double pos;

        if (argc < 2) {
                fprintf(stderr, "Need arg: new_pos (float)\n");
                exit(1);
        }
        pos = atol(argv[1]);
        if (pos < SERVO_MINPOS || pos > SERVO_MAXPOS) {
                fprintf(stderr, "Invalid range, servo min pos: %d, max pos: %d\n",
                        SERVO_MINPOS, SERVO_MAXPOS);
                exit(1);
        }
        usb_init();
        usb_find_busses();
        usb_find_devices();

        for (bus = usb_busses; bus; bus = bus->next) {
                for (dev = bus->devices; dev; dev = dev->next) {
                        if (dev->descriptor.idVendor != USB_VENDOR ||
                                dev->descriptor.idProduct != USB_PRODUCT)
                                        continue;
                        goto FOUND;
                }
        }

        fprintf(stderr, "Phidget device has not been found.\n");
        exit(1);
FOUND:
        udev = usb_open(dev);
        if (!udev) {
                fprintf(stderr, "Cannot open usb device.\n");
                exit(1);
        }
        setpos(udev, pos);
        return 0;
}


It's very simple, makes many assumptions, but it is working and
it's good starting point.
Put setpos() inside a loop with a usleep(20000) and the movement
will be slower and smoother.
Of course $(CC) should point to mipsel-linux-uclibc-gcc to cross compile etc. but this is a different story.
Actually this is a stripped version of servo.c, I've got simple functions to get capabilities, driver description etc. but I don't want to spam too much.

Thank you for your help and all suggestions.
I have to improve my small lib but I'm glad I can progress
with my main application.

jolouis

Postby jolouis » Fri May 16, 2008 5:13 pm

Mike_S, if you're still around I'd love to see any information you're willing to share about getting the phidgets libs onto OpenWRT/dd-wrt. I've been fiddling for the last two days with getting them to compile, and after basically re-writing half of the Makefiles I managed to get both the core library and the examples to compile under the OpenWRT Kamikaze SVN buildroot, but when I go to run the example it just segfaults on me...

Thanks!
-Rob

fitchett
Site Admin
Posts: 266
Joined: Fri Dec 05, 2003 3:45 pm
Location: Canada
Contact:

Postby fitchett » Fri May 16, 2008 6:03 pm

You may be having problems with OpenWRT if it uses uclibc. Uclibc has some issues with pthreads.

Chester

Mike_S

Postby Mike_S » Sat May 17, 2008 2:35 pm

Hi again,

Fortunately I'm receiving email notifications about new posts so you could say I'm still around :)
I have got all software working properly, here is the page with some photos, no interesting content yet, I'm just creating it, but I'm going to describe all my problems and solutions there, along with a software I wrote that is currently running to control web camera:

DYI tilt/pan cam

I have servo Phidget with 2 servos connected to it, some metal brackets and a web camera on top of it.
I'm not using Phidget library, I wrote a daemon server, linked with libusb directly, that receives messages from the applet embedded on a web page and controls servos movement. Using libusb is very simple and it was much simpler for me than debugging threading problems.
As you see on the photo, there are 4 arrow icons on the web page that you can control pan and tilt with.
It is working pretty well although I'm going to buy better web cam (probably Philips camera that better supports different light conditions) and I'm going to start using palantir server to achieve higher frame rate (currently the html frame that contains jpg refreshes every second).
I have got also simple program to control servos from the command line, this is pretty much the same program that I listed in my previous post.
jolouis, if you want to use servos connected to your Kamikaze box then I think it is much easier to use libusb directly. I think I would have spent much more time on debugging phidgets library/uclibc thread issues than writing my software to control servos.
Actually I had no problems with compiling libphidgets for mips using DD-WRT build root. If I remember correctly I just changed gcc to $(CC) in Makefiles and it worked fine. I'm using DD-WRT build root:
DD-WRT tool chain
jolouis, what do you want to use libphidgets for?
Is it for servo motors?

Cheers,
Mike

jeffrafter

Re: Servo weird behaviour - Broadcom and Linux 2.4

Postby jeffrafter » Wed Dec 30, 2009 8:19 am

I realize this thread is pretty old, but I am trying to get the phidget servo controller working on openwrt as well. I have tried the program that Mike_S included and just get:

Phidget device has not been found.

I am guessing I still have a difference in build/packages installed and was wondering if anyone has got this working (or if Mike is _still_ around :))

Thanks,
Jeff


Return to “Linux”

Who is online

Users browsing this forum: No registered users and 1 guest