How to soft start 12v12?

I am using 12v12 motor controllers for a simulator motion platform. The situation is that when off and unused, gravity pulls the platform to a resting position at the extremes of motor/servo travel. When I bring up the system software, it commands the 12v12s to their center/neutral positions and they go there with full force using the running PWM values. In an unloaded system, this is very abrupt and forceful.

What I need to do is read the initial motor positions, command those positions, energize the motors, and walk the motors to the desired neutral/rest positions. What I’d like to do is a soft start / homing motion that even though it’s running with full force, is a gentle and gradual motion.

I can do this manually in the JRK utility or can write my own software utility to do this, but was wondering if someone had already built such a thing. I would think this would be a common requirement in motion control. I’ve looked here and don’t find it, though.

Anyone know? Thanks in advance for any help.

Hello.

The jrk does not have any built-in support for a soft start like that, but you might be able to add that kind of function the way you mentioned (e.g. reading the current position of the motor to set the target and ease into the “resting” position of the simulator). I am not aware of any specific examples of this, but if you have not done so already, you might try posting on various DIY simulator-related forums (such as XSimulator) as well.

Brandon

Hey Brandon, thanks - and already written! I used Pololu’s example code and did just that - read the scaled feedback values and incremental/decremented until I hit the 2048 midpoint. It works great and the set target command in the example also turns on the motors. The scaled feedback values are perfect to use as initial values for setting the targets.

But I do have another question - the example uses command port on port values. Do those ever change? The JRK setup utility uses the JRK identifier. How do I turn that into a com port value or is it just a matter of formatting that correctly into the command to open the com port?

-Z

And another question, when I do a scaled feedback read, does that do whatever signal averaging has been configured on the JRK? I would bet it honors that but wanted to make sure.

Thanks!

Normally, Windows assigns a unique COM port number to each jrk motor controller. The assigned COM port number is associated with the device’s serial number, so the same controller will always be assigned to the same COM port no matter which USB port you plug it into on that computer. With multiple jrk controllers, you should be able to use that to know which device you are talking to based on its COM port name. For example, your program could be configured to know that “COM4” always corresponds to controller number 1, and “COM5” always corresponds to controller number 2.

Another option is to use the Pololu Protocol to send a serial command requesting data from the jrk controller. If you get a response, you know that the device number you used in the serial command was correct. If you don’t get a response after some amount of time, you know that the device number was wrong and you can try a different one.

For your second question, yes, the scaled feedback returned is after the averaging (and scaling) is applied.

Brandon

Perfect! Thanks Brandon!

Since the com ports are sticky, that’s good enough for me. And I suspected the averaging/scaling was in the scaledFeedback but wanted to check.

I’m a little leery about sending stuff out to see if/what response I get. I know odds are small that I would put anything into a weird state, but I’d rather not risk it and the com ports being sticky means I don’t need to.

By the way, here is the code I came up with to soft start the JRKs for motion platform use with SimTools from xsimulator.net in case anyone else would find it useful. It’s all based on the example in the 12v12 manual with only a few changes/additions. Thanks to you guys for the head start!

Built using MinGW on Win10 worked great! It’s certainly not pretty. I was just trying to get things to work and haven’t had time to really comment or clean up.

The source:

// Uses POSIX functions to send and receive data from a jrk.
// NOTE: The jrk's input mode must be "Serial".
// NOTE: The jrk's serial mode must be set to "USB Dual Port".
// NOTE: You must change the 'const char * device' line below.

#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#include <time.h>

#ifdef _WIN32
#define O_NOCTTY 0
#else
#include <termios.h>
#endif

char version[10] = "0.2b";

// Reads a variable from the jrk.
// The 'command' argument must be one of the two-byte variable-reading
// commands documented in the "Variable Reading Commands" section of
// the jrk user's guide.

int jrkGetVariable(int fd, unsigned char command)
	{
	if(write(fd, &command, 1) == -1)
		{
		perror("error writing");
		return -1;
		}

	unsigned char response[2];
	if(read(fd,response,2) != 2)
		{
		perror("error reading");
		return -1;
		}
	return response[0] + 256*response[1];
	}

// Gets the value of the jrk's Feedback variable (0-4095).
int jrkGetFeedback(int fd)
	{
	return jrkGetVariable(fd, 0xA5);
	}

// Gets the value of the jrk's Scaled Feedback variable (0-4095).
int jrkGetScaledFeedback(int fd)
	{
	return jrkGetVariable(fd, 0xA7);
	}

// Gets the value of the jrk's Target variable (0-4095).
int jrkGetTarget(int fd)
	{
	return jrkGetVariable(fd, 0xA3);
	}

// Sets the jrk's Target variable (0-4095).
int jrkSetTarget(int fd, unsigned short target)
	{
	unsigned char command[] = {0xC0 + (target & 0x1F), (target >> 5) & 0x7F};
	if (write(fd, command, sizeof(command)) == -1)
		{
		perror("error writing"); return -1;
		}
	return 0;
	}

int main(int argc, char *argv[])
{

printf("Home vers. %s\n", version);

// Validate inputs
printf("Inputs = %d.\n", argc);
if (argc != 4)
	{
	printf("Usage is home.exe <step size> <com1> <com2> eg: home.exe 2 COM4 COM7\n");
	return -1;
	}

printf("%s %s %s %s\n", argv[0], argv[1], argv[2], argv[3]);

int step = atoi(argv[1]);
if ((step < 1) || (step > 10))
	{
	step = 1;
	}

printf("Using step size of %d.\n", step);

// Open the 1st Jrk's virtual COM port.
char dev1[10];
char dev2[10];

sprintf (dev1, "\\\\.\\%s", argv[2]);
sprintf (dev2, "\\\\.\\%s", argv[3]);

const char * device1 = dev1;
int fd1 = open(device1, O_RDWR | O_NOCTTY);
if (fd1 == -1)
	{
	perror(device1);
	return 1;
	}

// Open the 2nd Jrk's virtual COM port.
const char * device2 = dev2;
int fd2 = open(device2, O_RDWR | O_NOCTTY);
if (fd2 == -1)
	{
	perror(device2);
	return 1;
	}

#ifndef _WIN32
struct termios options;
tcgetattr(fd, &options);
options.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN);
options.c_oflag &= ~(ONLCR | OCRNL);
tcsetattr(fd, TCSANOW, &options);
#endif

int sfeedback1 = jrkGetScaledFeedback(fd1);
printf("Current Scaled Feedback1 is %d.\n", sfeedback1);

int sfeedback2 = jrkGetScaledFeedback(fd2);
printf("Current Scaled Feedback2 is %d.\n", sfeedback2);

int setting1 = jrkGetTarget(fd1);
printf("Old Setting1 is %d.\n", setting1);

int setting2 = jrkGetTarget(fd2);
printf("Old Setting2 is %d.\n", setting2);

// Starting positions
int target1 = sfeedback1;
int target2 = sfeedback2;

int final1 = 2048;
int final2 = 2048;

int working1 = 1;
int working2 = 1;
while ((working1 == 1) || (working2 == 1))
	{
	if (target1 > final1)
		{
		target1 -= step;
		jrkSetTarget(fd1, target1);
		if (target1 <= final1)
			{
			jrkSetTarget(fd1, final1);
			working1 = 0;
			}
		}
	else
		{
		target1 += step;
		jrkSetTarget(fd1, target1);
		if (target1 >= final1)
			{
			jrkSetTarget(fd1, final1);
			working1 = 0;
			}
		}

	if (target2 > final2)
		{
		target2 -= step;
		jrkSetTarget(fd2, target2);
		if (target2 <= final2)
			{
			jrkSetTarget(fd2, final2);
			working2 = 0;
			}
		}
	else
		{
		target2 += step;
		jrkSetTarget(fd2, target2);
		if (target2 >= final2)
			{
			jrkSetTarget(fd2, final2);
			working2 = 0;
			}
		}
	usleep (5);
	}

setting1 = jrkGetTarget(fd1);
printf("New Setting1 is %d.\n", setting1);

setting2 = jrkGetTarget(fd2);
printf("New Setting2 is %d.\n", setting2);

close(fd1);
close(fd2);

printf("Done!\n");

return 0;
}
1 Like