Canada
Asked — Edited

4-In-1 Sensor Questions

I am attempting to get a 4-in-1 sensor to work as I need it to and not have much success - I need a hand. I am trying to get the 4- in-1 sensor to drive 2 servos to keep something level/plumb. I have the servos set to go up or down depending on the sensor readings. The problems I'm having are;

  1. It will kind of work for a short time but will only drive one servo at a time even if both should move,
  2. The Y axis stops working after a few minutes,
  3. Then everything stops working,
  4. For some reason the 'Sleep' command above the 'loop' is run each time and anything else put there -except the first line. I am running the sensor on a EZBv4/2. My code is a modified version of one from a JD project. Here's my code;

ControlCommand("MPU9150", Init)

sleep(1000)

:loop
#Added these because $AccelX and $AccelY were not recognized later in the script for some reason.
$XAccel = $AccelX
$YAccel = $AccelY

if ("x" =0)

print(1)  

sleep(2000)
  
goto(loop)
  
endif 
  
ControlCommand("MPU9150", RunOnce)

print("x: " + $XAccel)
print("y: " + $YAccel)

if ($XAccel > 1000)
ServoUp(D1,10)
Servospeed(D1,2)
 
ELSEif ($XAccel  < -1000)
ServoDown(D3,10)
Servospeed(D3,2)
Endif

if ($YAccel > 1000)
ServoUp(D3,10)
Servospeed(D3,2) 
  
ELSEif ($YAccel < -1000)
ServoDown(D3,10)
Servospeed(D3,2) 
Sleep(500)

endif  
sleep(1500)

goto(loop)

Has anyone played with these sensors much and got them working? I know I have a lot to learn about them so your assistance will be appreciated.
Thanks


ARC Pro

Upgrade to ARC Pro

ARC Pro is your gateway to a community of like-minded robot enthusiasts and professionals, all united by a passion for advanced robot programming.

#1  

Sounds as though maybe your servo’s position is not being updated, or too much load on the servo?

Are you using digital or analogue servos?

I know the ezb will work with both, but digital would be much better, hope you find the problem soon. : )

#2  

Hi @bhouston,

My guess is the way you state your servo speeds? From the Script help section:


Once the ServoSpeed() has been initialized the first time, specify the ServoSpeed() before specifying the Servo() position.

Your stating your servo speeds "after" you set your position.

PRO
USA
#3  

@bhouston,

What you have in mind ?
Are you trying to detect motion or track the orientation ?

Your code reads the IMU every 1.5 seconds. A lot of things can happen in 1500 milliseconds.

#4  

@Newagetomy, I'm using EZ Robot HD servos @Dave, I'll clean that up, thanks. @ptp, I am trying to detect motion. The robot starts out level, If the robot is leaned to the left or the right or to the front or back, that will be detected. Then the servos will move the axis effected back to level. I realize that 1500 milliseconds is a long time- I'm just trying to get it to work, then I'll shorten the time.

#5  

I've been working on this again today. If I run this code, it works great;


Servospeed(D1,2)
 
ControlCommand("MPU9150", Init)

sleep(500)

:loop
#Added these because $AccelX and $AccelY were not recognized later in the script for some reason.
$XAccel = $AccelX


if ("x" =0)

print(1)  

sleep(2000)
  
goto(loop)
  
endif 
  
ControlCommand("MPU9150", RunOnce)

print("x: " + $XAccel)
#print("y: " + $YAccel)

if ($XAccel > 1000)
ServoUp(D1,15)
 
ELSEif ($XAccel < -1000)
ServoDown(D1,15)
 
endif

sleep(100)
Goto(loop)

But I need 2 servos to run in the code. If I run this code;


Servospeed(D1,2)
Servospeed(D3,2) 
ControlCommand("MPU9150", Init)

sleep(500)

:loop
#Added these because $AccelX and $AccelY were not recognized later in the script for some reason.
$XAccel = $AccelX
$YAccel = $AccelY

if ("x" =0)

print(1)  

sleep(2000)
  
goto(loop)
  
endif 
  
ControlCommand("MPU9150", RunOnce)

print("x: " + $XAccel)
print("y: " + $YAccel)

if ($XAccel > 1000)
ServoUp(D1,15)

 
ELSEif ($XAccel < -1000)
ServoDown(D1,15)

 
endif
if ($YAccel > 1000)
ServoUp(D3,15)

 
ELSEif ($YAccel < -1000)
ServoDown(D3,15)

 
endif


sleep(100)
Goto(loop)

It does not move either of the 2 servos and the code runs lines of code outside of the 'loop'. This is what that looks like;


2: Servospeed(D3,2)
3: ControlCommand("MPU9150", Init)
5: sleep(500)
7: :loop
9: $XAccel = $AccelX
10: $YAccel = $AccelY
12: if ("x" =0)
20: endif
22: ControlCommand("MPU9150", RunOnce)
24: print("x: " + $XAccel)
> x: -4876
25: print("y: " + $YAccel)
> y: 1543
27: if ($XAccel > 1000)
31: ELSEif ($XAccel < -1000)
32: ServoDown(D1,15)
35: endif
36: if ($YAccel > 1000)
37: ServoUp(D3,15)
40: ELSEif ($YAccel < -1000)
47: sleep(100)
48: Goto(loop)

I still looking for some help before I give up on these sensors. Thanks

PRO
USA
#7  

Bob,

Try the code below and let us know the output:


ServoSpeed(D1,2)
ServoSpeed(D3,2)
ControlCommand("MPU9150", Init)
Sleep(500)

$movex_counter = 0
$movey_counter = 0
$debug_counter = 0

:loop
        $AccelX=0
        $AccelY=0
	ControlCommand("MPU9150", RunOnce)

	if ($AccelX>1000)
		ServoUp(D1,15)
		$movex_counter=$movex_counter+1
		Print("AccelX: " + $AccelX)
		Print("D1: " + GetServo(D1))
	elseif ($AccelX<-1000)
		ServoDown(D1,15)
		$movex_counter=$movex_counter+1
		Print("AccelX: " + $AccelX)
		Print("D1: " + GetServo(D1))
	endif

	if ($AccelY>1000)
		ServoUp(D3,15)
		$movey_counter=$movey_counter+1
		Print("AccelY: " + $AccelY)
		Print("D3: " + GetServo(D3))
	elseif ($AccelY<-1000)
		ServoDown(D3,15)
		$movey_counter=$movey_counter+1
		Print("AccelY: " + $AccelY)
		Print("D3: " + GetServo(D3))
	endif

	$debug_counter=$debug_counter+1

	#print debug msg every 2 seconds
	if ($debug_counter>=20)
		$debug_counter=0
		Print("movex_counter: " + $movex_counter)
		Print("movey_counter: " + $movey_counter)
	endif
	
	Sleep(100)
GoTo(loop)

#8  

@DJ, I'll try that. @ptp, Here's a snipet of what I get;


1: ServoSpeed(D1,2)
2: ServoSpeed(D3,2)
3: ControlCommand("MPU9150", Init)
4: Sleep(500)
6: $movex_counter = 0
7: $movey_counter = 0
8: $debug_counter = 0
10: :loop
11: $AccelX=0
12: $AccelY=0
13: ControlCommand("MPU9150", RunOnce)
15: if ($AccelX>500)
20: elseif ($AccelX<-500)
21: ServoDown(D1,15)
22: $movex_counter=$movex_counter+1
23: Print("AccelX: " + $AccelX)
> AccelX: -7170
24: Print("D1: " + GetServo(D1))
> D1: -225
25: endif
27: if ($AccelY>500)
28: ServoUp(D3,15)
29: $movey_counter=$movey_counter+1
30: Print("AccelY: " + $AccelY)
> AccelY: 1573
31: Print("D3: " + GetServo(D3))
> D3: 150
32: elseif ($AccelY<-500)
39: $debug_counter=$debug_counter+1
42: if ($debug_counter>=20)
46: endif
48: Sleep(100)
49: GoTo(loop)
10: :loop
11: $AccelX=0
12: $AccelY=0
13: ControlCommand("MPU9150", RunOnce)
15: if ($AccelX>500)
20: elseif ($AccelX<-500)
21: ServoDown(D1,15)
22: $movex_counter=$movex_counter+1
23: Print("AccelX: " + $AccelX)
> AccelX: -7131
24: Print("D1: " + GetServo(D1))
> D1: -240
25: endif
27: if ($AccelY>500)
28: ServoUp(D3,15)
29: $movey_counter=$movey_counter+1
30: Print("AccelY: " + $AccelY)
> AccelY: 1587
31: Print("D3: " + GetServo(D3))
> D3: 165
32: elseif ($AccelY<-500)
39: $debug_counter=$debug_counter+1
42: if ($debug_counter>=20)
46: endif
48: Sleep(100)
49: GoTo(loop)
10: :loop
11: $AccelX=0
12: $AccelY=0
13: ControlCommand("MPU9150", RunOnce)
15: if ($AccelX>500)
20: elseif ($AccelX<-500)
21: ServoDown(D1,15)
22: $movex_counter=$movex_counter+1
23: Print("AccelX: " + $AccelX)
> AccelX: -7208
24: Print("D1: " + GetServo(D1))
> D1: -255
25: endif
27: if ($AccelY>500)
28: ServoUp(D3,15)
29: $movey_counter=$movey_counter+1
30: Print("AccelY: " + $AccelY)
> AccelY: 1541
31: Print("D3: " + GetServo(D3))
> D3: 180
32: elseif ($AccelY<-500)
39: $debug_counter=$debug_counter+1
42: if ($debug_counter>=20)
46: endif
48: Sleep(100)
49: GoTo(loop)
10: :loop
11: $AccelX=0
12: $AccelY=0
13: ControlCommand("MPU9150", RunOnce)
15: if ($AccelX>500)
20: elseif ($AccelX<-500)
21: ServoDown(D1,15)
22: $movex_counter=$movex_counter+1
23: Print("AccelX: " + $AccelX)
> AccelX: -7162
24: Print("D1: " + GetServo(D1))
> D1: -270
25: endif
27: if ($AccelY>500)
28: ServoUp(D3,15)
29: $movey_counter=$movey_counter+1
30: Print("AccelY: " + $AccelY)
> AccelY: 1575
31: Print("D3: " + GetServo(D3))
> D3: 195
32: elseif ($AccelY<-500)
39: $debug_counter=$debug_counter+1
42: if ($debug_counter>=20)
46: endif
48: Sleep(100)
49: GoTo(loop)
10: :loop
11: $AccelX=0
12: $AccelY=0
13: ControlCommand("MPU9150", RunOnce)
15: if ($AccelX>500)
20: elseif ($AccelX<-500)
21: ServoDown(D1,15)
22: $movex_counter=$movex_counter+1
23: Print("AccelX: " + $AccelX)
> AccelX: -7142
24: Print("D1: " + GetServo(D1))
> D1: -285
25: endif
27: if ($AccelY>500)
28: ServoUp(D3,15)
29: $movey_counter=$movey_counter+1
30: Print("AccelY: " + $AccelY)
> AccelY: 1567
31: Print("D3: " + GetServo(D3))
> D3: 210
32: elseif ($AccelY<-500)
39: $debug_counter=$debug_counter+1
42: if ($debug_counter>=20)
46: endif
48: Sleep(100)
49: GoTo(loop)
10: :loop
11: $AccelX=0
12: $AccelY=0
13: ControlCommand("MPU9150", RunOnce)
15: if ($AccelX>500)
20: elseif ($AccelX<-500)
21: ServoDown(D1,15)
22: $movex_counter=$movex_counter+1
23: Print("AccelX: " + $AccelX)
> AccelX: -7136
24: Print("D1: " + GetServo(D1))
> D1: -300
25: endif
27: if ($AccelY>500)
28: ServoUp(D3,15)
29: $movey_counter=$movey_counter+1
30: Print("AccelY: " + $AccelY)
> AccelY: 1581
31: Print("D3: " + GetServo(D3))
> D3: 225
32: elseif ($AccelY<-500)
39: $debug_counter=$debug_counter+1
42: if ($debug_counter>=20)
46: endif
48: Sleep(100)
49: GoTo(loop)
10: :loop
11: $AccelX=0
12: $AccelY=0
13: ControlCommand("MPU9150", RunOnce)
15: if ($AccelX>500)
20: elseif ($AccelX<-500)
21: ServoDown(D1,15)
22: $movex_counter=$movex_counter+1
23: Print("AccelX: " + $AccelX)
> AccelX: -7135
24: Print("D1: " + GetServo(D1))
> D1: -315
25: endif
27: if ($AccelY>500)
28: ServoUp(D3,15)
29: $movey_counter=$movey_counter+1
30: Print("AccelY: " + $AccelY)
> AccelY: 1582
31: Print("D3: " + GetServo(D3))
> D3: 240
32: elseif ($AccelY<-500)
39: $debug_counter=$debug_counter+1
42: if ($debug_counter>=20)
46: endif
48: Sleep(100)
49: GoTo(loop)
10: :loop
11: $AccelX=0
12: $AccelY=0
13: ControlCommand("MPU9150", RunOnce)
15: if ($AccelX>500)
20: elseif ($AccelX<-500)
21: ServoDown(D1,15)
22: $movex_counter=$movex_counter+1
23: Print("AccelX: " + $AccelX)
> AccelX: -7144
24: Print("D1: " + GetServo(D1))
> D1: -330
25: endif
27: if ($AccelY>500)
28: ServoUp(D3,15)
29: $movey_counter=$movey_counter+1
30: Print("AccelY: " + $AccelY)
> AccelY: 1577
31: Print("D3: " + GetServo(D3))
> D3: 255
32: elseif ($AccelY<-500)
39: $debug_counter=$debug_counter+1
42: if ($debug_counter>=20)
46: endif
48: Sleep(100)
49: GoTo(loop)
10: :loop
11: $AccelX=0
12: $AccelY=0
13: ControlCommand("MPU9150", RunOnce)
15: if ($AccelX>500)
20: elseif ($AccelX<-500)
21: ServoDown(D1,15)
22: $movex_counter=$movex_counter+1
23: Print("AccelX: " + $AccelX)
> AccelX: -7154
24: Print("D1: " + GetServo(D1))
> D1: -345
25: endif
27: if ($AccelY>500)
28: ServoUp(D3,15)
29: $movey_counter=$movey_counter+1
30: Print("AccelY: " + $AccelY)
> AccelY: 1575
31: Print("D3: " + GetServo(D3))
> D3: 270
32: elseif ($AccelY<-500)
39: $debug_counter=$debug_counter+1
42: if ($debug_counter>=20)
46: endif
48: Sleep(100)
49: GoTo(loop)
10: :loop
11: $AccelX=0
12: $AccelY=0
13: ControlCommand("MPU9150", RunOnce)
15: if ($AccelX>500)
20: elseif ($AccelX<-500)
21: ServoDown(D1,15)
22: $movex_counter=$movex_counter+1
23: Print("AccelX: " + $AccelX)
> AccelX: -7149
24: Print("D1: " + GetServo(D1))
> D1: -360
25: endif
27: if ($AccelY>500)
28: ServoUp(D3,15)
29: $movey_counter=$movey_counter+1
30: Print("AccelY: " + $AccelY)
> AccelY: 1560
31: Print("D3: " + GetServo(D3))
> D3: 285
32: elseif ($AccelY<-500)
39: $debug_counter=$debug_counter+1
42: if ($debug_counter>=20)
46: endif
48: Sleep(100)
49: GoTo(loop)
10: :loop
11: $AccelX=0
12: $AccelY=0
13: ControlCommand("MPU9150", RunOnce)
15: if ($AccelX>500)
20: elseif ($AccelX<-500)
21: ServoDown(D1,15)
22: $movex_counter=$movex_counter+1
23: Print("AccelX: " + $AccelX)
> AccelX: -7168
24: Print("D1: " + GetServo(D1))
> D1: -375
25: endif
27: if ($AccelY>500)
28: ServoUp(D3,15)
29: $movey_counter=$movey_counter+1
30: Print("AccelY: " + $AccelY)
> AccelY: 1565
31: Print("D3: " + GetServo(D3))
> D3: 300
32: elseif ($AccelY<-500)
39: $debug_counter=$debug_counter+1
42: if ($debug_counter>=20)
46: endif
48: Sleep(100)
49: GoTo(loop)
10: :loop
11: $AccelX=0
12: $AccelY=0
13: ControlCommand("MPU9150", RunOnce)
15: if ($AccelX>500)
20: elseif ($AccelX<-500)
21: ServoDown(D1,15)
22: $movex_counter=$movex_counter+1
23: Print("AccelX: " + $AccelX)
> AccelX: -7134
24: Print("D1: " + GetServo(D1))
> D1: -390
25: endif
27: if ($AccelY>500)
28: ServoUp(D3,15)
29: $movey_counter=$movey_counter+1
30: Print("AccelY: " + $AccelY)
> AccelY: 1564
31: Print("D3: " + GetServo(D3))
> D3: 315
32: elseif ($AccelY<-500)
39: $debug_counter=$debug_counter+1
42: if ($debug_counter>=20)
46: endif
48: Sleep(100)
49: GoTo(loop)

I worked for a short time then quit working

PRO
USA
#9  

@bhouston:

Did you noticed the servo positions:


> D1: -225
> D1: -240
> D1: -255
> D1: -270
> D1: -285
> D1: -300
> D1: -315
> D1: -330
> D1: -345
> D1: -360
> D1: -375
> D1: -390
> D3: 150
> D3: 165
> D3: 180
> D3: 195
> D3: 210
> D3: 225
> D3: 240
> D3: 255
> D3: 270
> D3: 285
> D3: 300
> D3: 315

EZ-B Digital Port servo valid positions are 1-180. Q: The $1,000,000 question what should ARC do with -390 or a 256 value ? A: Nothing, Ignore => Stop working

You are using ServoUp, ServoDown functions to increment/decrement the position, when you get outside of 1-180 range, ARC ignores the value.

I believe you want track the absolute orientation not the relative orientation.

#10  

Thanks ptp, I noticed those numbers - didn't know what to make of them. Any advise on how to proceed? I want the sensor to move the servos so the sensor is back to level.

PRO
USA
#11  

Can you describe your setup, the IMU location and the relation with the servos.

some examples:

Control the servos manipulating the IMU similar to a mocap or kinect ? Detect motion (manual pushing or pulling the servos) ? Fall or equilibrium control ?

#12  

I will have the sensor centered on the top of the robot. The robot will start out in a level position, held by the two servos. These servos are then controlled by the 4-in-1 sensor. If the robot is put out of level, say by something going on below these servos, then the sensor would adjust the top of the robot back to a level position using the two servos. I hope that explains it OK.

PRO
USA
#13  

I'm familiar with the IMU9150, it's a cheap device easily sourced from Ebay china vendors, sometimes not the original chip but a clone with some glitches...

Also does not fit in the JD slot, so I order a 4-in-1 sensor to do a demo, it will take a few days to arrive, I'll come back later.

I don't believe you can get good results without a micro-processor processing the IMU data, before being sent to EZB.

most accelerometers are very sensitive, gyrometers drift, compass have noise, you can't rely on a single sensor, you need to query them multiple times per second, combine the sensors and apply a fusion algorithm to obtain "stable" values, this kind operations i.e. 100 times per second or more, can't be done on the PC (EZ-Builder).

So the solution needs an extra addon.

#14  

Thanks again ptp, It's interesting that it will run on servo OK but when the second one is added, the sensor can't handle it. I look forward to seeing what you come up with.

PRO
USA
#15  

@bhouston,

I don't think is related to more than one servo, i believe you can still use the sensor as it is...

The problem is the absolute vs relative values, maybe with some code tweaking you can keep track of the position.

#16  

I agree with @PTP... Put a conditional check on servo positions before ServoUp or ServoDown commands. This way it will only allow the servo to move as long as it doesn't try to move the servo out of it's 1 to 180 range...


if(GetServo(D1) > 15)
ServoDown(D1,15) # may have to be ServoUp depending on your servo's orientation
endif

#and/or

if(GetServo(D1) < 166)
ServoUp(D1,15) # may have to be ServoDown depending on your servo's orientation
endif

#17  

Hi Bob, Great work!

There may be a need to have external pots monitoring joint positions to provide proof positive feedback of "where the robot is now" So then you are checking the pot values along with the MPU values and deciding what action to take from there.

I agree with the comments about values out of range. "getServo() returns the last postion ARC told the servo to go to.... doesn't mean the servo got there..."

I see that in your calls to ServoUp and ServoDown you are asking the servo to move 15* at each step. In just six iterations you will have moved 90*. Perhaps the reaction should just be a couple of degrees, which is quite a lot for keeping balance.

Thanks for plowin' the field! S~

PRO
USA
#18  

4-in-1 demo

bear in mind i don't have DJ's communication skills.

#19  

Great demo, ptp. Can you monitor the X and Y axis at the same time and have the robot respond accordingly ?

PRO
USA
#20  

Bob,

Yes all the axis if you want.

Check the project:

JD_9150Serial.EZB

the problem is not monitoring 1,2,3 axis, the problem is the execution speed several factors:

  1. Connection WIFI (EZB4 v1) vs WIFI (EZB4 v2) vs USB (EZB4 v2)
  2. Ez-script code execution
  3. Other scripts

I don't believe you can handle a Balanced robot or avoid a fall (Humanoid) or other fast reactions with ARC/EZ-Script only.

I'm guessing some details (i can be wrong), remember Inverted Pendulum EZ-BIT product: https://www.ez-robot.com/Shop/AccessoriesDetails.aspx?productNumber=1360

the EZ-Bit consists of a micro-controller and MPU-9150 (4-in-1 Sensor) and has 2 servo ports to control the continuous servo wheels.

Calculating the angle (tilt/pitch), running the actions (back,forward) everything is executed in EZ-BIT micro-controller, a solution like that you don't have speed issues.

PRO
USA
#21  

For the demo i used an Arduino Mini Pro 3.3v and 4-in-1 sensor. The 4-in-1 sensor is connected to the Arduino I2C Bus, and arduino serial port is connected to the EZB serial port 0.

Than i have two versions to handle the serial communication:

  1. Pool_IMU Script

:loop
#write command 
UARTWrite(0, 0, "get_dmp_euler", 10)
#read response
UARTReadAvailable(0, 0)
sleep(100)
Goto(loop)

  1. Push_IMU Script

#write command to initiate push data 200 ms interval
UARTWrite(0, 0, "set_push 200", 10)
:loop
#read response
UARTReadAvailable(0, 0)
Goto(loop)

The second script is more efficient a single call to EZB to read the serial port vs two calls.

There is space for more improvement

Handling variable data (Text) and parsing text with EZ-Script is not efficient compared to use I2C bus:


:loop
# 2 bytes per angle x 3 = 6
$data=I2CRead (0, 0, Addr, 6)
sleep(100)
goto(loop)

To support the above solution you need a different micro-controller, one with 2 x I2c bus. Arduino mini is out of the picture, we need an arm cortex micro-controller.

The 4-in-1 sensor is connected to the ARM cortex i2c bus 0 (master), and the second i2c bus 1 (slave) is connected to EZB.

Another interesting detail, with a small adaption the 4-in-1 sensor supports a secondary I2C address, so is possible to use the same micro-controller to handle 2 x 4-in-1 sensors.

The cost is not relevant: cortex micro-controller is $20 vs Arduino mini $10 and you have more processing power plus the possibility to connect via I2C to EZB.

if you want more details or help with a micro-controller to handle the 4-in-1 sensor drop me an email.

PRO
Synthiam
#22  

Man, you never cease to amaze me PTP