I wanted to use two separate current sensing IC’s one for each motor instead of the one from the elektor design. Günter Gerold connects these to a separate Atmega168 and I connected mine in the same way so that i could also use his Bascom software for this secondary processor.
The elektor design has the ACS755 SCB-100 current sensing IC which is now obsolete. So instead I used ACS758 SCB 100 which is compatible to this one, and i used two of these.
Maybe it would have been better to use ACS758 SCB-50 to get more accuracy but i had two 100 amp units lying around.
The Atmega168 talks to the main processor board via I2C which is the reason that the SCL and SDA connectors have been brought out to the RS232 connector on the main Zzaag microprocessor CPU..
In the picture on the left you can see the additional Atmega168 which is interfacing with both the gearsonsors and the current sensors.
At the top left you can see the connector which attaches to the main microprocessor PCB and the FDTI programming connector.
The connectors at the bottom left are those for the gearsensors themselves.
The software is essentially the same as on the Gerold – Elektronik website except that two LEDs have been added which blink each time an interrupt is received from the geartooth sensors. The LEDs are connected to PB4 and PB5 respectively. This rather simplifies debugging asthe LEDs visualise if the program “sees” the geartooth sensors. The software caters for sensors of the type ATS667 or ATS665 which do not have sense direction but also the ATS657 which has direction sensing onboard. I have experimented with both the ATS667 and the ATS657 with thanks to Allegro who did send me samples.
I finally ended up using the ATS657 because of the direction sensing that this chip has.
The software is written in Bascom but is small enough to be usable in the freeware Bascom compiler. So there was no reason to change this to Arduino and i left it as is.
Below is the circuit diagram of the additional hardware. You can see the gearsensor connections and the current sensing ACS758 SCB-100.
As previously said the software i used for the gearsensor CPU was almost identical to that of Gerold – Elektronik. It is compiled using the freeware bascom compiler. This creates a HEX file which can be loaded into the Atmega168 using avrdude in the same way as programming a new bootloader into an arduino. I use the very nice YCIT GUI which you can download from here. A picture of the settings can be seen on the left. In the three pictures below you can see the geartoothsensor circuit boards. The one on the right is the ATS667 mounted in place on the motor in the same way as on the Gerold – Elektronik website. I used a small piece of board to mount the device on. You can also look at the Gerold – Elektronik website to see how it can be mounted. In the article WheelieGT Elektor also did an article on the subject with very good description as to how to mount etc.
The two pictures below on the left show the ATS657 circuit which is copied from the Elektor Wheelie forum. I simply wired this on a small piece of veroboard and it worked without modification. In order to test this software you can connect the I2C connection to the main Zzaag CPU via the 2 * 5 connector and run the following arduino program on it which visualises the data.
[spoiler]
// Test for communication with Gearsensor.bas // This is a slave I2c program listening to 8bit I2c code 0x40 // This is 0x20 or 32 in 7 bit code leaving the LSB as read. Wire deals with this // automatically so don't bother changing // It simply reads the relevant data from the Atmega168 running the Bascom program // mentioned above. // The data is coded as follows // Byte 1 and 2: Speed left // Byte 3 and 4: Speed right // Byte 5 and 6: Current left // Byte 7 and 8: Current right // Byte 9 Bit 6: left Direction // Byte 9 Bit 7: No Direction Flag left // Byte 9 Bit 3: right Direction // Byte 9 Bit 4: No Direction Flag right // I have tested both ATS667 and ATS657 so with and without direction data. Gearsensor.bas measures the pulses and draws // a conclusion about which direction. // The Atmega32 program on the CPU print needs to be adapted to take care of this. // I now use ATS657 which also generates direction data. // I also added two LED's to PORTB.4 and PORTB.5 which toggle on every interrupt. // One on INT0 and one on INT1. This way you can see the pulses arriving from the sensor. Very handy!!! #include <Wire.h> void setup() { Wire.begin(); // join i2c bus (address optional for master) Serial.begin(9600); // start serial for output } void loop() { Wire.requestFrom(32, 9); // request 9 bytes from slave device 32 int i=0; while(Wire.available()) // { i++; int c = Wire.receive(); // receive a byte as integer Serial.print(c,HEX); Serial.print(" "); // print the HEX number if (i==9) { Serial.print(" left = "); if ((c & 128) == 128) {Serial.print("None ");} if ((c & 64) == 64) {Serial.print("F");} else {Serial.print("B");} Serial.print(" right = "); if ((c & 16) == 16) {Serial.print("None ");} if ((c & 8) == 8) {Serial.print("F");} else {Serial.print("B");} } } Serial.println(); delay(500); }
[/spoiler]
[spoiler]
'--------------------------------------------------------------------------- ' _____ _ _ _ _ _ _ _ _ _ ' | __| |___| |_| |_ ___ ___ | | | | |_ ___ ___| |_|___ ' | __| | -_| '_| _| . | _| | | | | | -_| -_| | | -_| ' |_____|_|___|_,_|_| |___|_| |_____|_|_|___|___|_|_|___| ' ' (c)2009 Elektor International Media B.V. '--------------------------------------------------------------------------- 'Version: Speed100 - Peripheral Measurements for Elektor '--------------------------------------------------------------------------- 'Purpose: ' Measurement of Speed, Current and direction of rotation for the Elektor-Wheelie ' Byte 1 and 2: Speed left ' Byte 3 and 4: Speed right ' Byte 5 and 6: Current left ' Byte 7 and 8: Current right ' Byte 9 Bit 6: left Direction ' Byte 9 Bit 7: No Direction Flag left ' Byte 9 Bit 3: right Direction ' Byte 9 Bit 4: No Direction Flag right '--------------------------------------------------------------------------- 'Description: ' Until now only speed is calculated out of gear tooth sensor sensors '---------------------------------------------------------------------------' 'Changes Log: ' Speed090: 11.12.2009 ' First code by Günter Gerold ' Speed091: 11.12.2009 ' Handling of Timer1 overflow by Thomas Scherer ' Speed092: 12.12.2009 ' Fallback to Wordmax if no Interrupts after 2 Timer1 Overflows ' Speed093: 13.12.2009 ' Fallback to 10000 if no Interrupts after 228,48 ms (slower than 0,333 km/h) ' Timer0 and Timer2 ' Speed094: 11.07.2010 ' Measure the currents of the Sensors. ' for a short time of the ADC we dont wait for the result ' if the ADC is ready we store the value in the interrupt and switch the channel. ' Speed100: 25.12.2010 ' detection of the drivingdirection with the ATS657 45µs-Pulse = forward, 90µs Pulse = backward '--------------------------------------------------------------------------- 'ToDo: ' nothing '--------------------------------------------------------------------------- 'Contact: ' Please post ideas, improvements and code into this thread in the Elektor forum: ' http://www.elektor.de/forum/foren-ubersicht/foren-zu-elektor-projekten/elektorwheelie.996934.lynkx ' Günter Gerold: tv@gerold-online.de '--------------------------------------------------------------------------- $regfile = "m168def.dat" $crystal = 16000000 $baud = 57600 'timeout when waiting for pulses Config Timer0 = Timer , Prescale = 1024 On Timer0 Int_timer0 Start Timer0 'measure the distance between two pulses (speed) Config Timer1 = Timer , Prescale = 1024 'Time base: timer clock = 15625Hz = 64µs/pulse Start Timer1 'measure the width of the pulse (direction) Config Timer2 = Timer , Prescale = 64 '4µs per Tick Start Timer2 'Sensor inputs generate interrupts at rising and falling flank Config Int0 = Change 'Interrupt for the left tooth sensor Config Int1 = Change 'Interrupt for the right tooth sensor On Int0 Int_0 On Int1 Int_1 Led0 Alias Portb.5 Led1 Alias Portb.4 Config Led0 = Output Config Led1 = Output Led0 = 0 Led1 = 0 'measure Currentsensors On Adc On_adc 'ADC Interrupt Admux = &B01000000 Adcsra = &B11001111 Dim Cur_ch As Bit 'all Data stored in an Array, so its easy to send with I²C Dim Data_array(10) As Byte Dim Speed_left As Word At Data_array(1) Overlay Dim Speed_right As Word At Data_array(3) Overlay Dim Curr_left As Word At Data_array(5) Overlay Dim Curr_right As Word At Data_array(7) Overlay Dim Direction_byte As Byte At Data_array(9) Overlay Dim Count_left_old As Word 'detect Timer1 overflow Dim Count_right_old As Word 'detect Timer1 overflow Dim Timer_left As Word 'Value of Timer1 left motor Dim Timer_right As Word 'Value of Timer1 right motor Dim Timer0_overflow_l As Byte Dim Timer0_overflow_r As Byte Dim Timer2_up_l As Byte Dim Timer2_down_l As Byte Dim Timer2_up_r As Byte Dim Timer2_down_r As Byte Dim Left_direction As Byte Dim Right_direction As Byte Dim Cnt As Byte Dim Twi_control As Byte Dim Twi_status As Byte Const Wordmax = 65535 Const Bytemax = 256 Enable Interrupts Enable Int0 Enable Int1 Enable Timer0 Enable Timer2 Twsr = 0 Twdr = &HFF Twar = &H40 'Our I²C Adress Twcr = &B01000100 'Hardware TWI Slave Transmitter Speed_left = 10000 Speed_right = 10000 Do If Timer0_overflow_l > 14 Then '229ms and no Toothinterrupt (255 x 1024 x 14 x 62,5ns = 229ms), we don't wait longer and set a value. Timer0_overflow_l = 0 Speed_left = 10000 'Set 1/Speed to MAX = 0,12 km/h Set Direction_byte.7 'no Direction End If If Timer0_overflow_r > 14 Then Timer0_overflow_r = 0 Speed_right = 10000 Set Direction_byte.4 'no Direction End If Select Case Right_direction Case 5 To 17 'CW detected Set Direction_byte.3 Reset Direction_byte.4 Case 18 To 28 'CCW detected Reset Direction_byte.3 Reset Direction_byte.4 Case 38 To 53 'no Direction detected Set Direction_byte.4 End Select Select Case Left_direction Case 5 To 17 'CW detected Set Direction_byte.6 Reset Direction_byte.7 Case 18 To 28 'CCW detected Reset Direction_byte.6 Reset Direction_byte.7 Case 38 To 53 'no Direction detected Set Direction_byte.7 End Select Twi_control = Twcr And &H80 If Twi_control = &H80 Then 'Interruptflag of the Hardware TWI is set Twi_status = Twsr And &HF8 Select Case Twi_status Case &HA8: 'Send the first Byte Twdr = Data_array(1) Twcr = &B11000100 Cnt = 2 Case &HB8: 'Send additional Bytes Twdr = Data_array(cnt) Incr Cnt Twcr = &B11000100 Case Else : 'Ignore other Commands Twcr = &B11000100 End Select If Cnt = 10 Then Adcsra.6 = 1 'If all Data is send via I²C then start the ADC for new current values End If Loop Int_0: Toggle Led0 'A changing Flank was detected from the left Sensor If Pind.2 = 1 Then 'the rising Flank Timer0_overflow_l = 0 Timer_left = Timer1 'Timer1 measures the distance between the pulses Timer2_up_l = Timer2 'Timer2 measures the width of the pulse If Timer_left >= Count_left_old Then Speed_left = Timer_left - Count_left_old Else Speed_left = Wordmax - Count_left_old 'Overflow of Timer1 Speed_left = Speed_left + Timer_left End If Count_left_old = Timer_left 'store old Value If Speed_left > 10000 Then Speed_left = 10000 Else 'the falling Flank Timer2_down_l = Timer2 'calculate the width of the pulse If Timer2_down_l > Timer2_up_l Then Left_direction = Timer2_down_l - Timer2_up_l Else Left_direction = Bytemax - Timer2_up_l Left_direction = Left_direction + Timer2_down_l End If End If Return Int_1: Toggle Led1 'A changing Flank was detected from the left Sensor If Pind.3 = 1 Then 'the rising Flank Timer0_overflow_r = 0 Timer_right = Timer1 Timer2_up_r = Timer2 If Timer_right >= Count_right_old Then Speed_right = Timer_right - Count_right_old Else 'Overflow of Timer1 Speed_right = Wordmax - Count_right_old Speed_right = Speed_right + Timer_right End If Count_right_old = Timer_right If Speed_right > 10000 Then Speed_right = 10000 Else 'the falling Flank Timer2_down_r = Timer2 'calculate the width of the pulse If Timer2_down_r > Timer2_up_r Then Right_direction = Timer2_down_r - Timer2_up_r Else Right_direction = Bytemax - Timer2_up_r Right_direction = Right_direction + Timer2_down_r End If End If Return Int_timer0: 'count Timer0 Overflows for Timeout of the Wheels Incr Timer0_overflow_l Incr Timer0_overflow_r Return On_adc: 'ADC is ready and have a new value If Cur_ch = 0 Then 'value from the left Sensor Curr_left = Adc Toggle Cur_ch 'switch to the right sensor Admux.0 = Cur_ch Adcsra.6 = 1 'start ADC to get the value from the right sensor Else Curr_right = Adc Toggle Cur_ch Admux.0 = Cur_ch 'switch to the left sensor, but dont start the ADC. This was made later in the mainloop. End If Return
[/spoiler]
Download the files from here Gearsensor.pde Gearsensor3.bas
Below is the data from the gearsensor.pde program.
The data is coded as follows:
Byte 1 and 2: Speed left
Byte 3 and 4: Speed right
Byte 5 and 6: Current left
Byte 7 and 8: Current right
Byte 9 Bit 6: left Direction
Byte 9 Bit 7: No Direction Flag left
Byte 9 Bit 3: right Direction
Byte 9 Bit 4: No Direction Flag right
In the screenshot of the output on the right you can see the impact of turning the wheels by hand backwards B and forwards F. The word None means that between turning forward and backwards there was no direction flag set. You can also see in the first four bytes the speed of both wheels.