Questions about the hippocampus uuv SITL module

Hi,

I am trying to use the hippocampus uuv module for some simulations. Currently my problem is that I can only send attitude setpoints to the uuv but can’t make it move further. I wonder the reason why the thruster input didn’t give it the force to move forward or upward. I got some idea of computing the required attitude setpoints via ROS to allow position control(similar to mc_pos_control I guess). However, I’m still confused that if I can’t make it move by sending one attitude setpoint, how can I achieve the position control through a series of attitude points. I mean that the force for the thruster should work to make it move. But now as I have tried many times, the uuv only changes its attitude even if the thruster is given a value.

Cheers!

hi,
just to double check:

  • you have the hippocampus + uuv_att_control app running in gazebo
  • system running in offboard + armed?
  • to which ros topic are you sending the attitude setpoint?

Cheers
Daniel

Hi Daneil,

Yes I have hippocampus + uuv_att_control app running, but I used the headless mode, which will not show the GUI of the gazebo. Because I used the Ubuntu to run the simulation, it would be deadly slow once the gazebo GUI was started.

I just tried the following script and log the whole process. I checked it’s trajectory in the online PX4 log reviewer and found everytime the uuv just returned home, and couldn’t go further(like go straight with the set attitude) even if I prolong the mission time.

from future import division

PKG = ‘px4’

import rospy
from geometry_msgs.msg import Quaternion, Vector3
from geometry_msgs.msg import PoseStamped
from mavros_msgs.msg import AttitudeTarget
from mavros_test_common import MavrosTestCommon
from pymavlink import mavutil
from six.moves import xrange
from std_msgs.msg import Header
from threading import Thread
from tf.transformations import quaternion_from_euler

class MavrosOffboardAttctlTest(MavrosTestCommon):
“”"
Tests flying in offboard control by sending attitude and thrust setpoints
via MAVROS.

For the test to be successful it needs to cross a certain boundary in time.
"""

def setUp(self):
    super(MavrosOffboardAttctlTest, self).setUp()

    self.att = AttitudeTarget()
self.local_pos_ini = PoseStamped()
    self.att_setpoint_pub = rospy.Publisher(
        'mavros/setpoint_raw/attitude', AttitudeTarget, queue_size=1)
self.local_pos_pub = rospy.Publisher('mavros/local_position/init', PoseStamped, queue_size=1)

    # send setpoints in seperate thread to better prevent failsafe
    self.att_thread = Thread(target=self.send_att, args=())
    self.att_thread.daemon = True
    self.att_thread.start()

def tearDown(self):
    super(MavrosOffboardAttctlTest, self).tearDown()

#
# Helper methods
#

def send_att(self):
    rate = rospy.Rate(10)  # Hz
    self.att.body_rate = Vector3()
    self.att.header = Header()
    self.att.header.frame_id = "base_footprint"
    self.att.orientation = Quaternion(*quaternion_from_euler(0, -0.1,
                                                             0))
    self.att.thrust = 0.6
    self.att.type_mask = 7  # ignore body rate

    while not rospy.is_shutdown():
        self.att.header.stamp = rospy.Time.now()
        self.att_setpoint_pub.publish(self.att)
        try:  # prevent garbage in console output when thread is killed
            rate.sleep()
        except rospy.ROSInterruptException:
            pass

#
# Test method
#
def test_attctl(self):
self.send_loc_init()
    """Test offboard attitude control"""
    # boundary to cross
    boundary_x = 5
    boundary_y = -5
    boundary_z = -10

    # make sure the simulation is ready to start the mission
    self.wait_for_topics(60)
    self.wait_for_landed_state(mavutil.mavlink.MAV_LANDED_STATE_ON_GROUND,
                               10, -1)

    self.log_topic_vars()
    self.set_mode("OFFBOARD", 5)
    self.set_arm(True, 5)

    rospy.loginfo("run mission")
    rospy.loginfo("attempting to cross boundary | x: {0}, y: {1}, z: {2}".
                  format(boundary_x, boundary_y, boundary_z))
    # does it cross expected boundaries in 'timeout' seconds?
    timeout = 300  # (int) seconds
    loop_freq = 2  # Hz
    rate = rospy.Rate(loop_freq)
    crossed = False
    for i in xrange(timeout * loop_freq):
        if (self.local_position.pose.position.x > boundary_x and
                self.local_position.pose.position.y > boundary_y and
                self.local_position.pose.position.z > boundary_z):
            rospy.loginfo("boundary crossed | seconds: {0} of {1}".format(
                i / loop_freq, timeout))
            crossed = True
            break

        try:
            rate.sleep()
        except rospy.ROSException as e:
            self.fail(e)

    self.assertTrue(crossed, (
        "took too long to cross boundaries | current position x: {0:.2f}, y: {1:.2f}, z: {2:.2f} | timeout(seconds): {3}".
        format(self.local_position.pose.position.x,
               self.local_position.pose.position.y,
               self.local_position.pose.position.z, timeout)))

    self.set_mode("AUTO.LAND", 5)
    self.wait_for_landed_state(mavutil.mavlink.MAV_LANDED_STATE_ON_GROUND,
                               90, 0)
    self.set_arm(False, 5)

if name == ‘main’:
import rostest
rospy.init_node(‘test_node’, anonymous=True)

rostest.rosrun(PKG, 'mavros_offboard_attctl_test',
               MavrosOffboardAttctlTest)

What just came to my mind, did you select the right input mode parameter in QGC?

// Input Modes

/**

  • Select Input Mode
  • @value 0 use Attitude Setpoints
  • @value 1 Direct Feedthrough
  • @group UUV Attitude Control
    */

PARAM_DEFINE_INT32(UUV_INPUT_MODE, 0);

I didn’t really pay attention to that parameter. I’ll give it try on Monday and keep you updated.

Many thanks for your help!

Hi Daniel,

I’ve checked the UUV_INPUT_MODE parameter and it was set to 0 in default, so i guess it was not that problem. I have changed the testing script to use the “mavros/setpoint_attitude/thrust” topic and send a series of attitude topic to control the yaw from -3.14 to 3.14 rad. However, the result was the same like before-- the uuv can circle in its original place but the truster just can’t make the uuv move forward. I have also tried to send merely a series of thruster value, but the uuv just stayed at its original place. I’m confused about the function of the thruster and I wonder if there is any way to make it move forward or move toward a direction?

#!/usr/bin/env python2
from future import division

PKG = ‘px4’

import rospy
import numpy as np
from mavros_msgs.srv import CommandBool
from mavros_msgs.srv import SetMode
from geometry_msgs.msg import Quaternion, Vector3
from mavros_msgs.msg import AttitudeTarget
from mavros_msgs.msg import Thrust
from std_msgs.msg import Header
from tf.transformations import quaternion_from_euler

class Attitude_test:
“”"
Tests flying in offboard control by sending attitude and thrust setpoints
via MAVROS.

For the test to be successful it needs to cross a certain boundary in time.
"""

def __init__(self):
    self.att = AttitudeTarget()
    self.att_setpoint_pub = rospy.Publisher(
        'mavros/setpoint_raw/attitude', AttitudeTarget, queue_size=100)
    self.thrust = Thrust()
    self.thrust_pub = rospy.Publisher('mavros/setpoint_attitude/thrust', Thrust, queue_size=100)


def send_att(self, attitude):
    self.rate = rospy.Rate(10)  # Hz
    self.att.body_rate = Vector3()
    self.att.header = Header()
    self.att.header.frame_id = "base_footprint"
    self.att.orientation = Quaternion(*quaternion_from_euler(attitude[0], attitude[1],
                                                             attitude[2]))
    self.att.thrust = 0.8
    self.att.type_mask = 7  # ignore body rate

    self.att.header.stamp = rospy.Time.now()
   	self.att_setpoint_pub.publish(self.att)
    
    self.rate.sleep()
    print("sending attitude setpoint")

def send_thrust(self, thrust):
    self.thrust.header.stamp = rospy.Time.now()
    self.thrust.thrust = 0.8
    self.thrust_pub.publish(self.thrust)
    self.rate.sleep()
    print("sending thrust")

def arm(self):
    rospy.wait_for_service('mavros/cmd/arming')
    try:
        armService = rospy.ServiceProxy('mavros/cmd/arming', CommandBool)
        armService(True)
    except rospy.ServiceException as e:
        print("Service arming call failed: %s"%e)


def set_mode(self):
    rospy.wait_for_service('mavros/set_mode')
    try:
        flightModeService = rospy.ServiceProxy('mavros/set_mode', SetMode)
        flightModeService(custom_mode='OFFBOARD')
    except rospy.ServiceException as e:
        print('service set_mode call failed: %s. Offboard Mode could not be set.'%e)
        
def setDisarm(self):
    rospy.wait_for_service('mavros/cmd/arming')
    try:
        armService = rospy.ServiceProxy('mavros/cmd/arming', CommandBool)
        armService(False)
    except rospy.ServiceException as e:
        print("Service disarming call failed: %s"%e)

def setAutoLandMode(self):
    rospy.wait_for_service('mavros/set_mode')
    try:
        flightModeService = rospy.ServiceProxy('mavros/set_mode', SetMode)
        flightModeService(custom_mode='AUTO.LAND')
    except rospy.ServiceException as e:
        print('service set_mode call failed: %s. Autoland Mode could not be set.'%e)
    
def run(self):
    """Test offboard attitude control"""

    # make sure the simulation is ready to start the mission

    self.arm()
    
    # sending a sequence of setpoints to active the offboard mode
   	yaw = np.linspace(-3.14, 3.14, 10)
    for i in range(10):
        attitude = (0, 0, yaw[i])
        thrust = 0.8
        self.send_att(attitude)
        
    # set the offboard mode
    self.set_mode()

    # set a series of yaw setpoints and thrust value
    yaw = np.linspace(-3.14, 3.14, 100)
    for i in range(100):
        attitude = (0, 0, yaw[i])
        self.send_att(attitude)
        self.send_thrust(thrust)

    
    self.setAutoLandMode()
    self.setDisarm()

if name == ‘main’:
rospy.init_node(‘test_node’, anonymous=True)
attitude_test = Attitude_test()
attitude_test.run()

Cheers!

Hi Daniel,

Sorry that I have made a mistake by saying that the uuv can’t move yesterday. It actually can move if I also send the pitch setpoint(I’m curious about this as well, cause in hippocampus paper, it was said the thruster control output was in the direction of xB, which should be surge. But if I don’t set pitch setpoint, the thruster doesn’t function). However, it seems to only move to a similar direction every time even I set a completely opposite yaw direction.

Another point is that it can only move no more than one metre. I have compared the results of the gazebo iris model and uuv model using the same mavros script. The first script sends a list of setpoints with pitch -0.2 and yaw from 1.3 to 1.4 rad, 200 points in total and the second sends list of setpoints with pitch -0.2 and yaw from 4 to 4,1 rad, 600 points in total. The trajectory of iris and uuv and iris are shown below. On the second trial, the iris travels on the opposite direction and moves further than the first one. However, the uuv travels in the same direction in both trial and the traveling distance are both limited. Do you have any idea of this problem? Thanks

I think I have found the reason of the weird behavior that I mentioned before. It was because of this line of code: thrust_u = _param_direct_thrust.get(); in the uuv_att_control module. I haven’t noticed before that the thrust was set by the parameter and the default value in the parameter file sets thrust to 0. That’s why uuv can’t move. I have changed it to the value published by the attitude setpoint topic, which works fine now.