timmaxw / HitecDServo

Arduino library to program and control Hitec D-Series servos. (Not endorsed by Hitec.)
MIT License
5 stars 3 forks source link

Potential workaround that could be of interest #3

Open TTN- opened 1 month ago

TTN- commented 1 month ago

https://www.eevblog.com/forum/mechanical-engineering/programming-hitec-d485-rc-servo-settings/

If link goes dead. Archived copy: https://web.archive.org/web/20240511095348/https://www.eevblog.com/forum/mechanical-engineering/programming-hitec-d485-rc-servo-settings/

timmaxw commented 1 month ago

This is very cool, thanks for the link! I had no idea there was a secret menu in the programmer GUI.

TTN- commented 1 month ago

There's a few potential pathways here. I'm hoping the driver component can be modified so that the arduino can be used directly for coms (somehow inverting RX and TX as required). I have FTDI dongles but they are all clones so won't talk to FTProg to invert TX and RX. This is probably the lowest effort route and best user experience pathway? The source for the driver adapter is provided in the post, but have never worked on anything like that.

Another avenue could be to decompile the program and learn more about the protocol. mmm.

timmaxw commented 1 month ago

I'm hoping the driver component can be modified so that the arduino can be used directly for coms (somehow inverting RX and TX as required).

Maybe the Arduino could do the inversion?

Not sure if that would work?

best user experience pathway

I had a lot of trouble getting the GUI to run on Windows 10 (see https://github.com/timmaxw/HitecDServo/blob/main/extras/DPC11Notes.md), and it doesn't work at all on Linux; so personally I prefer solutions that bypass the GUI entirely.

TTN- commented 1 month ago

It's messed up when a vendor instructs Disable Windows driver signature verification. It's there for a reason.

What hell lets try it. Installing drivers now.. breadboard wired, and arduino ready to go.

#define nRX 2 // connect this to servo PWM pin
#define nTX 3 //connect to nRX pin via 1K resistor

#define RX 4 //connect FTDI RX to this pin
#define TX 5 //connect FTDI TX to this pin

void setup() {
  // put your setup code here, to run once:
  pinMode(TX, INPUT);
  pinMode(nTX, OUTPUT);

  pinMode(nRX, INPUT);
  pinMode(RX, OUTPUT);

}

void loop() {
  // put your main code here, to run repeatedly:
  digitalWrite(nTX, !digitalRead(TX));
  digitalWrite(RX, !digitalRead(nRX));
}

The FTDI adapter is one like this. FT232RL-USB-TO-TTL-Converter-Pinout

It's showing up as USB Serial Port (COM9. Guess now the question is how to get the right SiLabs driver installed, and then locate the .dll as per forum post. Any tips on that front?

TTN- commented 1 month ago

Ok looks like I forgot to install the driver that came in the same zip as the DPC-11 application.

the DLL to be replaced lives in that location. path C:\Program Files (x86)\Hitecrcd\DPC-11

TTN- commented 1 month ago

image

But we get some errors, I'm guessing new DPC-11 app requestst stuff that breaks this mod:

image

So lets get the old one, not from the forum. Note download link for the latest version is https://hitecrcd.com/uploads/DPC-11_Install__2020_12_09_01-2.9.9.zip

I bet that the older one is still in the uploads folder, so lets try that, picking the name from the forum post: https://hitecrcd.com/uploads/DPC-11_Setup_20180214_V2.9.1.zip

Which works. After installing that we are in! It sees the FTDI as adapter, but then gives up when we try to connect to the servo. It can't find it, so am hopeful the issue is something silly with my wiring or arduino sketch.

I'll go and double check everything but it's tantalizingly close!

TTN- commented 1 month ago

Btw SHA256 checksum of DPC-11 software ZIP file on the forum post and official site match.

TTN- commented 1 month ago

I realize the UI sucks, but I just want a solution with the least effort.

The wiring all looks ok. Not sure what issue is. Maybe the arduino is too slow. Got the dinosaur old scope on it, it's inverting correctly.

TTN- commented 1 month ago

The arduino code was too slow. Got chat GPT to whip me up some direct port manipulation and it's connected:

// D2 to PWM pin of servo
// D3 jumpered to D2 via 1K resistor
// D4 to RX pin of FTDI adapter
// D5 to TX pin of FTDI
//don't forget to connect the grounds between arduino, servo, and FTDI adapter

void setup() {
  // Set D2 and D5 as inputs
  DDRD &= ~((1 << DDD2) | (1 << DDD5));

  // Set D3 and D4 as outputs
  DDRD |= (1 << DDD3) | (1 << DDD4);
}

void loop() {
  // Read the state of D2 and invert it, then write to D4
  if (PIND & (1 << PIND2)) {
    // D2 is HIGH, set D4 LOW
    PORTD &= ~(1 << PORTD4);
  } else {
    // D2 is LOW, set D4 HIGH
    PORTD |= (1 << PORTD4);
  }

  // Read the state of D5 and invert it, then write to D3
  if (PIND & (1 << PIND5)) {
    // D5 is HIGH, set D3 LOW
    PORTD &= ~(1 << PORTD3);
  } else {
    // D5 is LOW, set D3 HIGH
    PORTD |= (1 << PORTD3);
  }
}

image

Fuck yes.

TTN- commented 1 month ago

I'll do a logic analyzer dump shortly. Any preference for where to connect the logic analyzer? On the FTDI side or servo side past the signal inversion?

Is there any programming actions that would be of particular interest?

timmaxw commented 1 month ago

Hooray, you got it working! If you do a complete write-up of exactly what you did, I'll link it from the main page.

A logic analyzer dump would be great! In particular, I'd love to see:

If you can provide those, that would be super helpful!

TTN- commented 1 month ago

How to Emulate DCP-11 programmer using clone FTDI adapter and Arduino Nano

Motivation: With a DPC-11 programmer you can reprogram the endpoints of your servo to be whatever you want. The range of motion can be increased to 180 degrees. Fail safe positions can be set, overload protection settings, dead band, speed, and more..

Let's get started.

Flash your arduino with the following code (just about any arduino will work):

void setup() {
  // Set D2 and D5 as inputs
  DDRD &= ~((1 << DDD2) | (1 << DDD5));

  // Set D3 and D4 as outputs
  DDRD |= (1 << DDD3) | (1 << DDD4);
}

void loop() {
  // Read the state of D2 and invert it, then write to D4
  if (PIND & (1 << PIND2)) {
    // D2 is HIGH, set D4 LOW
    PORTD &= ~(1 << PORTD4);
  } else {
    // D2 is LOW, set D4 HIGH
    PORTD |= (1 << PORTD4);
  }

  // Read the state of D5 and invert it, then write to D3
  if (PIND & (1 << PIND5)) {
    // D5 is HIGH, set D3 LOW
    PORTD &= ~(1 << PORTD3);
  } else {
    // D5 is LOW, set D3 HIGH
    PORTD |= (1 << PORTD3);
  }
}

Using a breadboard, make the following connections:

  1. Connect the servo to an external power source. I used 5V supplied by an ESC.
  2. Connect D2 to PWM pin of servo
  3. Jumper D2 to D3 with a 1K ohm resistor
  4. Connect D4 to the RX pin of the FTDI adapter
  5. Connect D5 to the TX pin of the FTDI adapter
  6. Connect Ground on the power supply of the servo, to the arduino, and to the FTDI adapter.
  7. Connect the 5V ouput from the FTDI adapter to the VIN pin on the arduino.

Here is my setup:

IMG_20240512_095822464

Now that's the hardware all done. Let's look at software:

You'll need to follow the installation instructions for the DPC-11 software here: https://hitecrcd.com/products/servos/programmers/dpc-11/product

But! Use the older version of the software: https://hitecrcd.com/uploads/DPC-11_Setup_20180214_V2.9.1.zip The newer one makes requests that the adapter layer doesn't know to translate.

Key steps of the installation is:

  1. Download the zip file.
  2. Unzip the file.
  3. Open the folder, install the servo adjustment program: DPC-11_Setup.msi
  4. Choose the "install for everyone" option as part of the installation steps.
  5. Then go into the HITECRCD_DPC-11 Driver Installer folder which is in the zip file you just downloaded, and install the driver: HITECRCD_DPC-11 Driver Installer.exe
  6. Once that's done, go to your PC's desktop. Right click on the shortcut DPC-11, click Open File Location
  7. Unzip this file SiUSBXp.zip and copy the SiUSBXp.dll into the folder that you just opened. For me this was here: C:\Program Files (x86)\Hitecrcd\DPC-11
  8. Choose "Copy and Replace" option when prompted.
  9. Power up your servo, connect the FTDI adapter to your PC, launch the DPC-11 program from the desktop shortcut, and it should show up as connected:

image

Click on the series of servo you have, for me I have a D645MW servo, so I click the D-series.

Next screen you get is this:

image

Click Connect. If all is well, it will connect, and you can make all changes as if you had a DPC-11 programmer!

image

User manual for full details on how to use the programmer can be found here: 411_DPC11_ManualV3.pdf

Source files for the DLL are here, it is what makes the FTDI adapter be recognized as the DPC-11 programmer: src.zip

Credit for this mod goes to user rtv over at the eevblog forums: https://www.eevblog.com/forum/mechanical-engineering/programming-hitec-d485-rc-servo-settings/

TTN- commented 1 month ago

Pulseview capture of parameter refresh, 1MHz, connected to RX and TX lines of FTDI unit: Hited D645MW DPC-11 RX-TX line capture during parameter refresh.zip

Let me know if you need anything else over the course of the coming week. I'll leave this assembled here on my desk in case we need it again. :)

TTN- commented 1 month ago

Here is some data:

tx data.csv rx data.csv

Pulseview's decoder export options are a bit limited unfortunately but I hope that's helpful.

Maybe have a look at installing pulseview and applying the UART decoder, might be an easier way to view it image

image

timmaxw commented 1 month ago

Thanks for the writeup! I've copied it into a Github Gist here https://gist.github.com/timmaxw/11b01f5703a1bc9f470ff810f17f3498 and I've linked it from the main page at https://github.com/timmaxw/HitecDServo.

I'll take a look at these logic analyzer captures and see if I can figure out what's going on...

timmaxw commented 1 month ago

I installed Pulseview and looked at the logic analyzer captures. The D645MW protocol looks basically identical to the D485HW protocol; I don't see anything that would explain why the HitecDServo library didn't work.

I'm curious to keep debugging this! If you want to keep helping, here are some other ideas to try:

TTN- commented 1 month ago

Nice work posting the instructions!

Patch applied. 4.5V measured on 5V from arduino, so ran with 1K pullup. Result:

18:40:09.254 -> readRawRegister() reg=0x0 const0x69=0xFFFFFF9A mystery=0x69 reg2=0x0 low=0x2 high=0x55 checksum=0x0
18:40:09.254 -> Error: Corrupt response from servo.

Run again, 2K pullup:

18:41:58.235 -> readRawRegister() reg=0x0 const0x69=0xFFFFFF9A mystery=0x69 reg2=0x0 low=0x2 high=0x55 checksum=0x0
18:41:58.235 -> Error: Corrupt response from servo.

Pulseview analyzer log of pin D2 and 2K pullup: D2 log - patched lib.zip

This was running the Example 3 - read settings sketch.

timmaxw commented 1 month ago

Thanks! I think I might see the problem... what happens if you apply this change?

TTN- commented 1 month ago

More than before :)

06:36:36.283 -> readRawRegister() reg=0x0 const0x69=0x69 mystery=0x0 reg2=0x0 low=0x55 high=0x87 checksum=0x0
06:36:36.283 -> readRawRegister() reg=0xB2 const0x69=0x69 mystery=0x0 reg2=0xB2 low=0x22 high=0x0 checksum=0xB2
06:36:36.330 -> readRawRegister() reg=0xB0 const0x69=0x69 mystery=0x0 reg2=0xB0 low=0x4D high=0x3F checksum=0xB0
06:36:36.330 -> readRawRegister() reg=0xC2 const0x69=0x69 mystery=0x0 reg2=0xC2 low=0x13 high=0x20 checksum=0xC2
06:36:36.376 -> readRawRegister() reg=0x32 const0x69=0x69 mystery=0x0 reg2=0x32 low=0x0 high=0x0 checksum=0x32
06:36:36.376 -> readRawRegister() reg=0x5E const0x69=0x69 mystery=0x0 reg2=0x5E low=0x0 high=0x0 checksum=0x5E
06:36:36.423 -> readRawRegister() reg=0x54 const0x69=0x69 mystery=0x0 reg2=0x54 low=0xFF high=0xF checksum=0x54
06:36:36.423 -> readRawRegister() reg=0x4E const0x69=0x69 mystery=0x0 reg2=0x4E low=0x1 high=0x0 checksum=0x4E
06:36:36.470 -> readRawRegister() reg=0x66 const0x69=0x69 mystery=0x0 reg2=0x66 low=0x0 high=0x0 checksum=0x66
06:36:36.517 -> readRawRegister() reg=0x68 const0x69=0x69 mystery=0x0 reg2=0x68 low=0x0 high=0x0 checksum=0x68
06:36:36.517 -> Error: Confusing response from servo.

D2 log - patched lib 2.zip

We do have a compiler warning of overflow:

HitecDServo-main\examples\Example3_ReadSettings\HitecDServo.cpp: In member function 'int HitecDServo::readByte()':
HitecDServo-main\examples\Example3_ReadSettings\HitecDServo.cpp:606:38: warning: overflow in implicit constant conversion [-Woverflow]
   int timeoutCounter = F_CPU * 0.050 / 10;
TTN- commented 1 month ago

Changing the line to int32_t timeoutCounter = F_CPU * 0.050 / 10; to avoid the overflow we get the same thing:

06:43:41.104 -> readRawRegister() reg=0x0 const0x69=0x69 mystery=0x0 reg2=0x0 low=0x55 high=0x87 checksum=0x0
06:43:41.104 -> readRawRegister() reg=0xB2 const0x69=0x69 mystery=0x0 reg2=0xB2 low=0x22 high=0x0 checksum=0xB2
06:43:41.151 -> readRawRegister() reg=0xB0 const0x69=0x69 mystery=0x0 reg2=0xB0 low=0x4D high=0x3F checksum=0xB0
06:43:41.197 -> readRawRegister() reg=0xC2 const0x69=0x69 mystery=0x0 reg2=0xC2 low=0x13 high=0x20 checksum=0xC2
06:43:41.197 -> readRawRegister() reg=0x32 const0x69=0x69 mystery=0x0 reg2=0x32 low=0x0 high=0x0 checksum=0x32
06:43:41.243 -> readRawRegister() reg=0x5E const0x69=0x69 mystery=0x0 reg2=0x5E low=0x0 high=0x0 checksum=0x5E
06:43:41.243 -> readRawRegister() reg=0x54 const0x69=0x69 mystery=0x0 reg2=0x54 low=0xFF high=0xF checksum=0x54
06:43:41.291 -> readRawRegister() reg=0x4E const0x69=0x69 mystery=0x0 reg2=0x4E low=0x1 high=0x0 checksum=0x4E
06:43:41.291 -> readRawRegister() reg=0x66 const0x69=0x69 mystery=0x0 reg2=0x66 low=0x0 high=0x0 checksum=0x66
06:43:41.337 -> readRawRegister() reg=0x68 const0x69=0x69 mystery=0x0 reg2=0x68 low=0x0 high=0x0 checksum=0x68
06:43:41.337 -> Error: Confusing response from servo.
timmaxw commented 1 month ago

Good catch on the overflow! I hadn't noticed that.

Seems like the problem is that the D645MW handles deadband settings differently than the D485HW does. The deadband is controlled by three registers, which I arbitrarily labeled as DEADBAND_1, DEADBAND_2, and DEADBAND_3. On the D485HW they act as follows:

/* DEADBAND_1, DEADBAND_2, and DEADBAND_3 together control the servo deadband.
- If deadband == 1, then DEADBAND_1=1; DEADBAND_2=5; and DEADBAND_3=11. This is
  the default setting.
- If deadband > 1, then:
  - DEADBAND_1 = 4*deadband-4
  - DEADBAND_2 = 4*deadband
  - DEADBAND_3 = 4*deadband+6 */
#define HD_REG_DEADBAND_1 0x4E
#define HD_REG_DEADBAND_2 0x66
#define HD_REG_DEADBAND_3 0x68

Your D645MW is reporting DEADBAND_1=1, DEADBAND_2=0, DEADBAND_3=0. The HitecDServo library is trying to translate this back into a "deadband setting" between 1 and 10, but it doesn't expect to see DEADBAND_2=0 or DEADBAND_3=0, so it reports "Error: Confusing response from servo."

As a short-term workaround, you could comment out this piece of code so it just skips reading the deadband: https://github.com/timmaxw/HitecDServo/blob/main/src/HitecDServo.cpp#L163-L182

The long-term solution would be to use the Hitec official GUI to set the deadband to various values, and use the logic analyzer to snoop on what it's setting the three deadband registers to. The serial protocol is pretty simple to decode: https://github.com/timmaxw/HitecDServo/blob/main/src/HitecDServoInternal.h#L30-L40 Then the HitecDServo.cpp code could be updated to also support the D645MW.

TTN- commented 1 month ago

Sorry for the delay here crazy week... I'll try grab individual captures of setting every setting of the servo and post it here early next week when I can.

Would be nice to be able to adjust servos later without the hitec software, and better still, without risking giving my computer aids with that DLL file. Kinda feel like reinstalling my PC now 🤔

TTN- commented 1 month ago

The long-term solution would be to use the Hitec official GUI to set the deadband to various values, and use the logic analyzer to snoop on what it's setting the three deadband registers to.

I'll take that a step further, capture setting ALL settings. You know, in case it's useful later.

I've just gone through the interface, setting / unsetting every feature split into separate captures, organized into folders in the ZIP file: D645MW FTDI uninverted captures.zip

Notes: To set Sensitivity Ratio the Smart Sense setting must be disabled (after all, Smart Sense, is basically some form of Sensitivity Ratio auto adjust).

Setting and opening ID's seems to be broken. When trying to a servo with ID 2, it just gets stuck repeatedly talking to the servo. But if ID 1 or 3 is set, nothing is sent. At one point I managed to have the program become unresponsive.

TTN- commented 1 month ago

At some stage I'll have a look at updating the code to match the captures but might be a while.

Tim I really appreciate the effort you've put into this despite not even owning a D645MW! Much appreciated mate :)

timmaxw commented 1 month ago

Thanks, this is great!

I think I figured out what's going on with the deadband, and I've pushed an updated version of the library (version 1.0.1). When you have some free time, give it another try and let me know if it works now? :)

TTN- commented 1 month ago

Thank you kindly! It would be my pleasure. Expect an update in 24hrs or so.

TTN- commented 1 month ago

Fantastic, Example3_ReadSettings is dumping info:

19:17:55.207 -> id=3
19:17:55.207 -> counterclockwise=1
19:17:55.207 -> speed=100
19:17:55.207 -> deadband=1
19:17:55.207 -> softStart=20
19:17:55.207 -> rangeLeftAPV=2322
19:17:55.207 -> rangeRightAPV=16324
19:17:55.253 -> rangeCenterAPV=8785
19:17:55.253 -> failSafe=0
19:17:55.253 -> failSafeLimp=0
19:17:55.253 -> powerLimit=100
19:17:55.253 -> overloadProtection=100
19:17:55.253 -> smartSense=1
19:17:55.253 -> sensitivityRatio=4095

I had a go with the programmer sketch but registers look outdated atm.

timmaxw commented 1 month ago

Awesome!

I had a go with the programmer sketch but registers look outdated atm.

What do you mean?