Bionx controller options?

jocoman

1 W
Joined
Sep 3, 2010
Messages
56
Probably near impossible, but has anyone been able to run a Bionx wheel with something other than the Bionx controller that is built into the battery box?
Just hoping.....
 
The newer CanBus motors can be driven by an arduino setup. This fellow did some good investigation into reverse engineering the protocol and writing some code

http://www.northerndtool.com/bionx

I find myself short a CanBus battery for my setup, so I am working on building a bionx compatible battery pack using an arduino. If I get something that works I'll post a description on the forum.
 
Wow. I am really impressed with this work...Great job of reverse engineering.
I wonder if I2C would be easier to tackle...
 
I've been working reverse engineering the I2C setup myself this weekend.

Using an arduino uno as a i2c snooper. I see that:
- the console is the master (no surprise).

- the motor is address 8.

- the battery pack address 9.

- turning the battery pack on is done by temporary shorting the "wake" line to ground. Turning it off requires writing to a register on device 9.

- the battery pack supplies +5v to the console and +40v (battery voltage) to the motor both over the comm cable. The battery separately supplies real power to motor over the power lines. The motor uses the +40v on the comm cable to power its own microprocessor. This is different from the canbus battery which only puts 12v on the comm cable to the motor. This may mean you can damage a canbus motor by plugging it into a i2c battery.

- if the battery does not receive a message from the console every 10 seconds it turns off power to the motor but does not turn off the +5v line or the +40v over the comm cable for a couple minutes.

- the console microprocessor talks to the console display (address 56) over the same i2c bus used to communicate with the motor and battery, so there is a LOT of background communication.

I'm still working out what each of the registers in both of the slave devices mean. I'll post more once I figure some of that out.
 
Turns out the Bionx I2C motor has a pretty short register list. Recall it is device 8.

The following registers are read from:

17 - rotation speed (read about a dozen times per second)
18 - unknown. read about once every few seconds
20 - motor loading (frequently read)
21 - strain gauge (frequently read)
32 - reads "17" only read once at power up. I assume this is an identifier My motor is a P250.

The following registers are written to:

2 - always written as zero
9 - speed (/power?) control valid numbers 0 - 64
65 - always written as 0 perhaps mode? (drive or regen)
66 - always written as 1 perhaps direction?

Based on this I have a pretty simple arduino program which mimics the controller. It reads the strain gauge and applies motor power in proportion. I can't test it through. My I2c controller has water damage to some to the circuitry which drives the MOSFETs and it does not reliably run. So as I am in the middle of rebuilding my motor with one of the Canbus controllers from eBay. Eventually I'll make a translation program to convert the Canbus communications to I2C so my I2C controller and battery can drive the rebuilt motor.

An interested user would need to supply their own battery pack which must supply 25 - 40V for the motor and 12v for the arduino. The battery would need heavy gauge wires with the power connector to supply power to the motor, and an on / off switch.

Besides that the parts list is short:
- An Arduino Uno and some case for it.
- Hirose connector HR30-6P-6S(71) (mouser part number 798-HR30-6P-6S71 )
- a USB cable to cut up to provide cabling.
- skill with a soldering iron to solder the hirose connector to the cable.

The battery pack is significantly more complicated. There are twenty registers which are read, of which I have only established the function of 7. I'll need to be able to read them dynamically while the motor is running to get a sense of what they do. Unfortunately without knowing what these do I can't easily create a drop-in replacement battery pack with a custom BMS.

If you have interest in this project PM me and I'll spell out more details.
 
cormode said:
I find myself short a CanBus battery for my setup, so I am working on building a bionx compatible battery pack using an arduino. If I get something that works I'll post a description on the forum.

Old post I know, but came across it as you did link to my website. :lol:

So did you get anything working with the battery side of things? Since the set up was my colleges, once I got them to work for the project I ended up leaving it at that. However I'd be interested to know.

Dimitri
 
I have had more than one request for the code I generated as a result of this project.

This is written for the arduino to simulate a console. It tries to use the strain gauge to set the power command, similar to the console

It does not require a Bionx battery to work, however if a Bionx battery is used as part of the setup it can also talk to the battery and keep it awake. Initial waking up the battery requires temporarily connecting two of the pins on the hirose connector.

If the serial port the arduino is monitored you will see status updates pretty frequently. To control the motor directly via serial port use the following: xx yy zz Where xx is the device, yy is the register to write and zz is the register value.
Motor is device 8, motor power is register 9, valid power values are 0-64.

If you use this program, please send me reports.

I also wrote a program to simulate the battery. This should let me use the bionx controller and motor but with an after market battery. I will post that too eventually...

Code:
/* IC2 Bionx Console simulator. Duplicate some functions of the console 
  * Measure strain gauge and apply motor power in response
  * Report to the arduino serial port critical measurements
  */

/*
 * Copyright Daniel Cormode 2012. Free for personal use, permission required for use in a commercial product
 * SCL is connected to Arduino analog pin 5  
 * SDA to analog pin 4.
 */
 
#define averagedpoints 30  // The number of points used to compute the rolling average of the strain gauge

#include <Wire.h>
unsigned long lastsecond;
unsigned long lastreport;
int lasttwenty;
int lastten;
int powersetting;
int rotationspeed;
int straingauge;
int motorloading;
int errorcode;
int averagestrain[ averagedpoints ] ;
unsigned long summedstrain;
int strainpoint;
int poweroverride;
int keepbatteryawake;

void setup()
{
 int data;
 // Open serial port
 Wire.begin();
 Serial.begin(115200);
 
 // Zero array used for averaging
 for (int i = 0; i++ ;i < averagedpoints)
  {
    averagestrain[i] = 0;
  }
  summedstrain = 0;
  strainpoint = 0;
  
  // Three commands to make the bionx battery connect and close the power relay.
  Serial.print("   battery  register 32 =  ");   // relay keep alive
  // wake up battery
  data = ReadSingleByte(9,32);
  Serial.println(data);
  
  Serial.print("   bat 48 =  ");   // relay keep alive
  // battery is I2C address 9
  data = ReadSingleByte(9,48);
  Serial.print(data);
  
  Serial.print("   bat 49 =  ");   // relay keep alive
  data = ReadSingleByte(9,49);
  Serial.print(data);
 
 
 Serial.println("Waiting to motor to become active");
 // initalize motor
 while ( ReadSingleByte(8,32) < 1)
 {
   delay (100);
 }
 
  Serial.print("   battery  register 32 =  ");   // relay keep alive
  // wake up battery
  data = ReadSingleByte(9,32);
  Serial.println(data);
 
 // mimic three commands which console writes at bootup
 Serial.println("Initializing motor");
 WriteSingleByte(8,2,0);  // initialize strain gauge ?
 delay (10);
 WriteSingleByte(8,65,0);  // set motor to apply torque from a stopped position.  Setting this to 1 forces motor to be already spinning before it will apply power.
 delay (10);
 WriteSingleByte(8,66,1);  // set motor direction as forward
 delay(5);
 
 lastsecond =0;
 lasttwenty = 0;
 lastten = 0;
 lastreport = 0; 
 poweroverride = 0;
 keepbatteryawake = 1;
  
}

// Routine to read a single byte register from the I2C bus
int ReadSingleByte(int address, int reg)
{
 // reg = register to read
 // address = device address. Bionx I2C motor is 8
 int data = -1;
 int timeout = 10;

 Wire.beginTransmission(address);
 Wire.send(reg);
 if (Wire.endTransmission() == 0)
 {
 Wire.requestFrom(address,1);
 while (data == -1 & timeout > 0){  // sometimes the motor seems to try clock stretching.  Allow this for 10 ms.
   if (Wire.available() > 0)
   {
     data = Wire.receive();
   }
   timeout -=1;
   delay(1);
   }
 }
 
 return data; 
}

// routine to write a single byte register on the I2C bus
void WriteSingleByte(int address, int reg, int data)
{
 Wire.beginTransmission(address);
 Wire.send(reg);
 Wire.send(data);
 Wire.endTransmission(); 
}

void loop()
{  
  // read the strain gauge and update the power command 20 times per second.
  
  // calculate if it is time to communicate with the motor
  int twenty = (millis() % 1000) / 20;
  if (twenty != lasttwenty )
  {
    lasttwenty = twenty;
    // read strain gauge at register 8.
    straingauge = ReadSingleByte(8,21);
    if (straingauge < 0) straingauge = 0;  // check that the strain gauge value is valid
 
    // do the math to calculate the average straingague value over the last 1.5 seconds
    // The motor reports instaneous stain gauge values. As I pedal this value changes dramatically depending on pedal position
    // Without averaging the proportional response is herky-jerky
    
    // This is done by keeping a log of the last few measurements.
    
    averagestrain[strainpoint] = straingauge;  // replace the appropriate position in the array of historical points
    strainpoint++;     // update the index used to find the current place in the historical array
    if (strainpoint == averagedpoints)  
      strainpoint = 0;
    
    // sum the log and divide by twenty to   
    summedstrain = 0;
    for (int i = 0; i < averagedpoints;i++){
      summedstrain += averagestrain[i];
    }
    
    summedstrain = summedstrain / averagedpoints;
    
    // reduce the average strain by 1 as the motor seems to have some self strain when running.
    // The strain guage is mostly immune to the torsional force of the motor, but not completely
    // The strain guage does respond well to the lateral force of the chain pulling on the axle.
    summedstrain -= 1;
    if (summedstrain < 0) summedstrain = 0;
    
    // the power command is some multiple of the strain gauge (proportional power)
    powersetting = summedstrain * 1;

    // check if the user has entered a command previously at the serial port to run the motor faster
    if (poweroverride > powersetting) {
      powersetting = poweroverride;
    }
    
    // sanity check to keep from overdriving the motor
    // commanded power over 64 cause the motor to not operate
    if (powersetting > 64) {
      powersetting = 64;
    }
    
    // write the power command to the motor
    WriteSingleByte(8,9,powersetting);
    delay(1);
  }
  
  int ten = (millis() % 1000) / 10;
  if (ten != lastten )
  {
    lastten = ten;
    // rotation speed is register 17
    rotationspeed = ReadSingleByte(8,17);
    delay(1);
    // motor loading is register 20
    motorloading = ReadSingleByte(8,20);
    delay(1);
  }
  
  int second = millis() / 1000;
  if (second != lastsecond){
    lastsecond = second;
    errorcode = ReadSingleByte(8,18);
  }
  
  int report = millis() / 2500;   //report to user and keep alive battery pack
  if (report != lastreport){
    lastreport = report;  
    printreport();
  }
  
  delay(1);
 
}

void printreport()
{
  int data;
  int user;
  char useradd[4];
  char userdata[4];
  int useraddi;
  int userdatai;
  char userdev[4];
  int userdevi;
  int i;  

  
 // troublesome motor code
 
 Serial.print("    pow cmd =  ");  
 Serial.print(powersetting); 
 
 Serial.print("    mot 18 =  ");  
 Serial.print(errorcode);

  //motor related
  
  Serial.print("    mot rotation =  ");   // rotation speed
  Serial.print(rotationspeed);


  Serial.print("    mot torque =  ");   // motor loading
  Serial.print(motorloading);

  
  Serial.print("    inst strain gauge =  ");   // strain gauge
  Serial.print(straingauge);
  
 // Battery Related
 
 if (keepbatteryawake)
 
 {
   
  Serial.print("   bat 48 =  ");   // relay keep alive
  // battery is I2C address 9
  data = ReadSingleByte(9,48);
  Serial.print(data);
  
  Serial.print("   bat 49 =  ");   // relay keep alive
  data = ReadSingleByte(9,49);
  Serial.print(data);
  
 }
  
  Serial.print("   bat 50 =  ");   //  seems to important to console
  data = ReadSingleByte(9,50);
  Serial.print(data);
  
  Serial.print("   bat 51 =  ");   //  seems to important to console
  data = ReadSingleByte(9,51);
  Serial.print(data);
  
  Serial.print("   bat 96 =  ");   //  seems to important to console
  data = ReadSingleByte(9,96);
  Serial.print(data);
  
  Serial.print("   bat 97 =  ");   //  seems to important to console
  data = ReadSingleByte(9,97);
  Serial.print(data);
  
 

// read from the serial port to see if the user wants to issue a command

  if (Serial.available() > 0)
  
  {
    for ( i =0; i<3;i++){
    userdev[i] = Serial.read();
    }
    
    userdev[i] = '\0';
          
    user = Serial.read();
    
    for ( i =0; i<3;i++){
    useradd[i] = Serial.read();
    }
    
    useradd[i] = '\0';
    
    user = Serial.read();
    
   for (i =0; i<3;i++){
    userdata[i] = Serial.read();
    }
    
    userdata[i] = '\0';
   
   Serial.println("");
   Serial.print(useradd);
   Serial.print(" ");
   Serial.print(userdata);
   Serial.println(""); 
   
    userdevi = atoi(userdev);
    useraddi = atoi(useradd);
    
    userdatai = atoi(userdata);
   
   Serial.println("");
   Serial.print(userdevi);
   Serial.print(" ");
   Serial.print(useraddi);
   Serial.print(" ");
   Serial.print(userdatai);
   Serial.println("");
    
    if (useraddi > 0 & useraddi < 256 & userdatai > -1 & userdatai < 256) {
      WriteSingleByte(userdevi,useraddi,userdatai);
    }
    
    if (userdevi == 8 & useraddi == 9) {
      poweroverride = userdatai;
      Serial.print("Power override set to");
      Serial.println(poweroverride);
    }
    
    
    
    if ((userdevi == 9 & useraddi == 33) & userdatai == 0) {
      keepbatteryawake = 0;
      Serial.print("Letting battery relay stay closed");         
    }
    
    if ((userdevi == 9 & useraddi == 33) & userdatai == 1) {
      keepbatteryawake = 1;
      Serial.print("Keeping battery relay open");         
    }
  }    
  
  Serial.println("");
}
 
Just another note that I discovered in my own work reverse engineering the I2C protocol for the old Bionx system, you do not need a battery on the I2C bus at all for the rest of the system to work.

This means that people who want to build their own battery packs for the Bionx system can simply cut the data cables connecting the console and the motor to the battery mount (bypassing the battery altogether), solder the green and white wires together (SDA and SCL) and connect the red and black wires for the motor cable to battery voltage. The console is a bit harder because it expects 5V over the red and black wires, but all I did was connect a cheap UBEC to it that provides 5V regulation. Now my motor and console work with whatever battery I plug into it! The battery level display is obviously gone, but that's about all the functionality you lose.

Nice work by the way cormode, I had the basics of the I2C protocol figured out, but it looks like your program is much better than mine. I appreciate you posting it!
 
Dimitri said:
cormode said:
I find myself short a CanBus battery for my setup, so I am working on building a bionx compatible battery pack using an arduino. If I get something that works I'll post a description on the forum.

Old post I know, but came across it as you did link to my website. :lol:

So did you get anything working with the battery side of things? Since the set up was my colleges, once I got them to work for the project I ended up leaving it at that. However I'd be interested to know.

Dimitri

After collision with a car my Bionx would not turn off: The console would power-up continuously.
When I opened the battery case it would seem the battery cells and BMS have come together.
DSC_0037.png

BMS becomes warm to touch and drains down battery.
PCB dated 09/2009 which I thought would be i2c, so attempted cormode's arduino sketch by breaking out SDA, SCL but saw no response on the serial monitor.
Read elsewhere that the change to canBUS was 05/2009, so now maybe I use Dimitri sketch.
My Issue is that both solutions seem to clone the console, yet I require BMS clone I think.

@Dimitri: Did you succeed in cloning the battery charge requirements?

My board looks like this.
DSC_0035.png
DSC_0038.png

I cannot determine if a component has gone bad or a firmware issue.
The bionx still functions correctly aside from the self power-up. Debug console reads voltage correctly, yet a couple of seconds later will read 08 then change to 28; I'm reading 8 as motor address, yet no idea what 28 address is.
Perhaps long shot but was hoping if I can communicate with BMS I can determine, reset or bypass the problem.

Maybe I have another battery soon - If not, I perhaps try to emulate doc solution and connect external controller if BMS is unworkable.

Thank you
 
I cannot determine if a component has gone bad or a firmware issue.
The bionx still functions correctly aside from the self power-up. Debug console reads voltage correctly, yet a couple of seconds later will read 08 then change to 28; I'm reading 8 as motor address, yet no idea what 28 address is.
Perhaps long shot but was hoping if I can communicate with BMS I can determine, reset or bypass the problem.

You definately have a canbus system. The silkscreening on the board labels some pins cl and ch - CanHigh and CanLow

I expect that the BMS board is destroyed. My suspicion is that one or more traces in the PCB are cracked, possibly in an internal layer and the CPU no longer gets the right signals.
 
cormode said:
You definately have a canbus system. The silkscreening on the board labels some pins cl and ch - CanHigh and CanLow

I expect that the BMS board is destroyed. My suspicion is that one or more traces in the PCB are cracked, possibly in an internal layer and the CPU no longer gets the right signals.

cormode thank you.
I cannot feel more foolish for not seeing the obvious! In my defence my research has been very fragmented and I got over excited when I saw arduino & bionx together :D
As I had spare arduino to hand, and this thread open, i gave it a go. Only later did I find info that my PCB was 2009 canBus. Became tempted to purchase a canBus sheild and attempt comms, but became confused, which led me to my poor post above :)
I was relying [wishing] on the arduino to dispense with the need to have the bionx BMS in place...

I am however resigned to the fact the the PCB is beyond my capabilities to fix, but nevertheless I am curious enough to play with the comms side in the vain hope that I can find a way around 'powering down' the system.

Perhaps i will buy Crumb128-CAN dongle to use with http://www.bigxionflasher.org/ just for fun whilst i delibrate on my next step..
 
Never did replicate that voltage signal on the power wires that the BionX motor seems to want to operate correctly.

I was pressed for time, and had to make it work, so I used a BionX battery controller PCB with my lead acid batteries.

I, to be truthful, don't have the experience base to have been able to do it in my time constraints. Figuring out numbers is easy, figuring out which one of the dozens of ways to communicate over a power wire BionX used is a wee bit more difficult for me.

Dimitri
 
Thank you Dimitri,

I, to be truthful, don't have the experience base to have been able to do it in my time constraints. Figuring out numbers is easy, figuring out which one of the dozens of ways to communicate over a power wire BionX used is a wee bit more difficult for me.

Hmm, that doesn't bode well for an under achiever such as I :) but i will contiue to probe nevertheless.

Thank you again all for your replies to my innate rambles...
 
Found the chip that is heating up. (U3)

bigx.png
What this chip is, and what is does remains a mystery, although it was apparent that the chip would become hot when the bike was powered ON, which was a surprise!

With a fully charged battery @24v, Chip voltages vary thus:
Battery sleeping.
2.6 --| |--7.85
3.25--| |--0.0
3.25--| |--7.85

Battery awake.
3.18--| |--11.8
3.25--| |--11.8
3.25--| |--11.8

Main 30 amp fuse removed
0.0 --| |--3.4
0,5 --| |--0.0
0.5 --| |--3.4
Also when main fused has been removed there is a faint audible 'high pitch' noise from the board.
Battery voltage after 12 hours 'sleeping' reads 22.4v.
 
Thought I'd post a follow up:

Address '28' is accessory line. Had this relyed via a BionX tech in Germany. Tech was good until I told them I had opened the battery and the subject of WARRENTY kept being repeated!
But happy that I had an 'in' I continued to bug 'em - End story; No fix for a 24v.
Although Bionx have offered a new 36/48v battery and will supply a battery charger Free Of Charge which was a nice guesture considering they had no obligatin to help.
 
Hi all!

This is most interesting stuff! I'm completely new here, and the reason I'm here is I was recently given two Bionx wheels (one 500W and one 350 RL) and one G1 controller, no battery. So I've been thinking about how to get the system going.
I'd like to possibly reuse the controller and driving both wheels off it. The thoughts is to have a two wheel drive small motorbike for the kids to play with, replacing the small mini mx that I converted to electric a couple of years ago and they now have outgrown. Or maybe something along the same lines for myself...

I'm sure going to need more help as things progress, but it sure looks promising so far!
 
it looks like canbus is a fairly standard off the shelf communication protocol http://en.wikipedia.org/wiki/CAN_bus

not so proprietary isnt it? so if someone could write some Arduino code to send the data to the motor to make it spin and eliminate the console and board in battery box and drive the motor directly from an Arduino

maybe even remove the speed limit provided that the speed limit lives in the console or battery box not the motor controller.
 
CAN Bus only defines the hardware and data packet structure aspects of the bus itself.

What way you decide to use the address and data fields is not actually defined. Which is why there are nearly 2 dozen well used "standard" versions of CAN Bus used worldwide today, depending on the application.

The BionX system doesn't follow conventional CAN Bus protocols in the way it structures it's address lines and data. Instead it is more like the I2C System that BionX switched from.

Right now, with just the information on my website, you can make the wheels spin, and emulate the controller and battery pack. The problem isn't that, the problem is that there is non-Bus data/signalling going from the battery controller to the motor. If you do a oscilloscope trace on the power output itself you'll see what I mean.

If you find the BionX software for bike dealers, you can strip away the speed limits to a point I am told. By re-configuring the motor controller itself. I however did not go this route. But if you Google Search it (especially on German sites) you can find it. I can tell you, trying to send commands to the motor to go above the speed limit results in the motor trying to brake the wheel, so this kind of software adjustment will be needed in addition to any controller you can build.

Dimitri
 
I know this thread is a bit old but did anyone ever get the code to simulate the Bionx I2C Battery?

cormode said:
I have had more than one request for the code I generated as a result of this project.

This is written for the arduino to simulate a console. It tries to use the strain gauge to set the power command, similar to the console

It does not require a Bionx battery to work, however if a Bionx battery is used as part of the setup it can also talk to the battery and keep it awake. Initial waking up the battery requires temporarily connecting two of the pins on the hirose connector.

If the serial port the arduino is monitored you will see status updates pretty frequently. To control the motor directly via serial port use the following: xx yy zz Where xx is the device, yy is the register to write and zz is the register value.
Motor is device 8, motor power is register 9, valid power values are 0-64.

If you use this program, please send me reports.

I also wrote a program to simulate the battery. This should let me use the bionx controller and motor but with an after market battery. I will post that too eventually...

Code:
/* IC2 Bionx Console simulator. Duplicate some functions of the console 
  * Measure strain gauge and apply motor power in response
  * Report to the arduino serial port critical measurements
  */

/*
 * Copyright Daniel Cormode 2012. Free for personal use, permission required for use in a commercial product
 * SCL is connected to Arduino analog pin 5  
 * SDA to analog pin 4.
 */
 
#define averagedpoints 30  // The number of points used to compute the rolling average of the strain gauge

#include <Wire.h>
unsigned long lastsecond;
unsigned long lastreport;
int lasttwenty;
int lastten;
int powersetting;
int rotationspeed;
int straingauge;
int motorloading;
int errorcode;
int averagestrain[ averagedpoints ] ;
unsigned long summedstrain;
int strainpoint;
int poweroverride;
int keepbatteryawake;

void setup()
{
 int data;
 // Open serial port
 Wire.begin();
 Serial.begin(115200);
 
 // Zero array used for averaging
 for (int i = 0; i++ ;i < averagedpoints)
  {
    averagestrain[i] = 0;
  }
  summedstrain = 0;
  strainpoint = 0;
  
  // Three commands to make the bionx battery connect and close the power relay.
  Serial.print("   battery  register 32 =  ");   // relay keep alive
  // wake up battery
  data = ReadSingleByte(9,32);
  Serial.println(data);
  
  Serial.print("   bat 48 =  ");   // relay keep alive
  // battery is I2C address 9
  data = ReadSingleByte(9,48);
  Serial.print(data);
  
  Serial.print("   bat 49 =  ");   // relay keep alive
  data = ReadSingleByte(9,49);
  Serial.print(data);
 
 
 Serial.println("Waiting to motor to become active");
 // initalize motor
 while ( ReadSingleByte(8,32) < 1)
 {
   delay (100);
 }
 
  Serial.print("   battery  register 32 =  ");   // relay keep alive
  // wake up battery
  data = ReadSingleByte(9,32);
  Serial.println(data);
 
 // mimic three commands which console writes at bootup
 Serial.println("Initializing motor");
 WriteSingleByte(8,2,0);  // initialize strain gauge ?
 delay (10);
 WriteSingleByte(8,65,0);  // set motor to apply torque from a stopped position.  Setting this to 1 forces motor to be already spinning before it will apply power.
 delay (10);
 WriteSingleByte(8,66,1);  // set motor direction as forward
 delay(5);
 
 lastsecond =0;
 lasttwenty = 0;
 lastten = 0;
 lastreport = 0; 
 poweroverride = 0;
 keepbatteryawake = 1;
  
}

// Routine to read a single byte register from the I2C bus
int ReadSingleByte(int address, int reg)
{
 // reg = register to read
 // address = device address. Bionx I2C motor is 8
 int data = -1;
 int timeout = 10;

 Wire.beginTransmission(address);
 Wire.send(reg);
 if (Wire.endTransmission() == 0)
 {
 Wire.requestFrom(address,1);
 while (data == -1 & timeout > 0){  // sometimes the motor seems to try clock stretching.  Allow this for 10 ms.
   if (Wire.available() > 0)
   {
     data = Wire.receive();
   }
   timeout -=1;
   delay(1);
   }
 }
 
 return data; 
}

// routine to write a single byte register on the I2C bus
void WriteSingleByte(int address, int reg, int data)
{
 Wire.beginTransmission(address);
 Wire.send(reg);
 Wire.send(data);
 Wire.endTransmission(); 
}

void loop()
{  
  // read the strain gauge and update the power command 20 times per second.
  
  // calculate if it is time to communicate with the motor
  int twenty = (millis() % 1000) / 20;
  if (twenty != lasttwenty )
  {
    lasttwenty = twenty;
    // read strain gauge at register 8.
    straingauge = ReadSingleByte(8,21);
    if (straingauge < 0) straingauge = 0;  // check that the strain gauge value is valid
 
    // do the math to calculate the average straingague value over the last 1.5 seconds
    // The motor reports instaneous stain gauge values. As I pedal this value changes dramatically depending on pedal position
    // Without averaging the proportional response is herky-jerky
    
    // This is done by keeping a log of the last few measurements.
    
    averagestrain[strainpoint] = straingauge;  // replace the appropriate position in the array of historical points
    strainpoint++;     // update the index used to find the current place in the historical array
    if (strainpoint == averagedpoints)  
      strainpoint = 0;
    
    // sum the log and divide by twenty to   
    summedstrain = 0;
    for (int i = 0; i < averagedpoints;i++){
      summedstrain += averagestrain[i];
    }
    
    summedstrain = summedstrain / averagedpoints;
    
    // reduce the average strain by 1 as the motor seems to have some self strain when running.
    // The strain guage is mostly immune to the torsional force of the motor, but not completely
    // The strain guage does respond well to the lateral force of the chain pulling on the axle.
    summedstrain -= 1;
    if (summedstrain < 0) summedstrain = 0;
    
    // the power command is some multiple of the strain gauge (proportional power)
    powersetting = summedstrain * 1;

    // check if the user has entered a command previously at the serial port to run the motor faster
    if (poweroverride > powersetting) {
      powersetting = poweroverride;
    }
    
    // sanity check to keep from overdriving the motor
    // commanded power over 64 cause the motor to not operate
    if (powersetting > 64) {
      powersetting = 64;
    }
    
    // write the power command to the motor
    WriteSingleByte(8,9,powersetting);
    delay(1);
  }
  
  int ten = (millis() % 1000) / 10;
  if (ten != lastten )
  {
    lastten = ten;
    // rotation speed is register 17
    rotationspeed = ReadSingleByte(8,17);
    delay(1);
    // motor loading is register 20
    motorloading = ReadSingleByte(8,20);
    delay(1);
  }
  
  int second = millis() / 1000;
  if (second != lastsecond){
    lastsecond = second;
    errorcode = ReadSingleByte(8,18);
  }
  
  int report = millis() / 2500;   //report to user and keep alive battery pack
  if (report != lastreport){
    lastreport = report;  
    printreport();
  }
  
  delay(1);
 
}

void printreport()
{
  int data;
  int user;
  char useradd[4];
  char userdata[4];
  int useraddi;
  int userdatai;
  char userdev[4];
  int userdevi;
  int i;  

  
 // troublesome motor code
 
 Serial.print("    pow cmd =  ");  
 Serial.print(powersetting); 
 
 Serial.print("    mot 18 =  ");  
 Serial.print(errorcode);

  //motor related
  
  Serial.print("    mot rotation =  ");   // rotation speed
  Serial.print(rotationspeed);


  Serial.print("    mot torque =  ");   // motor loading
  Serial.print(motorloading);

  
  Serial.print("    inst strain gauge =  ");   // strain gauge
  Serial.print(straingauge);
  
 // Battery Related
 
 if (keepbatteryawake)
 
 {
   
  Serial.print("   bat 48 =  ");   // relay keep alive
  // battery is I2C address 9
  data = ReadSingleByte(9,48);
  Serial.print(data);
  
  Serial.print("   bat 49 =  ");   // relay keep alive
  data = ReadSingleByte(9,49);
  Serial.print(data);
  
 }
  
  Serial.print("   bat 50 =  ");   //  seems to important to console
  data = ReadSingleByte(9,50);
  Serial.print(data);
  
  Serial.print("   bat 51 =  ");   //  seems to important to console
  data = ReadSingleByte(9,51);
  Serial.print(data);
  
  Serial.print("   bat 96 =  ");   //  seems to important to console
  data = ReadSingleByte(9,96);
  Serial.print(data);
  
  Serial.print("   bat 97 =  ");   //  seems to important to console
  data = ReadSingleByte(9,97);
  Serial.print(data);
  
 

// read from the serial port to see if the user wants to issue a command

  if (Serial.available() > 0)
  
  {
    for ( i =0; i<3;i++){
    userdev[i] = Serial.read();
    }
    
    userdev[i] = '\0';
          
    user = Serial.read();
    
    for ( i =0; i<3;i++){
    useradd[i] = Serial.read();
    }
    
    useradd[i] = '\0';
    
    user = Serial.read();
    
   for (i =0; i<3;i++){
    userdata[i] = Serial.read();
    }
    
    userdata[i] = '\0';
   
   Serial.println("");
   Serial.print(useradd);
   Serial.print(" ");
   Serial.print(userdata);
   Serial.println(""); 
   
    userdevi = atoi(userdev);
    useraddi = atoi(useradd);
    
    userdatai = atoi(userdata);
   
   Serial.println("");
   Serial.print(userdevi);
   Serial.print(" ");
   Serial.print(useraddi);
   Serial.print(" ");
   Serial.print(userdatai);
   Serial.println("");
    
    if (useraddi > 0 & useraddi < 256 & userdatai > -1 & userdatai < 256) {
      WriteSingleByte(userdevi,useraddi,userdatai);
    }
    
    if (userdevi == 8 & useraddi == 9) {
      poweroverride = userdatai;
      Serial.print("Power override set to");
      Serial.println(poweroverride);
    }
    
    
    
    if ((userdevi == 9 & useraddi == 33) & userdatai == 0) {
      keepbatteryawake = 0;
      Serial.print("Letting battery relay stay closed");         
    }
    
    if ((userdevi == 9 & useraddi == 33) & userdatai == 1) {
      keepbatteryawake = 1;
      Serial.print("Keeping battery relay open");         
    }
  }    
  
  Serial.println("");
}
 
Hello

I know this is a old post but is there some progress on the bionx battery emulation?

Greetings Dennis
 
Hi
I'm in France and try to find out the minimum communication needed to allow the controler to run
Does anyone of you know the responses to give to the control unit ?

Thanks in advance
BR
Nicolas
 
Hi all,
Sorry for my english, I am From Spain.
I have recently bought a second hand ebike (matra sports i.step, equipped with bionx i2c components) without battery.
After that I know what I have bought, I have found this little great information about bionx i2c comunication. Many thanks for sharing it.
I have tested to power the motor and the controller, and it comunicate, I see the speed of the wheel and when when I brake, the motor generates energy.
Randomly when I lightly press the brake, the motor spins a bit.
But I don't get any assistance when I pedaling.
I have tested your Arduino program, and I can comunicate, I can see on pc terminal, the speed of the wheel.
I have tried to send 08 09 50 to spin motor, but no effect.
(I power the ebike with a bench power supply)
When I checked the the program in the arduino IDE, I had to rename "Wire.send" to "Wire.write" and "Wire.receive" to "Wire.read".

My question is: did you obtain any results emulating the battery?

I would appreciate any help you can give me on this subject.
Thank you very much.
 
Hi TRoller,

I'm sorry but I can't give you an answer.
But in case you have a IC2 communication protocol Bionx system did you see the post from Quasse in Sun Sep 08, 2013 10:24 pm? It seems you can "bypass" the battery by connecting the motor communication cables to the console communication cables and sending a 5V to the console (see post for details). I have never done it so I can't tell you more than what's in that post.
In case you found or find out a solution to your problem, please post it here. Thanks.

Cheers,
Guelao
 
Did anybody tried cormodes Arduino sketch? I've tried it with an old I2C Bionx motor, just for the fun, and the motor runs, but the speed control doesn't work for some reason. As soon as I enter anything other than 0 in the speed register, it goes fulls speed. As I don't have the display, I can't really snoop on the communication, to see what the display is actually writing to the motor.
 
Back
Top