I haven't found much discussion of Shimano's electric shifting on here, yet it seems very relevant. I know there are a couple commercially available ebikes that shift gears automatically so rider can pedal at a constant cadence no matter what the motor speed, but Di2 seems to offer an opportunity for more DiY experimentation while still leveraging the decades of deraileur development. Plus, the price is no longer so forbidding.
That's what I told mysef anyway, before buying an ultegra di2 build kit last week. Now that I'm ankle deep in the technical deets, I'm having second thoughts...
- My first thought was to hook up a decoder and watch the CAN messages go by. After all, using an OBD reader with my car was dead easy... But I have yet to find anyone who has done this with Di2 successfully. While the evidence that Di2 (only ultegra version, NOT dura ace) is based around the CAN bus is strong, and hooking up an o-scope to the system provided additional comfort, getting a clean enough connection to decode proved surprisingly tricky. Either a) I am a butter fingered fool, or b) Shimano is using something odd, like the GM single-wire version of CAN. Most likely, both.
- "If you fail, move up the stack and try again... " Shimano sells a PC interface box that allows you to connect via USB to your drivetrain, and throws in a simple app that can trigger the various components as well as update firmware etc. Disassembly is trivial and the objects/methods are fairly well structured. Below, for example, is the public method to SetGear (basically, checks if it's doing front or rear, issues appropriate command over wire, then waits for response code.)
Of course, instantiating all the state to get to the point where this function can be called is ... more elaborate.
Which is why I'm here. Has anyone already done this? (Either the CAN way or the PC/USB way)? Any tips would be most welcome.
Thanks,
s.
public static bool SetCurrentGear(byte[] settingsGear, int slotNo, string modelNo)
{
byte[] data = new byte[] { settingsGear[0], settingsGear[1], 0, 0 };
int num = -1;
int num2 = 0;
byte groupId = 0;
string commandName = null;
if (modelNo == "FD-6770")
{
groupId = 10;
commandName = "EXTM_FR_SFT_LV_SET";
}
else
{
groupId = 11;
commandName = "EXTM_RA_SFT_LV_SET";
}
do
{
EtubeDataLinksMain.Instance.SendUnitCommandData(groupId, 8, data, slotNo);
EtubeDataLinksLog.SendCommandLog(slotNo, commandName, data, new string[] { "gear" });
DateTime time = DateTime.Now.AddMilliseconds(3000.0);
while (true)
{
AbsSerialDataReceivedEventArgs args = EtubeDataLinksMain.Instance.WaitUnitCommand(groupId, 10);
if ((args != null) && (args.Result == SerialDataReceivedResult.Success))
{
if (args.ReceiveData[1] == 10)
{
EtubeDataLinksLog.CommunicationLog(slotNo, "CurrentGear = " + args.ReceiveData[2]);
if (args.ReceiveData[2] == settingsGear[0])
{
num = 0;
break;
}
num = -1;
}
else if (args.ReceiveData[1] == 11)
{
EtubeDataLinksLog.ReceiveErrorResponseLog(slotNo, commandName, args.ReceiveData);
return false;
}
}
if (DateTime.Now > time)
{
EtubeDataLinksLog.ReceiveTimeoutLog(slotNo, commandName);
break;
}
}
}
while ((num2++ < 2) && (num != 0));
return (num == 0);
}
That's what I told mysef anyway, before buying an ultegra di2 build kit last week. Now that I'm ankle deep in the technical deets, I'm having second thoughts...
- My first thought was to hook up a decoder and watch the CAN messages go by. After all, using an OBD reader with my car was dead easy... But I have yet to find anyone who has done this with Di2 successfully. While the evidence that Di2 (only ultegra version, NOT dura ace) is based around the CAN bus is strong, and hooking up an o-scope to the system provided additional comfort, getting a clean enough connection to decode proved surprisingly tricky. Either a) I am a butter fingered fool, or b) Shimano is using something odd, like the GM single-wire version of CAN. Most likely, both.
- "If you fail, move up the stack and try again... " Shimano sells a PC interface box that allows you to connect via USB to your drivetrain, and throws in a simple app that can trigger the various components as well as update firmware etc. Disassembly is trivial and the objects/methods are fairly well structured. Below, for example, is the public method to SetGear (basically, checks if it's doing front or rear, issues appropriate command over wire, then waits for response code.)
Of course, instantiating all the state to get to the point where this function can be called is ... more elaborate.
Which is why I'm here. Has anyone already done this? (Either the CAN way or the PC/USB way)? Any tips would be most welcome.
Thanks,
s.
public static bool SetCurrentGear(byte[] settingsGear, int slotNo, string modelNo)
{
byte[] data = new byte[] { settingsGear[0], settingsGear[1], 0, 0 };
int num = -1;
int num2 = 0;
byte groupId = 0;
string commandName = null;
if (modelNo == "FD-6770")
{
groupId = 10;
commandName = "EXTM_FR_SFT_LV_SET";
}
else
{
groupId = 11;
commandName = "EXTM_RA_SFT_LV_SET";
}
do
{
EtubeDataLinksMain.Instance.SendUnitCommandData(groupId, 8, data, slotNo);
EtubeDataLinksLog.SendCommandLog(slotNo, commandName, data, new string[] { "gear" });
DateTime time = DateTime.Now.AddMilliseconds(3000.0);
while (true)
{
AbsSerialDataReceivedEventArgs args = EtubeDataLinksMain.Instance.WaitUnitCommand(groupId, 10);
if ((args != null) && (args.Result == SerialDataReceivedResult.Success))
{
if (args.ReceiveData[1] == 10)
{
EtubeDataLinksLog.CommunicationLog(slotNo, "CurrentGear = " + args.ReceiveData[2]);
if (args.ReceiveData[2] == settingsGear[0])
{
num = 0;
break;
}
num = -1;
}
else if (args.ReceiveData[1] == 11)
{
EtubeDataLinksLog.ReceiveErrorResponseLog(slotNo, commandName, args.ReceiveData);
return false;
}
}
if (DateTime.Now > time)
{
EtubeDataLinksLog.ReceiveTimeoutLog(slotNo, commandName);
break;
}
}
}
while ((num2++ < 2) && (num != 0));
return (num == 0);
}