2DOF harness tensionner with Fly PTmover

Hi!

My cockpit is static, I've build a pressure gSeat with bladders and RC servo.
I wanted to increase immersion by a harness tensionner.

I'd already tested a static harness tensionner on a 2 DOF plateform, and the feeling was great.
As my rig is static, I'll have to actuate the harness but the advantage is that I can make a 2 DOF tensionner.

principle:
2 DOF harness -> the strength on the right shoulder and left shoulder will be different

both will react along Surge (longitudinal acceleration)
and Sway (lateral acceleration) will tight one shoulder or the other (depending on left turn or right turn)
(maybe later add some heave information?)

harness : 5 points
the 5th will prevent the harness to move up, this will give actual tension (vs movement)!

prefer larger harness 3" (vs only 2")

actuators:
RC servos 35kg.cm (5V to 8,3V)
PSU @7,3V

arduino:
code for 4 servos as I want to combine the harness and the gSeat pressure bladders also RC servo driven.

software:
FlyPT mover https://www.xsimulator.net/community/faq/flypt-mover.29/category

1607507030563.png


1607507067271.png


Here is a video showing step by step how I drive the 2 DOF belt with Fly PTmover:

The strength from 35kg.cm servo is enough.
Power up the servo, sit down, thight the belt as you wish, and start the sim. If you tight the belt before powering up the servos, they are loose and they could be pushed out of their range...

The only drawback, in my opinion is the noise of the servos: they are whinning...

here some infos gathered in this FAQ https://www.xsimulator.net/community/faq/harness-tensioner-simulation.361/

► shopping list
"HV high torque servo motor Robot servo 35kg RDS3235 Metal gear Coreless motor digital servo arduino servo for Robotic DIY"
17€
I chose 270° range
You'll need a dedicated power supply (5V slower to 7,4V fastest)

Speed: 0.13sec/60 degree at(5v)
0.12sec/60 degree at(6v)
0.11sec/60 degree at(7.4v)

Torque: 29kg.cm.at(5v) -1.9A
32kg.cm.at(6v) -2.1A
35kg.cm.at(7.4v) -2.3A

or stronger but unecessary in my opinion
60kgcm 24€
https://www.aliexpress.com/item/4000055027119.html

speed is voltage related
torque is current related!

1/ choose speed AKA voltage
2/ check the spec which gives you the current at chosen voltage
3/ buy your PSU ;-)

if you choose 7,4V PSU, verify it'll be able to deliver up to 2.3A in order to give full torque (add a BIG margin ;-) )
https://fr.aliexpress.com/item/32823922664.html
11€ 7V 10A


here is my ball bearing support (12€ for 2 supports)
they are made of:
P000 https://www.aliexpress.com/item/32833812473.html
Zinc Alloy Diameter Bore Ball Bearing Pillow Block Mounted Support
they allow a big static disalignment as the bearing is mounted like a joint articulation :)

and 200mm Ø10 linear shaft Cylinder Chrome Plated Liner Rods
https://www.aliexpress.com/item/4001294745058.html

roller-jpg.434449


ball-bearing-harness-2-jpg.439581


ball-bearing-harness-1-jpg.439582


► budget:
2x 17€ for 35 kg.cm servo
11€ for 7V 10A PSU
(maybe consider a 12V 10A PSU + an Adjustable Power Module Constant Current 5A)
12€ for bearing rollers
15€ any arduino with a USB port (an original to support the community or a clone)

50€ for a used 3" width 5 points harness
total = 120€ all included



arduino code (for up to 4 servos)
C++:
// Multi Direct
// -> 4 servos
// <255><LeftBelt><127><127><RightBelt>
// Rig : Bit output -> 8 bits
// avec inversion
// PT Mover envoie de 0 à 255 par axe

/*Mover = output "Binary" et "10bits"
Arduino = Byte Data[2]
Data[0] = Serial.read();
Data[1] = Serial.read();
result = (Data[0] * 256 + Data[1]);

OU

Mover = output "Binary" et "8bits"
Arduino = Byte Data
Data = Serial.read(); on obtient directement le résultat*/

#include <Servo.h>  // local library "Servo.h" vs library partagée <Servo.h>

const byte nbServos = 4;

// create servo objects to control any servo
Servo myServo[nbServos];
const byte servoPin[nbServos] = {2, 3, 4, 5};  // pins digitales (pas forcément ~pwm)
const byte inversion[nbServos] = {1, 1, 0, 0 }; // paramètre à changer si un servo part le mauvais sens
int OldSerialValue[nbServos] = {0, 0, 0, 0};
int NewSerialValue[nbServos] = {0, 0, 0, 0};

// servo span:
int servoHomeDegres[nbServos] = { 0, 0, 0, 0}; //sera mis à jour avec la mesure de pression initiale
int servoMaxDegres[nbServos] = { 90, 90, 90, 90}; // cuisseG, cuisseD, côtéG, côtéD
int servoPositionTarget[nbServos] = {0, 0, 0, 0};

const byte deadZone = 0;

// =======================================
// Variables for info received from serial
// =======================================
int bufferPrevious = 0;      // To hold previous read fom serial command
int bufferCurrent = 0;       // To hold current read fom serial command
int bufferCount = 0;         // To hold current position in bufferCommand array
// byte bufferCommand[2*nbServos] = {0};  // (*2 if 10 bits) To hold received info from serial
int bufferCommand[4] = {0};  // To hold received info from serial

void setup()
{
  Serial.begin(115200); // opens serial port at specified baud rate

  // attach the Servos to the pins
  for (byte i = 0; i < nbServos; i++) {
    // pinMode(servoPin[i], OUTPUT); // done within the library
    myServo[i].attach(servoPin[i]);  // attaches the servo on servoPin pin
    }
  // move the servos to signal startup
  MoveAllServos255toDegres(125); // mi-course
  delay(1000);
  // send all servos to home
  MoveAllServos255toDegres(0);
}

void loop()
{
  // SerialValues contain the last order received (if there is no newer received, the last is kept)

  if (Serial.available())
  {
    bufferPrevious = bufferCurrent; // Store previous byte
    bufferCurrent = Serial.read(); // Get the new byte
    bufferCommand[bufferCount] = bufferCurrent; // Put the new byte in the array
    bufferCount++; // Change to next position in the array
    if (bufferCurrent == 255) bufferCount = 0; // one 255 is the start of the position info
    if (bufferCount == nbServos) //si 8 bits, nbServos // si 10 bits nbServos*2
      //Having reach buffer count, means we have the new positions and that we can update the aimed position
    {
      for (byte i = 0; i < nbServos; i++) {
        NewSerialValue[i] = bufferCommand[i];
        //NewSerialValue[i]= (bufferCommand[i*2] * 256) + bufferCommand[i*2+1]; // si 10 bits
      }
      bufferCount = 0;
    }
  }
  // Update orders sent to motor driver
  for (byte i = 0; i < nbServos; i++) {
    if (abs(OldSerialValue[i] - NewSerialValue[i]) > deadZone) {
      if (inversion[i] == 1)
      {
        envoiServoConsigne255toDegres(i, (255 - NewSerialValue[i]));
      }
      else
      {
        envoiServoConsigne255toDegres(i, NewSerialValue[i]);
      }
      OldSerialValue[i] = NewSerialValue[i];
    }
  }
}

void envoiServoConsigne255toDegres(byte servoID, int val )
{
  byte targetDegres;
  val = constrain(val, 0, 255); // constrain coupe au dessus et en dessous : écrêtage et pas mise à l'échelle (comme map)
  // sécurité pour éviter les cas où Simtools enverrait du négatif ou au-delà de 255
  targetDegres = map(val, 0, 255, servoHomeDegres[servoID], servoMaxDegres[servoID]);
  //  map(value, fromLow, fromHigh, toLow, toHigh)
  myServo[servoID].write(targetDegres);              // tell servo to go to position in variable : in steps of 1 degree
  // servo.write(angle)  -> angle: the value to write to the servo, from 0 to 180
}

void MoveAllServos255toDegres( int target)
{
  // send all servos to home
  for (byte i = 0; i < nbServos; i++) {
    envoiServoConsigne255toDegres(i, target);
  }
}

here is the setup:
setup 2DOF harness.png


and the file itself: replace .txt extension by .Mover extension
 

Attachments

  • 4Dof_Belt_255_multiDirect_v6bALPHA.txt
    94.9 KB · Views: 454
Last edited:
much less complicated
Things easy for others are often less so for me, particularly if hand-eye coordination is wanted.
Parts of SimHub (e.g. overlays and plugin development) are still opaque to me.
I think there is a protection
Sadly, that version does not report current draw,
which is valuable for monitoring servo loads
Stay near the power disconnect when trying it!
 
Upvote 0
I just tried it and didn't burn my regulator.
On the other hand, after 15 min, I burnt down one of the 2 engines.
When I open it, I see that the "MT9926" circuit is burnt.
I hesitate between replacing this component, replacing the motor, switching to 60kg motors or switching to the Wotever solution ...
 
Upvote 0
the Wotever solution
@illiac4 found motors that could be suitable for direct drive:

I like small compact design. Maybe using those small motors https://fr.aliexpress.com/item/32881467792.html with pwm and pot would do the trick. Those motors are strong and also can be fused.
Maybe also Monster Motor driver would do the trick.
We have used the same motors in this project https://github.com/aenniw/ARDUINO/tree/master/skarsta
For harness tensioning, exact control of motion is not needed, just control of torque,
which can be done by PWM drive to motors without feedback.
If I were going to redesign, that would be my choice,
perhaps using @illiac4's motors.

Meanwhile, 35kg servos are working OK for me:
  • first, break them in with no load,
    • so that their internal friction relaxes,
    • avoiding subsequent overheating
  • do not overtighten the harness
    • that is also useful for coordination with G seat
 
Upvote 0
I was lookin also a little bit and I think BTS7960 will be safe also for reverse direction generating an electricity like dinamo. Since they would run at around 12V the reverse voltage should not exceed 20V which is safe for those drivers.
Another thing that is problematic in motors is the reverse electricity causing power supply tripping. Also this can be solved easily with the diod. The diode will cause around 0,7v drop but with most power supplies it is possible to adjust with pot the output voltage. Here you can read more about: https://www.xsimulator.net/community/threads/power-supply-tripping.13110/
It is simple and cheap. I have used the same solution in my 2dof build and works great https://www.xsimulator.net/community/threads/simlab-gt2-to-2dof-conversion.13948/
As tensioners I thing the already suggested strings will work.
It could be very modular, small and cheap build. I could post a BOM list if someone think that it could be an interesting project.

So overall i think hardware wise everything should work but we will still need some kind of arduino code that will work ideally with simhub plugin for belts tensioner and 3d printed models (this will not be so hard).
 
Upvote 0
reverse electricity causing power supply tripping
Any motor driver with reversing capability should be robust against back emf;
my current-limited buck regulator from bulk supply into supercap has worked well
and should damp most spikes, protecting the power supply without resistors.

SimHub + Arduino code should take very minor modifications of that already used;
  • more tension by more pulse width
    • for servo position
    • for direct drive motor torque
      • zero pulse width should quickly release torque,
        perhaps no need for reverse
 
Upvote 0
It was not meant to protect the motor but power supply from tripping. Motors can only stall what would cause to raise the amperage which could melt the wire insulation inside the motor (but I doubt that this is the problem in this case. I had a problem when was building a Ikea desk with this motor but it was in a early stage of development. Here it was discussed and there are also pictures in dropbox https://github.com/aenniw/ARDUINO/issues/32). To protect from this you can use a simple fuse.
 
Last edited:
Upvote 0
Supercapacitor protects a power supply by acting as a short circuit for motor's inductive spikes,
then also providing peak start current.
For this application, motors would mostly be stalled, providing torque for tension,
with current limited by PWM duty cycle.
 
Upvote 0
RC servo RDS3235
Max. torque 35 kg.cm
no load speed 91 rpm
No Load Speed(RPM) : 200
No Load Current (mA) : ≤1100
Rated torque(kg.cm) : 27.0 Kg.cm
Rated Speed(RPM) : 120
Rated Current(A) : ≤6.0
Max. Torque : 90Kg.cm
stall Current(A) : 20

The specs look nice, thanks!
I think I could try one (approximately same range as 35kg servo) : I do not like the servo noise... and I would prefer torque control if achievable.
https://www.aliexpress.com/item/1005003294192755.html 13€ (store 94,7%)
Did you use them actually?

I have some motomonsters somewhere, I could change the code and use the current sense to drive the motor by torque... Hoping it would be sensitive enough, we wouldn't like to get some oscillations in the feeling.
 
Upvote 0
harness will not relax when motor will be stopped
I had considered that; code would have to briefly reverse motors to relax tensions.
This brief overdriving is also wanted for servos driving air bellows, to speed inflation/deflation of cushions.
Sourcing direct drive non-gear motors e.g. using fishline on small diameter reels would be better.
 
Upvote 0
Sourcing direct drive non-gear motors e.g. using fishline on small diameter reels would be better.
yeah, maybe this one?
17€
easy to wind a fishline on the long shaft and with this convenient hole

specs here https://handsontec.com/index.php/product/xd3420-dual-ball-bearing-long-life-dc-motor-3500rpm12v/
  • Motor Type: XD3420.
  • Low Noise Type: < 30dB.
  • Operating Voltage: 6~20Vdc. (Nominal 12Vdc)
  • No Load Speed: 3,500 RPM @ 12V.
  • Rated current: 400mA @ 12V.
  • Rated Torque: 2Kg.cm.
  • Long Life: 3,000 Hours Continuous operation.
  • Replaceable Carbon Brush.
  • Overall Size: 97 x Ø51 mm.
  • Shaft: Full Round Type Ø8mm.
  • Weight: 500g
with a 8mm shaft, the torque would give a 5 kg force. Probably to weak but with a torque driven system, it could provide a better feeeling.

I didn't measure the actual force of the 35kgf RC servo... that would be interesting to know :)

XD3420.png

with 6.35mm shaft
 
Last edited:
Upvote 0
20A drivers are not cheap or reliable sadly
Here are BTS7960 drivers, nominally rated at 43A for US$16: https://www.amazon.com/dp/B07TFB22H5

3741-High-power-Motore-drive-Modulo-Smart-car-BTS7960-43A-limit-control-semiconductor-refrigeration-drive.jpg

They are fairly well documented: https://electropeak.com/learn/interfacing-bts7960-43a-high-power-motor-driver-module-with-arduino/
A single unit can drive 2 motors without reversing.

Here is data for scooter motors:
ZBdjpUecHVhGhRT2PKtmCvsTbPvkehl3zg.png

Here are 250W electric scooter motors with 8mm diameter shaft for < US$30

71aZ-9HlhdL._SL1500_.jpg


1.6N.m = 16kg.cm; 4mm shaft radius -> 40kg,
so adequate tension with max rated torque @ 25A.
2cm tensioning is less than a single 8mm shaft revolution;
responsiveness to telemetry changes should be quite good.
Tying a loop of strong fishline around the nut,
then running line between sprocket teeth and tying a tight loop to the shaft
will secure it for rotation, then tie the other end to harness bracket.
 
Last edited:
Upvote 0
Here are BTS7960 drivers, nominally rated at 43A for US$16: https://www.amazon.com/dp/B07TFB22H5

3741-High-power-Motore-drive-Modulo-Smart-car-BTS7960-43A-limit-control-semiconductor-refrigeration-drive.jpg

They are fairly well documented: https://electropeak.com/learn/interfacing-bts7960-43a-high-power-motor-driver-module-with-arduino/
A single unit can drive 2 motors without reversing.

Here is data for scooter motors:
ZBdjpUecHVhGhRT2PKtmCvsTbPvkehl3zg.png

Here are 250W electric scooter motors with 8mm diameter shaft for US$35

71aZ-9HlhdL._SL1500_.jpg


1.6N.m = 16kg.cm; 4mm shaft radius -> 40kg,
so adequate tension with max rated torque @ 25A.
2cm tensioning is less than a single 8mm shaft revolution;
responsiveness to telemetry changes should be quite good.
Tying a loop of strong fishline around the nut,
then running line between sprocket teeth and tying a tight loop to the shaft
will secure it for rotation, then tie the other end to harness bracket.
Thanks for this info.
After doing a bit more research I decided to try it out and it works great. I wasn't sure if it would be enough power compared to my 65kg-cm servos, but wrapping the wire (100lb stainless steel picture frame line instead of fishing line) around the motor shaft is creating more than enough torque.
So many good things to say about this, from the instant torque, to not worrying about servo travel, and especially the silence.
Originally I wanted to control it with blek2char PWM, but after looking into it, Lebois' method of using ShakeIt Motors with Arduino Fan PWM was a lot easier. I also modified the PWM frequency to be under 20kHz to reduce motor driver heat and hopefully gain some efficiency.

One downside is power draw. Even though the motors are 250W, they easily draw 300-400W each while stalled. So for now I'm dedicating two of my bass shaker PSUs to tensioner duty as there is too much EMI to run shaker amps off of the same PSU as a motor.

I'm still working on the ShakeIt effects for this, but so far it feels really good. I'm using 1-50m/s^2 for the range which should be enough to rarely run into clipping issues (even with surge and sway combined) excepting the occasional collision.
 

Attachments

  • 20220531.jpg
    20220531.jpg
    128.4 KB · Views: 391
Upvote 0
it works great
I love it when a notion works out.
I want to believe that 12V should suffice,
having briefly tested one of these motors with a car battery.
I would like to use the supercapacitor trick to supply peak current,
but have yet to sort a scheme for cheaply and efficiently
limiting 12V supply current to 25A or so.
PWM coding progress stalled when trying to port blek2char.ino
to ESP32-S3, for which Arduino support is only partially baked,
so have drifted off to non-Sim projects.

When will you post the obligatory video?
 
Last edited:
Upvote 0
instant torque
Powered from a 12V auto battery,
250W 24V motor response is also quite instantaneous,
presumably thanks to that battery's low internal resistance.
Equivalent low source impedance probably wants
a supercapacitor across a 12V supply,
but few 12VDC supplies tolerate current surges
for initially charging supercaps.
BTS7960 current limiting is designed for inductive (motor) loads;
to initially charge a supercap would want it in series with a motor,
then a DPDT relay switches that supercap to be in parallel with supply
when fully charged.

Motor responsiveness could also be improved by digital predistortion.
For example, when signaling an Arduino to change from 50 to 70% PWM,
briefly set e.g. 80% PWM, then 70%.
Similarly, reducing from 70 to 50% could briefly set 40%, then 50%.
 
Last edited:
Upvote 0
Thanks @blekenbleu and @RacingMat for your great sharing. Simhub is a good software to use and it has a lot of great features. However vibration, shakers is not my intension. I were more into motions, but don't want to use simtools. I was looking into built-in + custom effect that were build into simhub, and able to move my seat a bit, eventhough it is just a one direction since simhub default effect were only one way driven direction for motors.
Then i was looking for their SHCustomProtocol.h code and try to use some to read feedback from the protocol binding however with only minor success. Only some of the times the motor moves when i use this method. Might need to look further on next time since on this code i might be able to read the analog signal for the pot, thus control the position of the motor base on serial/racing feedback.
Any other thought would be nice to hear from you guys.
 
Upvote 0
Back
Top