Arduino Question (ping Arduino Masters)

Getting more into arduino and writing a class for the BTS7960 Motor driver module here is the start and whats written and can be tested works (lots more todo but I got a day into that) so I post the code and then the question at the bottom of it

#define BUFF_SIZE 40
char pbuff[BUFF_SIZE];
boolean toggle = false; // is a divide by 2 to get the 1khz output signal
/*
Sub class of BTS7960. Needs the following
PIN/Name on Module Description
3 and 4 L_EN R_EN Shorted together to PWM needs a PWM pin on the arduino
1 marked RPWM FWD pin on the Arduino
2 marked LPWM REV Pin on the Arduino

Truth table logic
PWM FWD REV Result

pwm 1 0 Fwd controled speed by pwm
pwm 0 1 Rev "
1 0 0 Break - motor leads shorted
0 x x Coast - all off

IS1 and IS2 connect to an analog input pin and will read the current depending on which side is on
analogwrite(0) will turn it off and analogwrite(255) will turn it on

We limit it for now to 6 motors max on a Mega and 2 on UNO and Nano
for each motor that is used the corresponding timer (1 or 2) is set to approx 4 KHz

Arduino UNO, Nano (Remember A4 and A5 are reserved for wire library - I2C)

Motor PWM Pin in1_fwd in2_rev, IS Enc Pins(Quadrature) LS suggestion

0 9 T1 7 8 A0,A1 6,5 13,2
1 10 T1 11 12 A2,A3 3,4 A4,A5 (if not I2C used or A6,A7 on Nano

MEGA 2560

Motor PWM Pin in1_fwd in2_rev, IS Enc Pins(Quadrature) LS suggestion TBD

0 11 T1 24 25 A0,1 26,27
1 12 T1 28 29 A2,3 30,31
2 9 T2 32 33 A8,9 34,35
3 10 T2 36 37 A10,11 38,39
4 8 T4 40 41 A12,13 42,43
5 7 T4 44 45 A14,15 44,45

*/
#define F_ERROR 0 // 0 no error 1 is error
#define F_ENABLE_LS1 1 // 1 = use limit switches use limitswitch ls1 tied to in1 (fwd)
#define F_ENABLE_LS2 2 // 1 = ls2 tied to in2(rev)
#define F_LS_OPEN 3 // Limit switch unactivated state either 0 or 1 depending on NO, NC and if tied to ground or VCC
#define F_ENCODER 4 // Encoder is present or not
#define F_QUADRATURE 5 // Encoder if present is Quadrature (immaterial if F_ENCODER = 0
#define F_REVERSE 6 // Reverse the motor (0 - speed input) if 1 but leaves LS assignments alone
#define F_DIRECTION 7 // current direction reflection of in1(FWD) pin. Can be used to guess direction if not quadrature encoder
#define F_BREAK 8 // Motor in break mode
#define F_COAST 9 // Motor in Coast mode (disabled)
#define F_ENABLE_CS 10 // Use Current control (limit to max current)

class BTS7960_D {
public:
BTS7960_D(uint8_t pwm, uint8_t in1, uint8_t in2);
void Enable_CS(uint8_t is1, uint8_t is2);
void Disable_CS();
void Break();
void Coast();
bool Drive(int16_t mspeed);
uint16_t getStatus(); //Returns flags
void Reverse(); //sets reverse flag
void Update(); // needs to be called periodically to check thingslike current, switches, encoders etc etc

private:
// pins
uint8_t _pwm; // pin for pw
uint8_t _in1; // pin for L_EN which is connecte internally to in_1
uint8_t _in2; // pinf for R_EN
uint8_t _is1; // Current sense 1 pin must be analog pin
uint8_t _is2; // Current sense 2 pin "
uint8_t _sw1; // Limit switch in the in1 direction
uint8_t _sw2; // Limit swithc in the in2 direction
uint8_t _enc1; //encoder input 1
uint8_t _enc2; //encoder input 2
uint8_t _ls1; //Limit Switch input 1
uint8_t _ls2; //Limit Switch input 2
int16_t _curr_Speed; // -255 to +255 0 will coast
int16_t _last_Speed; // -255 to +255 0 will coast
uint16_t _flags = 0; // 7 - enable, 6 - reverse, 5 - useLimits, 4 - usequadrature, 3 - useencoder, 2 - direction, 0 - error
//8 - LSforward, 9 - LSreverse
};
/*
Constructor do basic rudimentary setup
/
BTS7960_D::BTS7960_D(uint8_t pwm, uint8_t in1, uint8_t in2) {
_pwm = pwm;
_in1 = in1;
_in2 = in2;
pinMode(_pwm, OUTPUT);
pinMode(_in1, OUTPUT);
pinMode(_in2, OUTPUT);
}
void BTS7960_D::Update() {
//if we hit the limitswitch and the limitswitch is active then stop the motor
if (bitRead(_flags, F_ENABLE_LS1) == 1) {
if (bitRead(_flags, F_LS_OPEN) != digitalRead(_ls1)) {
this->Break();
}
}
}
/

Use currentcontrol
/
void BTS7960_D::Enable_CS(uint8_t is1, uint8_t is2) {
_is1 = is1;
_is2 = is2;
bitWrite(_flags, F_ENABLE_CS, 1);
}
//reverse motor direction
void BTS7960_D::Reverse() {
bitWrite(_flags, F_REVERSE, 1);
}
/

Disable Current Sense
/
void BTS7960_D::Disable_CS() {
bitWrite(_flags, F_ENABLE_CS, 0);
}
/

get statusflags
/
uint16_t BTS7960_D::getStatus() {
return _flags;
}
/

Put motor in coast by disabling the unit
/
void BTS7960_D::Coast() {
analogWrite(_pwm, 0); // will set the pin to 0
_last_Speed = _curr_Speed;
_curr_Speed = 0;
}
/

Put the motor in break by turning both lower ends on and the upper ones off
*/
void BTS7960_D::Break() {
analogWrite(_pwm, 255); // will set the pin to 1
digitalWrite(_in1, 0);
digitalWrite(_in2, 0);
_last_Speed = _curr_Speed;
_curr_Speed = 0;
}
//Drive the motor positive = FWD negative = reverse
bool BTS7960_D::Drive(int16_t mspeed) {
if (bitRead(_flags, F_REVERSE) != 0) {
mspeed = 0 - mspeed; // reverse it
}
if (mspeed > 0) // forward
{
if (bitRead(_flags, F_DIRECTION) != 1) {
this->Break();
}
bitWrite(_flags, F_DIRECTION, 1); //Set direction
digitalWrite(_in1, 1);
digitalWrite(_in2, 0);
analogWrite(_pwm, mspeed);
}
else {
if (bitRead(_flags, F_DIRECTION) != 0) {
this->Break();
}
bitWrite(_flags, F_DIRECTION, 0);
digitalWrite(_in1, 0);
digitalWrite(_in2, 1);
analogWrite(_pwm, abs(mspeed));
}
_last_Speed = _curr_Speed;
_curr_Speed = mspeed;
return true;
}

//pin definitions
//Uno
#define P_U_PWM1 9
#define P_U_IN1 7
#define P_U_IN2 8

BTS7960_D motor1(P_U_PWM1, P_U_IN1, P_U_IN2);

void setup() {
Serial.begin(115200);
snprintf_P(pbuff, sizeof(pbuff), PSTR(“BTS79860 Test Boot up”));
Serial.println(pbuff);
TCCR1B = TCCR1B & B11111000 | B00000010; // for PWM frequency of 3921.16 Hz
motor1.Drive(-64);

}

void loop() {
// put your main code here, to run repeatedly:
motor1.Update();
}

As you can see in loop() there is the motor1.Update() which will stop the motor when it hits a limit switch or ramp the speed (to be written) or adjust the speed if we exceed a current limit etc or reach the limit of the encoder (to be written)

Ideally I would like to call that like every 10 ms or so - as often as possible but reliably regularly) so maybe through a timers ISR. But as there are possibly multiple instances (up to 2 on an UNO/Nano up to 6 on a Mega) it would be nice if we dont have to put all the Motor_n.Update() routines in the loop or ISR routine but the Class method Update() attaches itself to a timer - preferably the one associated with the PWM to sync it to the PWM pulse or every nth pulse so we kill the motor or change the speed at the rising edge.

Any Ideas to make this “cool” and easy to use?

This looks like an interesting project. I have a few comments to hopefully help you get started.

First, a word of caution: This looks like a fairly powerful motor driver. Please be careful while debugging your Arduino logic that you don’t have this connected to a mechanism that might actually use that much power. Or have a plan for how to quickly shut things down if it goes sideways.

Your code has a lot of features that don’t seem to be fully implemented yet, but I do notice a couple things unrelated to your main question. First, a pet peeve of mine, the word is “brake,” not “break.” When you short the terminals of a motor to stop it, you are applying the “brakes” of a car. You are not damaging the motor, as the word “break” would imply.

To brake the motor, you want to enforce the same voltage at both terminals. I would not use a PWM signal to attempt this, because even a “full on” PWM waveform spends part of every cycle in the “off” state. Instead, I would disable PWM and set the two PWM output pins either LOW or HIGH using the digitalWrite() function, and set L_EN and R_EN to a HIGH logic level.

In a similar vein, to coast the motor, you want to disconnect one or both motor terminals from any control voltage. You would do this by tri-stating the h-bridge outputs - set L_EN and/or R_EN to a LOW logic level.

I don’t see in your code that you are controlling both PWM lines. According to the specs for that driver, the RPWM and LPWM lines are the HIGH/LOW output controls. The R_EN and L_EN bits control tri-stating (disabling) the driver output entirely. So I think you want to be sure you understand electrically what the different pins on the BTS7960 module are doing before you get too deep into writing the driver for it.

Back to your original question, it is possible to dynamically attach interrupt handlers, but then you still have the problem once you get into the ISR of mapping that back onto one of your motor channels. You either need one ISR entry point hard-coded for each possible channel, or you need a generic ISR that can determine at interrupt time which motor channels are in use and enabled, which can introduce concurrency issues in your motor driver class. You may also start to run into limitations of which Arduino pins can be used for which functions at the same time.

I see why it might seem useful to avoid switching motor speeds mid-PWM-cycle, and there are ways to avoid this. But since this motor driver is simply using the PWM to deliver power to the motor coils, I wonder how necessary this is? Are you truly concerned about the energy commanded by a partial PWM waveform during a change-speed command?

If you do need to switch PWM only between cycles, you can (on some processors) read back the PWM timer value to determine where you are in the cycle, or you can attempt to synchronize your timer interrupt with the PWM generator, though that seems like it could be tricky for a variety of reasons. You can also simply read back the value of the PWM output pin using digitalRead() to determine whether the waveform is in a LOW logic state, and therefore between cycles.

There are a lot of ways to structure the logic, but TBH, I would start by getting the basic forward/reverse/coast/brake behavior working, and then introducing PWM speed control. Once you have the basic electrical functions working under software control, then move on to making the programming interface more elegant.

I hope these comments are helpful. I look forward to seeing where you take this project.

2 Likes

Look at the chips sheet and the truth table for it. I picked that way with 1 PWM to avoid some problems and gain some features if you look at the schematics of the board they just go to a driver to the IN and INH ports. IF I use the L_ and R_EN and tie them together and put the PWM then every time the PWM signal goes low (as the 2nd PWM is low I energize (turn on) both lower halfs of the bridge which does a brake on the motor for a very short time - very inefficient. The “alternative” method turns the motor on the low phase into a coast. So you just on/disable instead if on/brake with the pwm signal. Now i verified some claims with the scope that analogWrite(pin, 0) will turn PWM off and keep the output low and analogWrite(pin, 255) will do a straight on that is a feature of the arduino implementation of that command and according to the web on purpose especially for that fact.

As for thesting - right now its just sitting on the bench connected to some scopes and meters and nothing is moving. I used to “roll my own” motor controllers in the 70s and 80s and have some painful memories of a 2 HP motor going rogue due to a design error or “unintended feature” as they are also called. Wish I’d had an arduino back then. And yeah still some todo. as the drivers with shipping are < $4 and an arduino Nano can handle 2 which is also < $4 add a fan and some 3DP to mount it and you control 2 motors for <$15 with a feature set of about a talon SRX. I will include the wire library and control the Nano/controller sets via I2C (pin A4 and A5) and using the nano as it has 2 extra pins a6 and A7 which allows to control 2 motors each with 2 limit switches and a quadratur encoder or regular encoder as in the bosh motors for example.

here are the schematics of the controller (verified by me)
https://www.aliexpress.com/item/1005001631113020.html?spm=a2g0o.productlist.0.0.1d5473d8WBv4jN&algo_pvid=2cfca9b7-3bc4-4b45-b225-01ec4bcc4fa6&algo_expid=2cfca9b7-3bc4-4b45-b225-01ec4bcc4fa6-0&btsid=0bb0622c16224687235858761e5021&ws_ab_test=searchweb0_0,searchweb201602_,searchweb201603_

and here is the chip
https://www.digikey.com/htmldatasheets/production/70497/0/0/1/bts7960.html?utm_adgroup=General&utm_source=google&utm_medium=cpc&utm_campaign=Dynamic%20Search_EN_RLSA&utm_term=&utm_content=General&gclid=Cj0KCQjwktKFBhCkARIsAJeDT0hHkqGPpl-vifAgOO_Y6mGggvi4-lkIMXInq_P-xRqJjXg2RmsPC6gaAoixEALw_wcB

The IS is tied to ground with a 1K resistor on the board and will provide the current sense (not verified yet until I got a rig to run the motor under torque. but according to the Manual it will give about 5V at 43 A and almost 0 (some leakage) when off. So now I can take both IS lines into 2 analog in which I am doing right now or make a circuit to mix the 2 signals together in an analog fashion and use 1 analog input. I am testing right now on an UNO as the 10 nanos I ordered from China for $ 32 including shipping (328 variety) wont be here until june 24 its claimed. Besides the tester we need it to control 5-7 motors on the CORY off season project and kids are planning some other projects that would need about 5 more controllers so we are talking a total of about 15 controllers there abouts plus 5 for the tester. But the tester ones will be controlled from a mega which can handle 6 motors with all feedbacks so the main motivation for this was $$$

I understand what you’re doing there, but that’s not the usual way to use an h-bridge. The first link you provided lays out two methods of using the driver, neither of which uses the tri-state that way.

I think what you’ll find is that your method will be more efficient at getting the motors spinning, but it will have a harder time doing precise speed control, since the only way for the software to proactively slow the motor would be to reverse the speed. (You are optimized for acceleration, not steady state.) I think you’ll find that approach is disadvantageous for use with a PID control loop in situations where you are trying to achieve precise speed control, as one example.

It’s a novel approach to be sure, and I hope my feedback doesn’t deter you from further experimentation.

You should also be aware that, according to the datasheet, toggling INH has the side-effect of resetting the chip’s thermal overload protection flag. This may not be something that you want to be doing on every PWM cycle. It also implies that INH does more than just float the driver output.

1 Like

If I am reading the documents correctly, then R_EN and L_EN are connected to the active-low inhibit pins of each BTS 7960B half-bridge, while RPWM and LPWM are connected to their direction-select pins. For a driver pattern of power-coast (high-load-low then floating), you would then want to have RPWM and LPWM at opposite levels while R_EN and/or L_EN are pulsed (“Usage Method 2”). Setting the _EN pins high and pulsing RPWM or LPWM high (“Usage Method 1”), as seems to be suggested by the module header’s labelling, would give you power-brake (high-load-low then low-load-low).

As was mentioned though, pulsing the _EN pins does defeat some of the thermal shutdown functionality. Also, I’m not sure if you would ever really need to access the two feedback pins independently, in which case you should just be able to short the outputs together and use logic to determine the states from the resulting voltage, though that would probably also require individually measured ratios and fault currents.

I’m not sure I recall the ATMega328 datasheet perfectly, but I think the N-1/N PWM case was actually handled at the timer output level. Perhaps I am lacking some foresight, but I don’t really see the issue with having a single odd PWM pulse coming from a non-synchronized timer change, though I would have to reread that chapter to get a firm grasp on what would actually happen when you change the threshold value.

Ultimately, using an ATMega328 and a “cost optimized” half-bridge chip, I think you are going to have to accept some limitations on what is practical. You should be able to get functionality, but the reason you can’t buy something with the feature set of a Talon SRX for $15 is not just profit margins. Speed control, limit switches, and basic serial communication seems doable, but I would be very surprised at something like closed-loop quadrature-feedback control or optimized current limitations.

Thanks - I check it out and all will come down to testing I guess. I thought of that so you have a choice to either connect the pwm to either INH or IN and use the other pin as a direction signal. In the one case you go power/break and have the thermal protection in the other you go power/off(coast) and do not have the thermal protection. For now I opt for #2. Idealy I go power/coast with the IS on Question will be that if how ever long the high side of the PWM cycle is if that is enough to trigger the error. It will also limit the reading of the IS pin (current feedback) to the time the PWM is high on the channel it is high - hence - would love to tie that routine to an interrupt to read the current/IS pin right then and there. Another option would be to put a small resistor (I got some 0.05 ohm) in line with the power in on the + side of the driver and run that through an opamp circuitry to measure the average current and translate it into 0-5v to be read by the arduino then with some RC and a diode you could keep it kinda stable for long enough to get a somewhat accurate reading. (+/- some motor noise). well here is the other part of the project

this is the display code where an uno drives a display (reading the SD card still needs to be done and some other things)

Tester_Display_UNO.zip (6.2 KB)

and this the mega part that will get that motor driver class

Tester_FW_1.zip (4.6 KB)

and here a little video showing some of what works atm
20210530-181508-1_45KL5CJ9.zip (4.3 MB)
Had to zip everything as it does not take MP4 or INO files

BTW on the bench with nothing on the motor - no load both ways make it run.

Guess I am going to be busy on this for a while but its ok - I am retired lol

The quadrature - closed loop I am pretty sure I can do - depending on the max frequency of the Encoder signal. Looking into interrupts right now and start to experiment with that. My shortcoming is that I just started to look into C++ arduino style. My background as a programmer for the past 30ish years was Xbase and a lot of SQL mixed with some PHP or VB for the frontend so mostly WAMP/LAMP internet data stuff. Before that I did a lot of automation but that was in assembly and some of it Hex coded and about 40 years ago. IOW I am just learning this stuff (yeah I did some Java stuff to be able to help the team with that)

So for efficiency sake I would like to make that interrupt driven in the “good old days” with only one interrupt on something like a TI9995 I Ored all the ones I wanted to process and tied the ouput of this multi Or circuit to the Interrupt and then by software see who caused it - can do that too but that would require an outside circuit, sane with the IS circuit The side where LSS is active and HSS is not does not output anything and the HSS high side only outputs when HSS is high so tying the 2 together will involve at least some diodes or you skew the result through at least the 1k resisto to ground - in effect you parallel those 2 resistors and both sides would be running on a 500 ohm resistor where it asks for a 1k. So you need to read the current when the apropriate HSS goes active or shortly thereafter it seems. I will have a better grasp on that once I test it under load.

Now if I can read that current and lets say I set it to 20 A (about 2.5V) I can use Bang Bang or something similar or maybe even some PID to keep it close to 20 A by playing with the PWM signal. That should work as I did that in the early 80s with some 555s and some op amps to convert the current to voltage by reading a resistor, then amplify it using some op amp circuitry and control the pulse with of the 555 with that voltage. and the desired current back then was selected with a pot that was part of the opamp circuitry. So there was “proof of concept” even though decades old.

My goal is though to make this easy and it could also benefit some other teams and it would be much more palletable to everyone to buy a nano and 2 drivers and then wire them together as compared to also making a board with a bunch of components that need to be soldered/wired correctly. Well if the IS dont work for the current then Resistor/op amp it will be

Just to be clear, I don’t see a “direction select” bit documented anywhere. The documentation labels the “left” channel as “forward” and the “right” channel as “reverse” but this assumes you are using the pair together.

It’s a fine point, but worth noting, as many stepper motor drivers have a single digital pin that specifies the forward/reverse direction of motor rotation, which is not exactly the case here.

EDIT: I see where maybe some of the confusion comes from. In the datasheet, it says:

IN I Input Defines whether high- or lowside switch is activated

…which, judging from the circuit diagram, is referring to whether the output is connected to the supply voltage, or to ground.

I was referring to those header pins on the module being connected, through a buffer, to pin 2 on each BTS 7960B half-bridge, which is labelled in its own datasheet as IN, Input: Defines whether high- or lowside switch is activated. My phrasing was poor there, I was trying to highlight the difference between the way the pins work on this module, with these half-bridges, and what seems typical, in my mind, for a full H-bridge motor driver.

Your edit is correct, each PWM pin would control whether one of the motor terminals (M+ or M- on the module silk-screen) would be connected to B+ or B-, and the _EN pin determines whether the connection in question is activated or not.

Yeah I know thats why you use the truth table indicated in the chip doc and what I look for and seem to have is

LSS1   LSS2   HSS1  HSS2        S1       S2       Verbose

ON       OFF    OFF   ON        OFF     CS        Forward
OFF      ON     ON    OFF       CS       OFF      Reverse
OFF      OFF    OFF   OFF      OFF     OFF      Coast
ON       ON     OFF   OFF      OFF     OFF      Brake

No Matter how you run it you only get current sense when HSSn is ON And you only get LSS to OFF if eithr INH is 0 or IN is 0 so to not have both LSS on (break) on the low end of the PWM you have to have INH of the oposing chip at 0 so you need to pulse INH otherwise you get a break every time lets say IN 1 goes low (as part of the PW) and the other side is low. So in my case IN1 != IN2 and that pair is the “direction” the only exception is during brake

Now as for syncing it I am looking into PCINTx to generate an interrupt for a pin. Works but now How do I include that into a class lol. I could make it static but then that static routine would have to know all classes that already exist of that kind to check their pins? Maybe something similar to an arraylist collection in other languages?

Quadrature closed-loop is certainly not an impossibility, just a challenge, and one I don’t think this set of hardware is especially conducive to. I recall looking at doing ISR encoder reading on an Arduino like this and found that, for my use case at least, there was too much tiptoeing around other interrupt-driven libraries to be comfortable using it. I ended up going with another common hobby chip, the ESP32, that has built-in hardware for pulse counting that is far more capable than what I could hope to expect doing ISR decoding on the ATMega328.

While the BTS 7960 datasheet specifies values at 1kOhm, I don’t really see anything to suggest that 500R would pose any sort of problem. Certainly with something like 1M or 1R would be bad, but the phrasing implies that other values than 1K exactly are viable. If you wished, you could also just tie the two feedback pins together and remove one of the resistors to maintain the 1K to ground. The current outputs should flow together just fine.

I don’t want to imply that it can’t be done, and especially not that you in particular would be unable to or incapable of achieving it. Seeing some of what is out there in terms of chips for driving and controlling motors and mechanisms, using this set of hardware seems like it is not giving any benefit to the difficulty of the project as a whole. In terms of software, it is hard to give advice or suggestions without really knowing what the intent of the project is, or what sort of API you are looking to implement. Is this code/microcontroller solely for driving the motor and interpreting basic commands from a more central robot controller, or is this it? I’ve inferred the latter, but reading things like limit switches as a single call in a whole-robot loop seems like it has the potential for disaster. Is this supposed to be a fairly close analog to FRC code, or is it just going to be completely off to the side?

1 Like

I am not sure where you got that truth table from, but I’m not sure it is telling the whole story. There is a truth table on page 19 of the datasheet for the part.

It is derived from that datasheet as the “goal” of having the 2 chips work together. Based on that goal and the one in the datasheet I work on the code

ATM I don’t use any API out there - I found one fro the BTS7960 which is extremely rudimentary. And does not support anything beyond turning the motor off and on. Now if you know one that supports that and is full featured - lmk. Also if you know other hardware/software solutions that are really inexpensive I am interested.

As for the goal… We are a poor club that wants to do all kinda things. Right now we are building a material tester and a community outreach robot the community outreach bot has a budget of about $500 and stuff we have a lot off lying around and probably wont use that much in the future (like for example CIMs which will more and more be replaced by NEos) So for example CORY - the community outreach robot will use 5-7 CIMs it is also a test platform so for example the drive train will feature this
WheelPlanetary
which is a 3DP 8:1 gearbox inside a wheel - so far tested out great for anything except being mounted to a robot Its 3DP out of HIPS, ABS and Nylon and TPU (combined a little over 1lb) uses a handful of 608 bearings Now if it survives on CORY it will go into a bot for an off season competition and then maybe into a FRC competition one. So on Cory we have the choice to either buy some motor controllers or roll our own. We would like to include things we did with our competition robot on some of the controllers like for example the arms - if it hits something we don’t want to drive you into the ground or tip the bot over but stop. In our competition bot we read back the current from the talon SRX so if we decide that >10A lets say is a problem - then we stop. This

Lif2

is going to be the heart of a tester and maybe the prototype of a lifter its a 276:1 compound planetary. In the tester it will be run by 3 CIMs that will “work as one” and will be programmable to apply a predetermined torque on something. So If I set it to 200lb I want it to simulate the weight of something 200lb if I set it to 300lb etc. Plus I can go full bore and detect “It broke at 290 lb” and elongated by xxx and here is the curve displaying the elongation, torque over time etc. We 3DP a lot and atm just kinda guess on what should be strong enough. (we got 2 anycubic Chirons)

Plus the kids want to build all kinda stuff. So Some very cheap, capable motor controllers that can do closed loop quadrature, limit switches and current sense and have a “follow the leader” mode would come in quite handy to put the Cims to good use.

Now we built this

https://pirringers.com/3dp/?p=36

It got about 14kg of HIPS (<$10/kg) in it and some donated (<$100) aluminum in it and some of it is just on there to bring up the weight as we wanted to weigh at least 100 lb.

And never got to use it due to COVID. Just to show where everything will go to. So RN we need a bunch of cheap capable motor controllers for those off season projects that hopefully will make us a better team in the future

Did some more research. Will for now forgo the fancy stuff with attaching an class method to an interrupt and just code it manually. Will change and maybe hardcode the pins and use some PCINT to process them as an interrupt. Like explained her (and other places)

The PCINT interrupts also work on output pins so I can enable one for the PWM pins. I probably do a wrapper class to hardcode them at least for now for Motor 1 and 2 on an uno/nano and motor 1-6ish (depending on tests if it can handle it processing wise) on a mega. Furthermore I will try to tie the IS lines together it will definitely cut the CS from a 0-5V range down to a 0-2.5 V range so meaning the Amp accuracy should drop from 1024 to 512 increments but I think we can live with that.

So that means arranging pins in a manner that all relevant input pin (2 for quadrature enc and 2 for LS) are mapped to the apropriate register. As we also read the output of the PWM we can trigger that on either high or low to sync reading the current. (probably best on high) . Goal will be to have all the pins for the same motor on the same port so to only need 1 PCINT per motor

So until my skills in writing code for arduino improve. RN there will be the class and the ISRs that go along in the Library and it will be up to the programmer to remember to call the apropriate functions from loop() and not use the ISRs used by the system nor mess with the timers associated with the PWM.

But this way some of the issues can be resolve. CS will be read when the PWM signal goes high - there is still a case to deal with that if it is high all the time (analogWrite(pwmpin, 255) . The limitswitches will cause an interrupt and so do not need be polled all the time and the same for the quadrature signal. It should be ok to only interrupt on A going High and then read the direction from the B input and increament/decrement the counter and stop the motor if applicable. This should limit the Max quadrature frequency on a nano/Uno to about 3 khz for 2 motors and on a Mega if one uses a mega with 6 motors that would drop to about 1khz That means for a CIM if the encoder is mounted to the shaft directely to about 12-13 pulses per rev maximun. Which means probably not every motor controlled by a mega can have a quadrature encoder. If they are of the gearmotor style probably more than 2 per 16mhz chip would not be safe and not more than 3 of the CIM encoder style. But tests will show that.