So this question is more for the college students, but it’s open season for anyone…
How would you go about getting individual control for more than 10 motors? In college, you are allowed 12 motors, but you only have 10 spots… so how do you go about getting individual control for each motor? (While still maintaining legality)
For the VEX people, I know this isn’t the official question area, but any ideas?
It is possible I think, but difficult, to use digital outputs to generate pwm pulses for two more motors using RobotC. The difficult part is that even when “Hogging” the cpu there is a background task running every 15mS that takes 1mS (approx) of cpu time away from the current task. The trick is to synchronize the user task with this background task so that the generated digital pulse is not extended by it. I was interested in being able to synchronize with this for another reason. The way I started to do this was to use the global variable nIfiSPIMsgCounts which increments during the background task, that is, detecting this value changing in a tight loop indicates the start of the next 15mS period. Pulse generation would have to use loop delays and it would be important that no other user tasks interrupted this process. Anyway, that’s the general principle. The user generated pulse would then need to be taken through a power expander so battery power was used for the motor (again a theory, not tested). Do not connect the motor to the 5V power on the digital out port.
Here, if you have access to an oscilloscope take a look at the pwm signal on digital out 1. There is still some jitter (perhaps 20uS) due to other background interrupts but it may work. It’s more stable when not being debugged by the PC. High school students, don’t go here, definitely college only. Again Do not connect digital outputs directly to motors.
#pragma config(Sensor, dgtl1, DigiOut, sensorDigitalOut)
//*!!Code automatically generated by 'ROBOTC' configuration wizard !!*//
task UserPwm()
{
int oldspi;
int i;
while(1)
{
// hog CPU
hogCPU();
// synchronize with background task
oldspi = nIfiSPIMsgCounts;
while( oldspi == nIfiSPIMsgCounts)
;
// pulse high
SensorValue DigiOut ] = 1;
// 1.5 mS pulse - add a variable here for vary pulse length
// change between 1mS and 2mS. About 100 loops per 500uS.
for(i=0;i<310;i++)
;
// pulse low
SensorValue DigiOut ] = 0;
releaseCPU();
// Wait until the 15mS are almost over
wait1Msec(10);
}
}
task main()
{
StartTask( UserPwm );
while(1)
{
wait1Msec(1000);
}
}
I wanted to add a few more thoughts as it was pretty late yesterday when I posted this idea.
The drive strength of the digital output would need to be verified. I don’t know what’s in the motor controller 29 and the digital output may not drive it.
I made an assumption on how the power expander works, this also needs to be verified.
It may not be competition legal, the existing motors are controlled by the LPC2458 supervisor processor as far as I can tell, this allows motors to be disabled independently of the user code. Motor control from user code may be illegal.
I tried something like this a while ago with very limited success. It doesn’t take much to break this scheme, particularly if you are using multiple tasks in your program.
It was enough to drive a 3-wire servo, so I suspect it would work with an MC29 too.
Yep, this is what I did, and it works fine.
One VERY IMPORTANT NOTE: Do NOT mix motor port cables and data port cables into one Power Expander. It bridges the +V lines for all 4 inputs. The motor port lines have their +V lines at full battery voltage. The data port lines have their +V lines at a regulated 5V. If you attach both to a single Power Expander, that will bridge between the raw battery voltage and the +5V rail, resulting in a fried microcontroller. Do not mix-and-match signal sources on a single Power Expander.
Other similar chips of type ‘embedded cpu’ have internal timers that can be set to deliver a given pulse-width without cpu code intervention every cycle.
Does the Cortex have that type of feature?
It does, though I don’t know the pin mapping between the CPU and the I/O ports, so it is hard to tell how many are actually available. The timer-capable GPIOs may be used for the motor ports (that was true of the Vex PIC microcontroller).
Regardless, I’m not sure how you would manage them from your program. As far as I can tell, neither EasyC nor RobotC give you the register-level access you would need to manage the on-chip resources directly. I’d like to be able to use the I²C port, but that doesn’t seem to be possible with the available development environments.
There’s certainly no register level access from RobotC due to the VM implementation. I get the feeling it would be possible from EasyC as under the hood it’s using the arm gcc compiler linking against their runtime library. The datasheet for the STM32F103 that runs the user firmware is available so it should be possible to figure out where digital IO is connected. Whether it’s worth the effort is debatable. I wish VEX would release more technical documentation for those users that want to utilize the hardware in non standard ways.
The code I threw together last night gives a pretty stable output, synchronizing to the background task helps a lot. Normally this type of task would be given a higher priority than other user tasks, however, so far I have not been able to get RobotC to start tasks with different priorities, it just gives a runtime error.
I won’t pretend to answer any of the questions in this thread, but I do know that I²C support is on the product roadmap for an upcoming firmware release.