Added a Wiki, please help to add pages to the wiki! -

Author Topic: controlling stepper motors - solved  (Read 25840 times)

May 22, 2013, 04:43:08 pm
Hi All,

There was a discussion some time ago on how to control stepper motors in the context of custom kernel setup.

Should anyone be still interested the description is available here:

Soon, I'm planning to add a few more tricks (SD/MMC card access through soft-SPI, camera, wifi etc)


« Last Edit: May 30, 2013, 08:57:09 am by admin »

May 23, 2013, 03:26:21 am
That's brilliant, thanks for the heads up!

  • **
May 24, 2013, 01:16:37 am
If you're interested, I have mostly ported the NUC700 support from kernel 2.6 to the latest git one, which successfully boots (although I am having issues finding a toolchain that can generate FLAT binaries for userspace.)

I have a little more left to port, and some things to implement from scratch (mtdblock partition support) but let me know if you'd be interested in being able to run the latest kernel and I will try to post the code somewhere.

May 24, 2013, 03:37:27 am

After dissasembling one of these camera's I've managed to build some sort of ROV, I would love to have control over gpio so I can use a dc motor for propulsion.

May 26, 2013, 04:00:44 am
i was one of the people on the uclinux forum trying to figure this out.
great job, you managed to get it to work.
I compiled and tested your code and it seems to be working ok.
however, now the next challenge is figuring out how to get 'half-step' mode to work.
Im currently trying to get it to work, but Im having some problems figuring it out.
using your code as a base, i tried to run the motor as fast as possible (by doing usleep(0); ), but its definitely much slower than the speeds the motors produce using the stock firmware/web utility. the web interface controls for pan/tilt move very quickly and smoothly, so Im assuming that its running in half-step mode.
I can provide code if youre interested in seeing what Im trying to accomplish.
The issue that confuses me the most is the fact that its supposedly in 'addressable latch' mode, yet the LE latch transition pin is grounded (as you also stated in your blog). So im not clear on how to setup the correct stepping algorithm for half-step mode.

May 26, 2013, 11:48:06 am

Yes, it's rather slow, but should be acceptable for most applications. I suspect there's not too much we could do to make it faster. The reason being that the "delay()" functions in userspace are not accurate and to make it worse the minimum delay seems to be limited by the system pre-defined "USER_HZ" (haven't verified that yet - just guessing, you may want to play with linux-2.6.x/arch/arm/include/asm/param.h values). Long-term proper solution would be to create a simple kernel driver to handle the stepping routines. Just for testing, instead of udelay/delay, try using a "dirty" calibrated do_nothing_loop - it'll eat the whole CPU time but at least could confirm if the delay functions are to be blamed.

I'm busy now preparing a custom kernel/rootfs with all the basic features required so that it could be used as a kind of "minimalistic-embedded-operating-system", so far it has: writable filesystem (jffs), login system, telnetd, ftpd, camera sensor access, basic http server, soft sd/mmc etc. Going to share the image files soon.

May 27, 2013, 01:30:56 am
I think you may be on to something.
I tried using your recommended 'do nothing' loop and things did seem to speed up.
I had to play with the number of loop iterations in order to get close to something that would work.
In my case, a number of around 8000 loop iterations seemed to work.
Also, I found that I had to use the stepper in 'two phase,full step' mode
(2 consecutive motor pins go HIGH on each step instead of just one).
I needed to do this to increase the torque in order for the motor to spin more smoothly at higher speed.In half-step mode, the pulses seemed to be too fast & weak to spin the motor, and single-phase full-step mode wasn't much better either. The motor now seems to run faster, but it still seems like the stock ptz driver runs smoother, faster, and is less 'glitchy'.

I can share the source for my prototype stepper app if you'd like to check it out, just let me know.

Im not an expert in the low-level linux kernel hacking & device driver stuff, but I'm willing to learn and put in the work to get a driver built if you'd be willing to collaborate on this. Ive been really frustrated by the lack of interest and help on the GPIO/stepper motor stuff here on the openipcam forums; it seems like not many people have taken it too seriously.

So do you believe that the timing/speed issues can be more easily solved within a driver?
Also, one of my main questions on the stepper control setup was 'how would we go about setting up a driver/control app that can power both motors at the same time?' do you have any ideas on how this could be accomplished?

FYI, I see that you're interested in building a full-blown custom kernel for the foscam platform?
My idea was to do the same; in fact, I'm running my own custom 3.1 uclinux kernel.
my plan was to create a completely custom package (separate from the openipcam stuff which seems to try to stay close to or depend on the original firmware). Anyway, I mention it in case you'd like to compare notes on anything relating to setting up your own custom ipcam kernel.
« Last Edit: May 27, 2013, 01:32:49 am by changosurf »

May 27, 2013, 05:29:57 pm

In kernelspace driver code one can use much more precise timers, a delay should always be quite close to the desired value, while in userspace it can be virtually random - depending on other processes running in the system. Also the driver code section responsible for handling the stepping bit-bangling routines is less likely to be preempted. We'll see, I'm going to create a simple driver (when I have some time :) )

Just for my curiosity, why do you need the additional torque / more speed ? Are you planning to create a kind of robotic/moving device ?

BTW: the early test version of my kernel/rootfs package is ready, at the moment it can handle:

- Based on Linux version
- rt2800usb wifi network support (Ralink idVendor=148f, idProduct=3070)
- PixArt cmos usb camera (idVendor=1d0f, idProduct=1801)
- jffs2 writable root filesystem (2MB)
- jffs2 writeble user/data filesystem (~500KB)
- experimental software spi bus + sd/mmc, slow but enough to save camera snapshots, stream mp3 files etc.
- v4l camera interface
- mathopd http server (with cgi support)
- simple login subsystem (users account / passwords)
- inetd
- telnetd
- ftpd
- userspace binary to controll horizontal/vertical stepper motors

It can be downloaded from:

May 27, 2013, 06:13:56 pm
ok, thanks for the info on the kernel-space stuff.
I'd like to try setting up a test driver too.

The additional torque is in order to get the camera to spin at the faster speed using the user-space binary that I built using your demo code. perhaps it wont be necessary to use the dual-phase, full-step mode in kernel space? we'll see once there's a test driver available.

Currently, I don't actually *need* the higher speed, but I do prefer the camera to move quickly from one position to the next. I'm not building a robot, but I guess that it would be useful for someone that did want to use the camera for that purpose. The factory firmware is able to move the camera at high speed, so I believe that any custom firmware should be able to reproduce the same features as the stock firmware (otherwise people might not want to use it and will prefer the factory firmware).

question: are you planning on publishing the code for your custom images, or will it be something that you prefer to keep closed-source?

My current 3.1 kernel is setup very similar to your kernel.
I have a customized version of mjpg_streamer in order to stream the v4l video from the camera.
I also have most of the networking tools setup (wifi + LAN driver too).
I just need to piece everything together into a complete functional package.
I also need to setup an http server & build somekind of web front-end (but this should be the easiest part).

So, basically, the biggest part that has been missing from my setup is the GPIO stepper motor control...
« Last Edit: May 27, 2013, 06:52:32 pm by changosurf »

May 28, 2013, 03:50:16 am

Just for my curiosity, why do you need the additional torque / more speed ? Are you planning to create a kind of robotic/moving device ?

These Foscams and clones are very suitable to make a robot. I took one apart to make a little ROV and it's not doing bad at all. I'm hanging at your lips for any way to increase speed / torque!

May 28, 2013, 04:56:00 am
ok, here are some updates on all of this...

1) I managed to setup the stepper control code so that you can run both motors at the same time, with varying directions and number of steps for both the horizontal & vertical axes separately.
So, from the command line, i can currently do something like this:
Code: [Select]
$ stepper [speed] [horiz_step_count] [horiz_direction] [vert_step_count] [vert_direction]

By using this method, it's not possible to have different speeds for each axis;
simultaneous movement in both directions requires that only one speed be used.

Once I manage to get a device driver built, Im thinking that ideally you should be able to open up the device file, '/dev/pantilt', and write some kind of command string.
Perhaps something like:
Code: [Select]
// control string format
// [r|a:][p:][+/-]horiz_offset;[r|a:][p:][+/-]vert_offset;speed
// +/- value for offset indicates direction
// offsets can contain a modifier [r|a:val] => relative or absolute offset
// if not specified, defaults to relative offsets
//   *absolute offsets must be positive
//   *direction will be ignored for absolute offsets
//   *x 'origin' is at right-most limit (facing towards camera) of horizontal range
//   *y 'origin' is at bottom of vertical range
// percent offsets can also be specified by adding 'p:' modifier
// example: to center camera, use absolute 50% offsets, 'a:p:50;a:p:50'

// So, the following string

char *camCTL = "-30;a:20;600";

// would move the camera:
// - horizontally CCW 30 steps (relative to its current position)
// - vertically to the absolute position of '20' steps from the bottom
// - at a speed of '600' speed units (speed still needs to be worked out)

//now write to device file

int fp = open("/dev/pantilt", O_RDWR);
write(fp, camCTL, strlen(camCTL));

// reading from the device should provide status messages
// on the current speed setting, x,y ranges & positions
// So, doing something like the following...

char buf[BUFSIZ];

// would print something like:
// speed:600
// x-range:500
// x-position:125
// y-range:80
// y-position:20

2) I also set up some 'calibration' routines that pan/tilt the cam through its entire range of motion in order to calculate the size of the horizontal & vertical ranges and to then 'center' the camera (while at the same time keeping track of the current position in both the horizontal and vertical directions). This will make it possible to perform movements to 'absolute' positions, which also leads to cool stuff like being able to have preset, user-defined 'camera patrol paths'. It also adds a little bit of a safeguard/protection for the stepper motors; since the current positions & movement ranges are known values, the motor control logic will not allow a user to try to run past the lower or upper boundaries of the valid x,y motion ranges (thus preventing the motor from being overworked or damaged due to having the motor 'banging' against the boundary limiters).
The only issue with this so far is that it's not 100% reliable, since the camera's position can be 'disturbed' by something or someone 'altering' the camera position, either with their hands or by some other outside mechanical force. If that were to happen, it would require that the calibration routine be run again. I guess this would require some kind of 'boundary checking' routine that will periodically verify that the calculated boundaries values are still valid? dunno, need to think about this some more...

3) slow speeds are still an issue, and it doesn't appear to be fixable until I can actually get a driver going that works and can leverage the lower latency available in kernel-space. Assuming that we *can* in fact go high-speed within the driver, it will certainly help a lot with the calibration routines (which are currently painfully slow).

...and that's all for now; questions/comments/feedback are welcome...
« Last Edit: May 28, 2013, 07:31:09 am by changosurf »

May 28, 2013, 09:45:38 am
This may be a bit off topic but since you seem to know your way around stepper motors; what would I need to drive heavier motors? I understand there's half a H-bridge on the chip for each coil, can I just use that to drive some bigger transistors (i.e. cut the leads to the current motor and solder a beefy transistor on the end of those?)

May 28, 2013, 12:14:44 pm

The ULN2803A chip used to drive the camera motors is rated at 500mA per output (outputs can be joined to increase max. current). But be careful not to draw too much power as the PCB design almost certainly wasn't designed to survive high amperage. If you need to drive bigger steppers build an external circuit (don't forget about a good power supply) disconnect connectors from the camera small steppers and use them as a control signals to drive your bigger transistors/bridges/whatever - no need to cut leads etc.

BTW: any details, pictures of your ipcam-robot ?


Good work, how fast (more-or-less) are you able to pulse the steppers using your code ?

According to the datasheet for 24BYJ motor used in my clone-cam ( the operating frequency  PPS (pulses per second) is 100. Depending on the actual load it might be possible to spin it faster.

To answer your question about publishing the code: Sure no probs, but I'd have to tar/zip the whole kernel source and userspace directory tree and upload it somewhere (as you know it can be quite big).

Would you be willing to share your customised mjpg_streamer ? I was going to adapt it as well, but there's no point in reinventing the wheel.

May 28, 2013, 08:20:57 pm
Ok, I've managed to get a driver going that implements all of the features that I listed above.
The driver is pretty much done and is almost 100% functional, I just need to clean up the code a little bit. I didnt include any of the LED control code stuff, but a good question would be 'where should the LED control go?' should it be included into the same pan/tilt driver, or should it have its own separate driver?

I think the driver is pretty cool so far; you can do something like this:
Code: [Select]
/ # cat /dev/pantilt
/ #
/ # echo '60,-10,2000' > /dev/pantilt #moves the camera +60x,-10y,2000 microsecond pulse speed

I don't have an exact number of pulses/second for the actual motor.
Im using the 'udelay()' kernel function to setup the timing in the driver, and a value of about 2000 microseconds seems to be working pretty fast & responsive. Now the pan/tilt calibration routines fly through and finish in a hurry. The exact number for the udelay value might still need some adjustment, but so far it seems pretty close to the factory firmware's speed & smoothness. Also, I'm still running in 'dual-phase,full-step mode, so this might affect the performance of the movements; when I get a chance, Im going to try lowering it back down to the regular 'single-phase, full-step' and see how it responds.

On publishing the source for the custom kernel, it wouldnt be necessary to publish everything; just the most 'interesting' parts that are relevant to the project.

as soon as I get a chance, I'll get you the code for my custom (hacked) version of mjpg_streamer.
It might not be the best solution for streaming the video, but it was the fastest way to get started with something that worked. Some of the mjpg-streamer code might be excessively bloated and unecessary, so it might need to be hacked down even more, or perhaps even just scrapped altogether in favor of a more compact, custom solution that simply pulls the image data from the camera and sends it somewhere else.

How should I send it to you? should I post it here, email, upload it somewhere? let me know...

« Last Edit: May 28, 2013, 11:22:55 pm by changosurf »

May 29, 2013, 06:33:07 am
ok, I have an initial version of the pan/tilt driver ready to release for anyone who'd be willing to test & play with it. You'd need to feel comfortable modifying makefiles and configuring the source code in order to compile it as a built-in driver. Whoever is interested, PM me...

coming soon: a separate, more simple driver for controlling the camera's LED...I'd welcome feedback on the type of functionality that would be desired for the LED driver (i.e., just a simple 'on/off' switch, or something more complicated, like a driver-driven 'flashing' routine, or something more sophisticated).

thoughts/feedback/questions are welcome...